add more information to copy-file error message

The `file/cache` relies on matching the text of a message, and the
text had changed to have less information on Unix, including whether
the problem was with the source or destination file. Add a notion of
error step to rktio and use it to improve the `copy-file` message.
This commit is contained in:
Matthew Flatt 2017-06-21 16:30:44 -06:00
parent 7152cc1ba6
commit cfa1d7c54c
5 changed files with 80 additions and 9 deletions

View File

@ -3477,11 +3477,37 @@ static Scheme_Object *copy_file(int argc, Scheme_Object **argv)
filename_for_error(argv[0]), filename_for_error(argv[0]),
filename_for_error(argv[1])); filename_for_error(argv[1]));
} else { } else {
const char *how;
switch (rktio_get_last_error_step(scheme_rktio)) {
case RKTIO_COPY_STEP_OPEN_SRC:
how = "cannot open source file";
break;
case RKTIO_COPY_STEP_OPEN_DEST:
how = "cannot open destination file";
break;
case RKTIO_COPY_STEP_READ_SRC_DATA:
how = "error reading source file";
break;
case RKTIO_COPY_STEP_WRITE_DEST_DATA:
how = "error writing destination file";
break;
case RKTIO_COPY_STEP_READ_SRC_METADATA:
how = "error reading source-file metadata";
break;
case RKTIO_COPY_STEP_WRITE_DEST_METADATA:
how = "error writing destination-file metadata";
break;
default:
how = "copy failed";
}
scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
"copy-file: copy failed\n" "copy-file: %s\n"
" source path: %q\n" " source path: %q\n"
" destination path: %q\n" " destination path: %q\n"
" system error: %R", " system error: %R",
how,
filename_for_error(argv[0]), filename_for_error(argv[0]),
filename_for_error(argv[1])); filename_for_error(argv[1]));
} }

View File

@ -779,24 +779,38 @@ RKTIO_EXTERN rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, const char
rktio_bool_t exists_ok); rktio_bool_t exists_ok);
/* Starts a file copy. Depending on the OS, this step may perform the /* Starts a file copy. Depending on the OS, this step may perform the
whole copy, or it may just get started. Can report whole copy, or it may just get started. Can report
`RKTIO_ERROR_EXISTS`. */ `RKTIO_ERROR_EXISTS`, and sets an error step as listed further below. */
RKTIO_EXTERN rktio_bool_t rktio_copy_file_is_done(rktio_t *rktio, rktio_file_copy_t *fc); RKTIO_EXTERN rktio_bool_t rktio_copy_file_is_done(rktio_t *rktio, rktio_file_copy_t *fc);
RKTIO_EXTERN rktio_ok_t rktio_copy_file_step(rktio_t *rktio, rktio_file_copy_t *fc); RKTIO_EXTERN rktio_ok_t rktio_copy_file_step(rktio_t *rktio, rktio_file_copy_t *fc);
/* As long as the copy isn't done, call `rktio_copy_file_step` to make /* As long as the copy isn't done, call `rktio_copy_file_step` to make
a little progress. Use `rktio_copy_file_finish_permissions` (optionally) a little progress. Use `rktio_copy_file_finish_permissions`
and then `rktio_copy_file_stop` when done. */ (optionally) and then `rktio_copy_file_stop` when done. An error
sets an error step as listed further below. */
RKTIO_EXTERN rktio_ok_t rktio_copy_file_finish_permissions(rktio_t *rktio, rktio_file_copy_t *fc); RKTIO_EXTERN rktio_ok_t rktio_copy_file_finish_permissions(rktio_t *rktio, rktio_file_copy_t *fc);
/* Depending on the OS, copies permissions from the source to the /* Depending on the OS, copies permissions from the source to the
destination. This step can be performed at any time between the destination. This step can be performed at any time between the
start and stop. Reports success if this step isn't needed (e.g., start and stop. Reports success if this step isn't needed (e.g.,
where a copy fully completes when it is started). */ where a copy fully completes when it is started). On error, the
step is set to `RKTIO_COPY_STEP_WRITE_DEST_METADATA`. */
RKTIO_EXTERN void rktio_copy_file_stop(rktio_t *rktio, rktio_file_copy_t *fc); RKTIO_EXTERN void rktio_copy_file_stop(rktio_t *rktio, rktio_file_copy_t *fc);
/* Deallocates the copy process, interrupting it if the copy is not /* Deallocates the copy process, interrupting it if the copy is not
complete. */ complete. */
/* Step values for errors from `rktio_copy_file_start` and
`rktio_copy_file_step`: */
enum {
RKTIO_COPY_STEP_UNKNOWN,
RKTIO_COPY_STEP_OPEN_SRC,
RKTIO_COPY_STEP_OPEN_DEST,
RKTIO_COPY_STEP_READ_SRC_DATA,
RKTIO_COPY_STEP_WRITE_DEST_DATA,
RKTIO_COPY_STEP_READ_SRC_METADATA,
RKTIO_COPY_STEP_WRITE_DEST_METADATA
};
/*************************************************/ /*************************************************/
/* System paths */ /* System paths */
@ -1059,7 +1073,12 @@ enum {
RKTIO_ERROR_CONVERT_OTHER, RKTIO_ERROR_CONVERT_OTHER,
}; };
RKTIO_EXTERN int rktio_get_last_error_step(rktio_t *rktio);
/* Some operations report further information about the step that
failed. The meaning of a step number is operation-specific. */
RKTIO_EXTERN void rktio_set_last_error(rktio_t *rktio, int kind, int errid); RKTIO_EXTERN void rktio_set_last_error(rktio_t *rktio, int kind, int errid);
RKTIO_EXTERN void rktio_set_last_error_step(rktio_t *rktio, int step);
/* In case you need to save and restore error information. */ /* In case you need to save and restore error information. */
RKTIO_EXTERN void rktio_remap_last_error(rktio_t *rktio); RKTIO_EXTERN void rktio_remap_last_error(rktio_t *rktio);

