[racket-dev] call-with-atomic-output-file

From: Nick Sivo (nicksivo at gmail.com)
Date: Sat May 31 17:24:57 EDT 2014

Hello,

I'm using call-with-atomic-output-file, and noticed a discrepancy in
the documentation and observed behavior.
http://docs.racket-lang.org/reference/Filesystem.html suggests that it

"Opens a temporary file for writing in the same directory as file ...
and then atomically moves the temporary file in place of proc."

In my testing, this appears to be true when the file has a path
component ("a/b", "./out"), but isn't always true when the file is in
the current working directory ("out"):

(require racket/file)

(define (display-tempfile-path port tempfile)
  (displayln tempfile))

(define (test-call-with-atomic-output-file)
  (displayln (~a "Current Directory: " (current-directory)))
  (call-with-atomic-output-file "/Users/nsivo/temp/somefile"
                                display-tempfile-path)
  (call-with-atomic-output-file "./somefile"
                                display-tempfile-path)
  (call-with-atomic-output-file "somefile"
                                display-tempfile-path))

Welcome to DrRacket, version 6.0.1 [3m].
Language: racket [custom].
> (test-call-with-atomic-output-file)
Current Directory: /Users/nsivo/temp/
/Users/nsivo/temp/tmp14015696951401569695422
./tmp14015696951401569695423
/var/folders/0h/yf13qqgx02b_y1ymndcnvn980000gn/T/tmp14015696951401569695423

I would expect the last tempfile to be in the /Users/nsivo/temp/
directory, not /var/folders/... While this doesn't matter on my local
machine, in production the temp directory is its own filesystem:

Welcome to Racket v6.0.
> (require racket/file)
> (define (display-tempfile-path port tempfile)
  (displayln tempfile))
> (current-directory)
#<path:/home/nsivo/>
> (call-with-atomic-output-file "somefile"
                                display-tempfile-path)
/var/tmp/tmp14015698421401569842614
rename-file-or-directory: cannot rename file or directory
  source path: /var/tmp/tmp14015698421401569842614
  dest path: /home/nsivo/somefile
  system error: Cross-device link; errno=18

I believe that changing

(make-temporary-file "tmp~a" #f (path-only path))

to

(make-temporary-file "tmp~a" #f (or (path-only path) "./"))

will fix the problem, and is essentially how I've worked around the
issue for now.

Is the current behavior wrong? Is a pull request the best way for me
to submit a patch?

Cheers,
Nick

Posted on the dev mailing list.