~ chicken-core (chicken-5) 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