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
(cherry picked from commit c9d4e0fb8c)
This commit is contained in:
Matthew Flatt 2011-07-23 19:52:42 -06:00 committed by Eli Barzilay
parent fd6e9c28d3
commit 7895045a1c
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
%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
%Z = potential platform-specific error number; additional char*
is either NULL or a specific error message
%N = boolean then error number like %E (if boolean is 0)
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)
@ -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);
break;
case 'N':
case 'm':
ints[ip++] = mzVA_ARG(args, int);
ints[ip++] = mzVA_ARG(args, int);
break;
@ -389,14 +392,19 @@ static intptr_t sch_vsprintf(char *s, intptr_t maxlen, const char *msg, va_list
}
break;
case 'e':
case 'm':
case 'E':
case 'Z':
case 'N':
{
int en, he;
int en, he, none = 0;
char *es;
if (type == 'N') {
if (type == 'm') {
none = !ints[ip++];
type = 'e';
he = 0;
} else if (type == 'N') {
he = ints[ip++];
type = 'E';
} else
@ -412,7 +420,7 @@ static intptr_t sch_vsprintf(char *s, intptr_t maxlen, const char *msg, va_list
if (he)
es = (char *)scheme_hostname_error(en);
if (en || es) {
if ((en || es) && !none) {
#ifdef NO_STRERROR_AVAILABLE
if (!es)
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);
tlen = strlen(t);
} else {
t = "errno=?";
tlen = 7;
if (none) {
t = "";
tlen = 0;
} else {
t = "errno=?";
tlen = 7;
}
}
}

View File

@ -3834,7 +3834,7 @@ failed:
static Scheme_Object *copy_file(int argc, Scheme_Object **argv)
{
char *src, *dest, *reason = NULL;
int pre_exists = 0;
int pre_exists = 0, has_err_val = 0, err_val = 0;
Scheme_Object *bss, *bsd;
if (!SCHEME_PATH_STRINGP(argv[0]))
@ -3885,12 +3885,16 @@ static Scheme_Object *copy_file(int argc, Scheme_Object **argv)
s = fopen(src, "rb");
if (!s) {
err_val = errno;
has_err_val = 1;
reason = "cannot open source file";
goto failed;
}
d = fopen(dest, "wb");
if (!d) {
err_val = errno;
has_err_val = 1;
fclose(s);
reason = "cannot open destination file";
goto failed;
@ -3916,6 +3920,8 @@ static Scheme_Object *copy_file(int argc, Scheme_Object **argv)
else if (errno != EINTR)
break;
}
err_val = errno;
has_err_val = 0;
reason = "cannot set destination's mode";
} else
reason = "read or write failed";
@ -3927,15 +3933,23 @@ static Scheme_Object *copy_file(int argc, Scheme_Object **argv)
return scheme_void;
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;
has_err_val = 1;
#endif
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,
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;
}