Bug 931720 - Return low-level error correctly from nsLocalFile::CopyToNative(). r=bsmedberg

Fix copytonative to return better meaningful error (from errno) when PR_Write()/PR_Read() failed (e.g., failed to write to full file system, etc.)
This commit is contained in:
ISHIKAWA, Chiaki
2013-10-31 23:04:11 -04:00
parent dfc10c9376
commit ff2d9b8e2f

View File

@@ -817,6 +817,18 @@ nsLocalFile::CopyToNative(nsIFile *newParent, const nsACString &newName)
char buf[BUFSIZ];
int32_t bytesRead;
// record PR_Write() error for better error message later.
nsresult saved_write_error = NS_OK;
nsresult saved_read_error = NS_OK;
// DONE: Does PR_Read() return bytesRead < 0 for error?
// Yes., The errors from PR_Read are not so common and
// the value may not have correspondence in NS_ERROR_*, but
// we do catch it still, immediately after while() loop.
// We can differentiate errors pf PR_Read and PR_Write by
// looking at saved_write_error value. If PR_Write error occurs (and not
// PR_Read() error), save_write_error is not NS_OK.
while ((bytesRead = PR_Read(oldFD, buf, BUFSIZ)) > 0) {
#ifdef DEBUG_blizzard
totalRead += bytesRead;
@@ -825,6 +837,7 @@ nsLocalFile::CopyToNative(nsIFile *newParent, const nsACString &newName)
// PR_Write promises never to do a short write
int32_t bytesWritten = PR_Write(newFD, buf, bytesRead);
if (bytesWritten < 0) {
saved_write_error = NSRESULT_FOR_ERRNO();
bytesRead = -1;
break;
}
@@ -835,18 +848,39 @@ nsLocalFile::CopyToNative(nsIFile *newParent, const nsACString &newName)
#endif
}
// Record error if PR_Read() failed.
// Must be done before any other I/O which may reset errno.
if ( (bytesRead < 0) && (saved_write_error == NS_OK)) {
saved_read_error = NSRESULT_FOR_ERRNO();
}
#ifdef DEBUG_blizzard
printf("read %d bytes, wrote %d bytes\n",
totalRead, totalWritten);
#endif
// TODO/FIXME: better find out how to propagate errors of
// close. Errors of close can occur. Read man page of
// close(2); At least, we should tell the user that
// filesystem/disk is hosed so that users can take remedial
// action.
// close the files
PR_Close(newFD);
PR_Close(oldFD);
// check for read (or write) error after cleaning up
if (bytesRead < 0)
return NS_ERROR_OUT_OF_MEMORY;
// Let us report the failure to write and read.
// check for write/read error after cleaning up
if (bytesRead < 0) {
if (saved_write_error != NS_OK)
return saved_write_error;
else if (saved_read_error != NS_OK)
return saved_read_error;
#if DEBUG
else // sanity check. Die and debug.
MOZ_ASSERT(0);
#endif
}
}
return rv;
}