~ chicken-core (master) ee2bab380aa424c045536bdfc6afb26e172aa504
commit ee2bab380aa424c045536bdfc6afb26e172aa504
Author: Peter Bex <peter.bex@xs4all.nl>
AuthorDate: Sun Aug 3 14:52:32 2014 +0200
Commit: Peter Bex <peter.bex@xs4all.nl>
CommitDate: Sat Aug 16 12:37:31 2014 +0200
Fix file-mkstemp behaviour on Windows (#819).
Before, it would return "random" invalid file descriptors.
Thanks to Michele La Monaca for the initial patch.
Signed-off-by: Evan Hanson <evhan@foldling.org>
diff --git a/NEWS b/NEWS
index 71341e85..7a627523 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,8 @@
- Unit "posix":
- set-file-position! now allows negative positions for seek/cur (thanks
to Seth Alves).
+ - file-mkstemp now works correctly on Windows, it now returns valid
+ file descriptors (#819, thanks to Michele La Monaca).
- Runtime system:
- Removed several deprecated, undocumented parts of the C interface:
diff --git a/posixwin.scm b/posixwin.scm
index c41e18db..0af657d6 100644
--- a/posixwin.scm
+++ b/posixwin.scm
@@ -198,7 +198,6 @@ readdir(DIR * dir)
#endif /* ifndef __WATCOMC__ */
#ifdef __WATCOMC__
-# define mktemp _mktemp
/* there is no P_DETACH in Watcom CRTL */
# define P_DETACH P_NOWAIT
#endif
@@ -256,7 +255,6 @@ C_free_arg_string(char **where) {
#define C_open(fn, fl, m) C_fix(open(C_c_string(fn), C_unfix(fl), C_unfix(m)))
#define C_read(fd, b, n) C_fix(read(C_unfix(fd), C_data_pointer(b), C_unfix(n)))
#define C_write(fd, b, n) C_fix(write(C_unfix(fd), C_data_pointer(b), C_unfix(n)))
-#define C_mkstemp(t) C_fix(mktemp(C_c_string(t)))
#define C_flushall() C_fix(_flushall())
@@ -778,14 +776,37 @@ EOF
(define file-mkstemp
(lambda (template)
(##sys#check-string template 'file-mkstemp)
- (let* ([buf (##sys#make-c-string template 'file-mkstemp)]
- [fd (##core#inline "C_mkstemp" buf)]
- [path-length (string-length buf)])
- (when (eq? -1 fd)
- (##sys#update-errno)
- (##sys#signal-hook #:file-error 'file-mkstemp "cannot create temporary file" template) )
- (values fd (##sys#substring buf 0 (fx- path-length 1) ) ) ) ) )
-
+ (let* ((diz "0123456789abcdefghijklmnopqrstuvwxyz")
+ (diz-len (string-length diz))
+ (max-attempts (* diz-len diz-len diz-len))
+ (tmpl (string-copy template)) ; We'll overwrite this later
+ (tmpl-len (string-length tmpl))
+ (first-x (let loop ((i (fx- tmpl-len 1)))
+ (if (and (fx>= i 0)
+ (eq? (string-ref tmpl i) #\X))
+ (loop (fx- i 1))
+ (fx+ i 1)))))
+ (cond ((not (directory-exists? (or (pathname-directory template) ".")))
+ ;; Quit early instead of looping needlessly with C_open
+ ;; failing every time. This is a race condition, but not
+ ;; a security-critical one.
+ (##sys#signal-hook #:file-error 'file-mkstemp "non-existent directory" template))
+ ((fx= first-x tmpl-len)
+ (##sys#signal-hook #:file-error 'file-mkstemp "invalid template" template)))
+ (let loop ((count 1))
+ (let suffix-loop ((index (fx- tmpl-len 1)))
+ (when (fx>= index first-x)
+ (string-set! tmpl index (string-ref diz (random diz-len)))
+ (suffix-loop (fx- index 1))))
+ (let ((fd (##core#inline "C_open"
+ (##sys#make-c-string tmpl 'file-open)
+ (bitwise-ior open/rdwr open/creat open/excl)
+ (fxior _s_irusr _s_iwusr))))
+ (if (eq? -1 fd)
+ (if (fx< count max-attempts)
+ (loop (fx+ count 1))
+ (posix-error #:file-error 'file-mkstemp "cannot create temporary file" template))
+ (values fd tmpl)))))))
;;; Directory stuff:
Trap