Skip to content

Commit

Permalink
Bug 931720 - Return low-level error correctly from nsLocalFile::CopyT…
Browse files Browse the repository at this point in the history
…oNative(). 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.)
  • Loading branch information
zephyrus00jp committed Nov 1, 2013
1 parent bc8e890 commit 651ef27
Showing 1 changed file with 37 additions and 3 deletions.
40 changes: 37 additions & 3 deletions xpcom/io/nsLocalFileUnix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down

0 comments on commit 651ef27

Please sign in to comment.