win32: fix `copy-file' handling of file-exists error

The specific error reported by CopyFileW doesn't seem
to be documented. It's unclear whether Racket's old test
for ERROR_EXISTS_ALREADY was the wrong choice (as opposed
to ERROR_FILE_EXISTS) or whether some Windows versions
use it; we test for both for now.

Also, improve error reporting when an errno or
GetLastError() value is available.

Closes PR 12074

Merge to 5.1.2
This commit is contained in:
Matthew Flatt 2011-07-23 19:52:42 -06:00
parent 42f41d868a
commit c9d4e0fb8c
2 changed files with 38 additions and 11 deletions

View File

@ -202,12 +202,14 @@ Scheme_Config *scheme_init_error_escape_proc(Scheme_Config *config)
%- = skip int %- = skip int
%L = line number as intptr_t, -1 means no line %L = line number as intptr_t, -1 means no line
%e = error number for strerror() %e = error number for strerror()/FormatMessage()
%E = error number for platform-specific error string %E = error number for platform-specific error string
%Z = potential platform-specific error number; additional char* %Z = potential platform-specific error number; additional char*
is either NULL or a specific error message is either NULL or a specific error message
%N = boolean then error number like %E (if boolean is 0) %N = boolean then error number like %E (if boolean is 0)
or error number for scheme_hostname_error() or error number for scheme_hostname_error()
%m = boolean then error number like %e, which
is used only if the boolean is 1
*/ */
static intptr_t sch_vsprintf(char *s, intptr_t maxlen, const char *msg, va_list args, char **_s) static intptr_t sch_vsprintf(char *s, intptr_t maxlen, const char *msg, va_list args, char **_s)
@ -259,6 +261,7 @@ static intptr_t sch_vsprintf(char *s, intptr_t maxlen, const char *msg, va_list
ints[ip++] = mzVA_ARG(args, int); ints[ip++] = mzVA_ARG(args, int);
break; break;
case 'N': case 'N':
case 'm':
ints[ip++] = mzVA_ARG(args, int); ints[ip++] = mzVA_ARG(args, int);
ints[ip++] = mzVA_ARG(args, int); ints[ip++] = mzVA_ARG(args, int);
break; break;
@ -389,14 +392,19 @@ static intptr_t sch_vsprintf(char *s, intptr_t maxlen, const char *msg, va_list
} }
break; break;
case 'e': case 'e':
case 'm':
case 'E': case 'E':
case 'Z': case 'Z':
case 'N': case 'N':
{ {
int en, he; int en, he, none = 0;
char *es; char *es;
if (type == 'N') { if (type == 'm') {
none = !ints[ip++];
type = 'e';
he = 0;
} else if (type == 'N') {
he = ints[ip++]; he = ints[ip++];
type = 'E'; type = 'E';
} else } else
@ -412,7 +420,7 @@ static intptr_t sch_vsprintf(char *s, intptr_t maxlen, const char *msg, va_list
if (he) if (he)
es = (char *)scheme_hostname_error(en); es = (char *)scheme_hostname_error(en);
if (en || es) { if ((en || es) && !none) {
#ifdef NO_STRERROR_AVAILABLE #ifdef NO_STRERROR_AVAILABLE
if (!es) if (!es)
es = "Unknown error"; es = "Unknown error";
@ -443,8 +451,13 @@ static intptr_t sch_vsprintf(char *s, intptr_t maxlen, const char *msg, va_list
sprintf((char *)t, "%s; errno=%d", es, en); sprintf((char *)t, "%s; errno=%d", es, en);
tlen = strlen(t); tlen = strlen(t);
} else { } else {
t = "errno=?"; if (none) {
tlen = 7; t = "";
tlen = 0;
} else {
t = "errno=?";
tlen = 7;
}
} }
} }

View File

@ -3835,7 +3835,7 @@ failed:
static Scheme_Object *copy_file(int argc, Scheme_Object **argv) static Scheme_Object *copy_file(int argc, Scheme_Object **argv)
{ {
char *src, *dest, *reason = NULL; char *src, *dest, *reason = NULL;
int pre_exists = 0; int pre_exists = 0, has_err_val = 0, err_val = 0;
Scheme_Object *bss, *bsd; Scheme_Object *bss, *bsd;
if (!SCHEME_PATH_STRINGP(argv[0])) if (!SCHEME_PATH_STRINGP(argv[0]))
@ -3886,12 +3886,16 @@ static Scheme_Object *copy_file(int argc, Scheme_Object **argv)
s = fopen(src, "rb"); s = fopen(src, "rb");
if (!s) { if (!s) {
err_val = errno;
has_err_val = 1;
reason = "cannot open source file"; reason = "cannot open source file";
goto failed; goto failed;
} }
d = fopen(dest, "wb"); d = fopen(dest, "wb");
if (!d) { if (!d) {
err_val = errno;
has_err_val = 1;
fclose(s); fclose(s);
reason = "cannot open destination file"; reason = "cannot open destination file";
goto failed; goto failed;
@ -3917,6 +3921,8 @@ static Scheme_Object *copy_file(int argc, Scheme_Object **argv)
else if (errno != EINTR) else if (errno != EINTR)
break; break;
} }
err_val = errno;
has_err_val = 0;
reason = "cannot set destination's mode"; reason = "cannot set destination's mode";
} else } else
reason = "read or write failed"; reason = "read or write failed";
@ -3928,15 +3934,23 @@ static Scheme_Object *copy_file(int argc, Scheme_Object **argv)
return scheme_void; return scheme_void;
reason = "copy failed"; reason = "copy failed";
if (GetLastError() == ERROR_ALREADY_EXISTS) err_val = GetLastError();
if ((err_val == ERROR_FILE_EXISTS)
|| (err_val == ERROR_ALREADY_EXISTS))
pre_exists = 1; pre_exists = 1;
has_err_val = 1;
#endif #endif
scheme_raise_exn(pre_exists ? MZEXN_FAIL_FILESYSTEM_EXISTS : MZEXN_FAIL_FILESYSTEM, scheme_raise_exn(pre_exists ? MZEXN_FAIL_FILESYSTEM_EXISTS : MZEXN_FAIL_FILESYSTEM,
"copy-file: %s; cannot copy: %q to: %q", "copy-file: %s; cannot copy: %q to: %q%s%m%s",
reason, reason,
filename_for_error(argv[0]), filename_for_error(argv[0]),
filename_for_error(argv[1])); filename_for_error(argv[1]),
has_err_val ? " (" : "",
has_err_val,
err_val,
has_err_val ? ")" : "");
return NULL; return NULL;
} }