diff --git a/racket/src/racket/src/file.c b/racket/src/racket/src/file.c index 53cc9e46ba..7191393017 100644 --- a/racket/src/racket/src/file.c +++ b/racket/src/racket/src/file.c @@ -3343,7 +3343,7 @@ static char *filename_for_error(Scheme_Object *p) 0); } -static int can_enable_write_permission() +int scheme_can_enable_write_permission(void) { #ifdef DOS_FILE_SYSTEM if (SCHEME_TRUEP(scheme_get_param(scheme_current_config(), MZCONFIG_FORCE_DELETE_PERMS))) @@ -3364,7 +3364,7 @@ static Scheme_Object *delete_file(int argc, Scheme_Object **argv) NULL, SCHEME_GUARD_FILE_DELETE); - if (!rktio_delete_file(scheme_rktio, fn, can_enable_write_permission())) { + if (!rktio_delete_file(scheme_rktio, fn, scheme_can_enable_write_permission())) { scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, "delete-file: cannot delete file\n" " path: %q\n" @@ -4683,7 +4683,7 @@ static Scheme_Object *delete_directory(int argc, Scheme_Object *argv[]) #endif if (!rktio_delete_directory(scheme_rktio, filename, current_directory, - can_enable_write_permission())) { + scheme_can_enable_write_permission())) { scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, "delete-directory: cannot delete directory\n" " path: %q\n" diff --git a/racket/src/racket/src/port.c b/racket/src/racket/src/port.c index bedf634ffc..5a5f4bcf84 100644 --- a/racket/src/racket/src/port.c +++ b/racket/src/racket/src/port.c @@ -3595,7 +3595,7 @@ scheme_do_open_output_file(char *name, int offset, int argc, Scheme_Object *argv int internal) { int e_set = 0, m_set = 0, i; - int existsok = 0; + int open_flags = 0, try_replace = 0; char *filename; char mode[4]; int typepos; @@ -3616,22 +3616,23 @@ scheme_do_open_output_file(char *name, int offset, int argc, Scheme_Object *argv if (SAME_OBJ(argv[i], append_symbol)) { mode[0] = 'a'; - existsok = RKTIO_OPEN_APPEND; + open_flags = RKTIO_OPEN_APPEND; e_set++; } else if (SAME_OBJ(argv[i], replace_symbol)) { - existsok = RKTIO_OPEN_REPLACE; + try_replace = 1; e_set++; } else if (SAME_OBJ(argv[i], truncate_symbol)) { - existsok = RKTIO_OPEN_TRUNCATE | RKTIO_OPEN_CAN_EXIST; + open_flags = RKTIO_OPEN_TRUNCATE | RKTIO_OPEN_CAN_EXIST; e_set++; } else if (SAME_OBJ(argv[i], must_truncate_symbol)) { - existsok = RKTIO_OPEN_MUST_EXIST | RKTIO_OPEN_TRUNCATE; + open_flags = RKTIO_OPEN_MUST_EXIST | RKTIO_OPEN_TRUNCATE; e_set++; } else if (SAME_OBJ(argv[i], truncate_replace_symbol)) { - existsok = RKTIO_OPEN_TRUNCATE | RKTIO_OPEN_REPLACE | RKTIO_OPEN_CAN_EXIST; + open_flags = RKTIO_OPEN_TRUNCATE | RKTIO_OPEN_CAN_EXIST; + try_replace = 1; e_set++; } else if (SAME_OBJ(argv[i], update_symbol)) { - existsok = RKTIO_OPEN_MUST_EXIST; + open_flags = RKTIO_OPEN_MUST_EXIST; if (typepos == 1) { mode[2] = mode[1]; typepos = 2; @@ -3640,7 +3641,7 @@ scheme_do_open_output_file(char *name, int offset, int argc, Scheme_Object *argv mode[1] = '+'; e_set++; } else if (SAME_OBJ(argv[i], can_update_symbol)) { - existsok = RKTIO_OPEN_CAN_EXIST; + open_flags = RKTIO_OPEN_CAN_EXIST; if (typepos == 1) { mode[2] = mode[1]; typepos = 2; @@ -3686,7 +3687,7 @@ scheme_do_open_output_file(char *name, int offset, int argc, Scheme_Object *argv (internal ? 0 : (SCHEME_GUARD_FILE_WRITE - | ((existsok & RKTIO_OPEN_REPLACE) + | (try_replace ? SCHEME_GUARD_FILE_DELETE : 0) /* append mode: */ @@ -3694,19 +3695,38 @@ scheme_do_open_output_file(char *name, int offset, int argc, Scheme_Object *argv ? SCHEME_GUARD_FILE_READ : 0) /* update mode: */ - | ((existsok & (RKTIO_OPEN_CAN_EXIST | RKTIO_OPEN_MUST_EXIST) - && !(existsok & (RKTIO_OPEN_REPLACE - | RKTIO_OPEN_TRUNCATE - | RKTIO_OPEN_APPEND))) + | ((open_flags & (RKTIO_OPEN_CAN_EXIST | RKTIO_OPEN_MUST_EXIST) + && !(open_flags & (RKTIO_OPEN_TRUNCATE + | RKTIO_OPEN_APPEND)) + && !try_replace) ? SCHEME_GUARD_FILE_READ : 0)))); scheme_custodian_check_available(NULL, name, "file-stream"); - fd = rktio_open(scheme_rktio, filename, (RKTIO_OPEN_WRITE - | existsok - | (and_read ? RKTIO_OPEN_READ : 0) - | ((mode[1] == 't') ? RKTIO_OPEN_TEXT : 0))); + while (1) { + fd = rktio_open(scheme_rktio, filename, (RKTIO_OPEN_WRITE + | open_flags + | (and_read ? RKTIO_OPEN_READ : 0) + | ((mode[1] == 't') ? RKTIO_OPEN_TEXT : 0))); + + if (!fd + && try_replace + && (scheme_last_error_is_racket(RKTIO_ERROR_EXISTS) + || (scheme_last_error_is_racket(RKTIO_ERROR_ACCESS_DENIED) + && rktio_file_exists(scheme_rktio, filename)))) { + /* In replace mode, delete file and try again */ + if (!rktio_delete_file(scheme_rktio, filename, scheme_can_enable_write_permission())) { + scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, + "%s: error deleting file\n" + " path: %q\n" + " system error: %R", + name, filename); + } + try_replace = 0; + } else + break; + } if (!fd) { if (scheme_last_error_is_racket(RKTIO_ERROR_EXISTS)) { @@ -3718,19 +3738,12 @@ scheme_do_open_output_file(char *name, int offset, int argc, Scheme_Object *argv "%s: path is a directory\n" " path: %q", name, filename); - } else { -#if 0 - /* Add a way to get this information from rktio_open()? */ - if (....) - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - "%s: error deleting file\n" + } else + scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, + "%s: cannot open output file\n" " path: %q\n" " system error: %R", - name, filename); - -#endif - filename_exn(name, "cannot open output file", filename, 0); - } + name, filename); } return make_fd_output_port(fd, scheme_make_path(filename), and_read, -1, NULL); diff --git a/racket/src/racket/src/schpriv.h b/racket/src/racket/src/schpriv.h index e6989a98e3..0eee605d70 100644 --- a/racket/src/racket/src/schpriv.h +++ b/racket/src/racket/src/schpriv.h @@ -4549,6 +4549,8 @@ Scheme_Object *scheme_current_library_collection_paths(int argc, Scheme_Object * Scheme_Object *scheme_current_library_collection_links(int argc, Scheme_Object *argv[]); Scheme_Object *scheme_compiled_file_roots(int argc, Scheme_Object *argv[]); +int scheme_can_enable_write_permission(void); + #ifdef MZ_USE_JIT int scheme_can_inline_fp_op(); int scheme_can_inline_fp_comp(); diff --git a/racket/src/rktio/demo.c b/racket/src/rktio/demo.c index b6238686e9..3308dca838 100644 --- a/racket/src/rktio/demo.c +++ b/racket/src/rktio/demo.c @@ -704,7 +704,7 @@ int main(int argc, char **argv) rktio_fd_t **pipe_fds; if (stress && verbose) - printf(" iter %d\n", i); + printf(" iter %d\n", (int)i); pipe_fds = rktio_make_pipe(rktio, 0); check_valid(pipe_fds); @@ -756,7 +756,7 @@ int main(int argc, char **argv) rktio_listener_t *lnr; if (stress && verbose) - printf(" iter %d\n", i); + printf(" iter %d\n", (int)i); check_many_lookup(rktio); diff --git a/racket/src/rktio/rktio.h b/racket/src/rktio/rktio.h index 7e5274e397..92edde1266 100644 --- a/racket/src/rktio/rktio.h +++ b/racket/src/rktio/rktio.h @@ -112,24 +112,23 @@ typedef struct rktio_fd_t rktio_fd_t; /* Used for `rktio_open` with `RKTIO_OPEN_WRITE`: */ #define RKTIO_OPEN_TRUNCATE (1<<3) #define RKTIO_OPEN_APPEND (1<<4) -#define RKTIO_OPEN_REPLACE (1<<5) -#define RKTIO_OPEN_MUST_EXIST (1<<6) -#define RKTIO_OPEN_CAN_EXIST (1<<7) +#define RKTIO_OPEN_MUST_EXIST (1<<5) +#define RKTIO_OPEN_CAN_EXIST (1<<6) /* Used for `rktio_system_fd`: */ -#define RKTIO_OPEN_SOCKET (1<<8) -#define RKTIO_OPEN_UDP (1<<9) -#define RKTIO_OPEN_REGFILE (1<<10) -#define RKTIO_OPEN_NOT_REGFILE (1<<11) +#define RKTIO_OPEN_SOCKET (1<<7) +#define RKTIO_OPEN_UDP (1<<8) +#define RKTIO_OPEN_REGFILE (1<<9) +#define RKTIO_OPEN_NOT_REGFILE (1<<10) /* If neither RKTIO_OPEN_REGILE nor RKTIO_OPEN_NOT_REGILE are specified, then the value is inferred by `rtkio_system_fd`. */ -#define RKTIO_OPEN_DIR (1<<12) -#define RKTIO_OPEN_NOT_DIR (1<<13) +#define RKTIO_OPEN_DIR (1<<11) +#define RKTIO_OPEN_NOT_DIR (1<<12) /* Inferred when neither is specified and when `RKTIO_OPEN_[NOT_]REGFILE` is also inferred. */ -#define RKTIO_OPEN_INIT (1<<14) +#define RKTIO_OPEN_INIT (1<<13) /* Make `rtkio_system_fd` set a socket as nonblocking, etc. */ -#define RKTIO_OPEN_OWN (1<<15) +#define RKTIO_OPEN_OWN (1<<14) /* Make `rtkio_system_fd` record a socket for reliable clean up on pre-NT Windows. */ RKTIO_EXTERN rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes); @@ -152,8 +151,11 @@ RKTIO_EXTERN int rktio_fd_modes(rktio_t *rktio, rktio_fd_t *rfd); /* Returns all of the recorded mode flags. */ RKTIO_EXTERN rktio_fd_t *rktio_open(rktio_t *rktio, const char *src, int modes); -/* Can report `RKTIO_ERROR_DOES_NOT_EXIST` in place of system error, - and can report `RKTIO_ERROR_UNSUPPORTED_TEXT_MODE` on Windows. */ +/* Can report `RKTIO_ERROR_DOES_NOT_EXIST` in place of a system error + in read mode, and can report `RKTIO_ERROR_IS_A_DIRECTORY`, + `RKTIO_ERROR_EXISTS`, or `RKTIO_ERROR_ACCESS_DENIED` in place of a + system error in write mode. On Windows, can report + `RKTIO_ERROR_UNSUPPORTED_TEXT_MODE`. */ RKTIO_EXTERN rktio_ok_t rktio_close(rktio_t *rktio, rktio_fd_t *fd); /* Can report `RKTIO_ERROR_EXISTS` in place of system error, @@ -823,6 +825,7 @@ enum { RKTIO_ERROR_UNSUPPORTED = 1, RKTIO_ERROR_DOES_NOT_EXIST, RKTIO_ERROR_EXISTS, + RKTIO_ERROR_ACCESS_DENIED, RKTIO_ERROR_LINK_FAILED, RKTIO_ERROR_NOT_A_LINK, RKTIO_ERROR_BAD_PERMISSION, diff --git a/racket/src/rktio/rktio_error.c b/racket/src/rktio/rktio_error.c index 0d7181d221..605f7b6b68 100644 --- a/racket/src/rktio/rktio_error.c +++ b/racket/src/rktio/rktio_error.c @@ -91,6 +91,22 @@ void rktio_remap_last_error(rktio_t *rktio) #endif #ifdef RKTIO_SYSTEM_WINDOWS rktio_set_last_error(rktio, RKTIO_ERROR_KIND_WINDOWS, ERROR_FILE_NOT_FOUND); +#endif + break; + case RKTIO_ERROR_EXISTS: +#ifdef RKTIO_SYSTEM_UNIX + rktio_set_last_error(rktio, RKTIO_ERROR_KIND_POSIX, EEXIST); +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + rktio_set_last_error(rktio, RKTIO_ERROR_KIND_WINDOWS, RKTIO_ERROR_EXISTS); +#endif + break; + case RKTIO_ERROR_ACCESS_DENIED: +#ifdef RKTIO_SYSTEM_UNIX + rktio_set_last_error(rktio, RKTIO_ERROR_KIND_POSIX, EACCES); +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + rktio_set_last_error(rktio, RKTIO_ERROR_KIND_WINDOWS, ERROR_ACCESS_DENIED); #endif break; } diff --git a/racket/src/rktio/rktio_file.c b/racket/src/rktio/rktio_file.c index 734e6e8c54..cd928d65ed 100644 --- a/racket/src/rktio/rktio_file.c +++ b/racket/src/rktio/rktio_file.c @@ -131,23 +131,11 @@ static rktio_fd_t *open_write(rktio_t *rktio, const char *filename, int modes) set_racket_error(RKTIO_ERROR_IS_A_DIRECTORY); return NULL; } else if (errno == EEXIST) { - if (!(modes & RKTIO_OPEN_REPLACE)) { - set_racket_error(RKTIO_ERROR_EXISTS); - return NULL; - } else { - do { - cr = unlink(filename); - } while ((cr == -1) && (errno == EINTR)); - - if (cr) { - get_posix_error(); - return NULL; - } - - do { - fd = open(filename, flags | RKTIO_BINARY, 0666); - } while ((fd == -1) && (errno == EINTR)); - } + set_racket_error(RKTIO_ERROR_EXISTS); + return NULL; + } else if (errno == EACCES) { + set_racket_error(RKTIO_ERROR_ACCESS_DENIED); + return NULL; } if (fd == -1) { @@ -197,32 +185,14 @@ static rktio_fd_t *open_write(rktio_t *rktio, const char *filename, int modes) NULL); if (fd == INVALID_HANDLE_VALUE) { - int errv; - errv = GetLastError(); - if ((errv == ERROR_ACCESS_DENIED) && (modes & RKTIO_OPEN_REPLACE)) { - /* Delete and try again... */ - if (DeleteFileW(WIDE_PATH_temp(filename))) { - fd = CreateFileW(WIDE_PATH_temp(filename), - GENERIC_WRITE | ((modes & RKTIO_OPEN_READ) ? GENERIC_READ : 0), - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - hmode, - 0, - NULL); - if (fd == INVALID_HANDLE_VALUE) { - get_windows_error(); - return NULL; - } - } else { - get_windows_error(); - return NULL; - } + int errv = GetLastError(); + if (errv == ERROR_ACCESS_DENIED) { + set_racket_error(RKTIO_ERROR_ACCESS_DENIED); + return NULL; } else if (errv == ERROR_FILE_EXISTS) { set_racket_error(RKTIO_ERROR_EXISTS); return NULL; - } - - if (fd == INVALID_HANDLE_VALUE) { + } else { get_windows_error(); return NULL; }