Open Bug 1844663 Opened 1 years ago Updated 1 years ago

atomicFileOutputStream deletes its output file on close

Categories

(Core :: Networking, defect, P2)

defect

Tracking

()

People

(Reporter: bytesized, Unassigned)

References

Details

(Whiteboard: [necko-triaged])

Steps to Reproduce:

  1. Open the browser console and run:
let l = {}; 
XPCOMUtils.defineLazyGetter(l, "BinaryOutputStream", () => {
  return Components.Constructor(
    "@mozilla.org/binaryoutputstream;1",
    "nsIBinaryOutputStream",
    "setOutputStream"
  );
});
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.initWithPath("C:\\Users\\<user>\\test.txt");
let stream = FileUtils.openAtomicFileOutputStream(file);
let bstream = new l.BinaryOutputStream(stream);
let encoded = new TextEncoder().encode("testing 123\n");
bstream.writeByteArray(encoded);
  1. Observe that test.txt exists and contains the right contents
  2. Run stream.close();
  3. Observe that test.txt no longer exists.

I took a peek at the implementation of nsAtomicFileOutputStream and noticed that the handling is a bit different if the file already exists. So I tried the above steps again after creating an existing test.txt. This time I see that test-1.txt is created with the expected output, but it is also deleted when the stream is closed and test.txt does not contain the new contents afterwards.

I spent a little time in a debugger investigating, and the file is being deleted here. It seems like it probably works properly if nsAtomicFileOutputStream::Finish() is called first, but neither my example code nor the production code that I'm trying to fix (Bug 1830368) ever seem to hit that function.

Severity: -- → S3
Priority: -- → P2
Whiteboard: [necko-triaged]

It seems like it works properly if instead of stream.close() you run

stream.QueryInterface(Ci.nsISafeOutputStream);
stream.finish();

After rereading this comment, it kinda seems like the implementation expects that the caller will call finish() if to indicate that the file writing is complete and close() to indicate that we actually don't want that file anymore and just want to delete it? I guess that technically there is nothing wrong with this, but it's pretty different from normal file usage conventions. That certainly isn't how fclose works, for example. So if that is how it's meant to work, some explaining comments might be good. Especially here.

You need to log in before you can comment on or make changes to this bug.