View File

@ -78,12 +78,22 @@ int rktio_get_last_error_kind(rktio_t *rktio)
return rktio->errkind; return rktio->errkind;
} }
int rktio_get_last_error_step(rktio_t *rktio)
{
return rktio->errstep;
}
void rktio_set_last_error(rktio_t *rktio, int kind, int errid) void rktio_set_last_error(rktio_t *rktio, int kind, int errid)
{ {
rktio->errkind = kind; rktio->errkind = kind;
rktio->errid = errid; rktio->errid = errid;
} }
void rktio_set_last_error_step(rktio_t *rktio, int new_errstep)
{
rktio->errstep = new_errstep;
}
void rktio_remap_last_error(rktio_t *rktio) void rktio_remap_last_error(rktio_t *rktio)
{ {
if (rktio->errkind == RKTIO_ERROR_KIND_RACKET) { if (rktio->errkind == RKTIO_ERROR_KIND_RACKET) {

View File

@ -1589,8 +1589,10 @@ rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, const char *dest, const
rktio_fd_t *src_fd, *dest_fd; rktio_fd_t *src_fd, *dest_fd;
src_fd = rktio_open(rktio, src, RKTIO_OPEN_READ); src_fd = rktio_open(rktio, src, RKTIO_OPEN_READ);
if (!src_fd) if (!src_fd) {
rktio_set_last_error_step(rktio, RKTIO_COPY_STEP_OPEN_SRC);
return NULL; return NULL;
}
do { do {
ok = fstat(rktio_fd_system_fd(rktio, src_fd), &buf); ok = fstat(rktio_fd_system_fd(rktio, src_fd), &buf);
@ -1601,6 +1603,7 @@ rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, const char *dest, const
get_posix_error(); get_posix_error();
else else
set_racket_error(RKTIO_ERROR_IS_A_DIRECTORY); set_racket_error(RKTIO_ERROR_IS_A_DIRECTORY);
rktio_set_last_error_step(rktio, RKTIO_COPY_STEP_READ_SRC_METADATA);
rktio_close(rktio, src_fd); rktio_close(rktio, src_fd);
return NULL; return NULL;
} }
@ -1609,6 +1612,7 @@ rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, const char *dest, const
| (exists_ok ? RKTIO_OPEN_TRUNCATE : 0))); | (exists_ok ? RKTIO_OPEN_TRUNCATE : 0)));
if (!dest_fd) { if (!dest_fd) {
rktio_close(rktio, src_fd); rktio_close(rktio, src_fd);
rktio_set_last_error_step(rktio, RKTIO_COPY_STEP_OPEN_DEST);
return NULL; return NULL;
} }
@ -1632,9 +1636,15 @@ rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, const char *dest, const
const wchar_t *dest_w; const wchar_t *dest_w;
src_w = WIDE_PATH_copy(src); src_w = WIDE_PATH_copy(src);
if (!src_w) return NULL; if (!src_w) {
rktio_set_last_error_step(rktio, RKTIO_COPY_STEP_OPEN_SRC);
return NULL;
}
dest_w = WIDE_PATH_temp(dest); dest_w = WIDE_PATH_temp(dest);
if (!dest_w) return NULL; if (!dest_w) {
rktio_set_last_error_step(rktio, RKTIO_COPY_STEP_OPEN_DEST);
return NULL;
}
if (CopyFileW(src_w, dest_w, !exists_ok)) { if (CopyFileW(src_w, dest_w, !exists_ok)) {
rktio_file_copy_t *fc; rktio_file_copy_t *fc;
@ -1651,6 +1661,7 @@ rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, const char *dest, const
set_racket_error(RKTIO_ERROR_EXISTS); set_racket_error(RKTIO_ERROR_EXISTS);
else else
get_windows_error(); get_windows_error();
rktio_set_last_error_step(rktio, RKTIO_COPY_STEP_UNKNOWN);
free(src_w); free(src_w);
@ -1677,14 +1688,17 @@ rktio_ok_t rktio_copy_file_step(rktio_t *rktio, rktio_file_copy_t *fc)
fc->done = 1; fc->done = 1;
return 1; return 1;
} else if (len == RKTIO_READ_ERROR) { } else if (len == RKTIO_READ_ERROR) {
rktio_set_last_error_step(rktio, RKTIO_COPY_STEP_READ_SRC_DATA);
return 0; return 0;
} else { } else {
intptr_t done = 0, amt; intptr_t done = 0, amt;
while (done < len) { while (done < len) {
amt = rktio_write(rktio, fc->dest_fd, buffer + done, len - done); amt = rktio_write(rktio, fc->dest_fd, buffer + done, len - done);
if (amt < 0) if (amt < 0) {
rktio_set_last_error_step(rktio, RKTIO_COPY_STEP_WRITE_DEST_DATA);
return 0; return 0;
}
done += amt; done += amt;
} }
return 1; return 1;
@ -1706,6 +1720,7 @@ rktio_ok_t rktio_copy_file_finish_permissions(rktio_t *rktio, rktio_file_copy_t
if (err) { if (err) {
get_posix_error(); get_posix_error();
rktio_set_last_error_step(rktio, RKTIO_COPY_STEP_WRITE_DEST_METADATA);
return 0; return 0;
} }
#endif #endif

View File

@ -33,6 +33,7 @@
struct rktio_t { struct rktio_t {
int errid; int errid;
int errkind; int errkind;
int errstep;
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
char *last_err_str; char *last_err_str;
#endif #endif