rktio: normalize 'replace and 'truncate/replace behavior
For `open-output-file`: Move 'replace mode handling out of rktio and into the client. Formerly, on Windows, 'replace mode was just 'truncate with a fallback for permission problems, so this change makes it delete an existing file and replace it, which is more consistent with how 'replace has always worked on Unix. In 'truncate/replace mode, if a truncating open fails due to a permission error and the file exists, then try again as a 'replace. That's how it worked on Windows before, and now it's how Unix works.
This commit is contained in:
parent
5d68ec297a
commit
36ca1361d9
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user