views:

254

answers:

8

When an application saves a file, a typical model is to save the file to a temporary location, then move the temporary file to the final location. In some cases that "move" becomes "replace". In pseudo code:

Save temp file;
if final file exists
   delete final file;
move temp file to final filename;

There's a window in there where the delete might succeed, but the move may not, so you can handle that by something like :

Save temp file;
if final file exists
   move final file to parking lot
move temp file to final filename;
if move succeeded       
   delete previous final file. 
else
   restore previous final file.

Now to my questions:

  1. is it preferred to save the temporary file to a temporary directory, and then move it, as opposed to saving the temporary file to the final directory? (if so, why?)

  2. Is there a difference in attributes and permissions on a file that is first saved to a temp dir, then moved to the final file in a different directory, as compared to a file that is saved to a temp file in the final directory, and then renamed within the directory?

  3. If the answers to both are YES, then how can I do the preferred thing while getting the appropriate ACL on file which was first saved to a temporary directory and then moved to a final directory?

A: 

I prefer saving the temporary file to the final directory:

  1. It avoids the potential permission problems that you've described.

  2. The final directory might be on a different volume, in which case the move (of the temporary to the final file) is really a copy + delete -- which incurs a lot of overhead if you do it often or if the file is big.

You can always rename the existing file to a second temporary file, rename the new temporary file to the existing file's name, and rollback on error. That seems to me to be the safest combination.

EDITED: I see that your "parking lot" already described my suggestion, so I'm not sure I've added much here.

Ben M
+1  A: 

Microsoft Word saves a temp file to the original directory starting with a tilde (~). I would just follow that convention.

Spencer Ruport
Yes, and Excel, too, I think. And maybe other office apps.
Cheeso
Other apps mangle the name obnoxiously, for example InDesign creates a file that looks like its filename got corrupted. same practice, but sort of unfriendly.
TokenMacGuy
@Cheeso yeah you're correct, I think all the office apps do that. I figure if users are used to seeing the translucent file show up when they open an office file they won't be too surprised when your app does the same thing making it a safe approach all around.
Spencer Ruport
+1  A: 

Create a temp file in the temp folder if it is just a temporary file. Otherwise, create it in its final destination.

Caveats:

1) This may not work if the final destination is a 'pickup' folder (unless the 'pickup' process checks for locked files (which it should))

2) The final destination has special permissions that have to be created in code and applied before being able to move to the final destination.

Mitch Wheat
A: 

1 . Yes, it is preferred to save to a temporary file first

Because the final file will never be in a corrupt state should the creation of the file fails for any reason. If you write directly to the final file and your program crashed mid-way... it will definitely leave the final file in an invalid state.

2 . Yes

The "inherited" attributes and permissions will of course, be different. But temporary directories on most systems usually are pre-configured for all applications to use. The "final file" directory might, however, need to be configured. Say the "Program Files" folder and Vista UAC, for example.

3 . Copy ACL from the final file to the temp file prior to replacing?

chakrit
maybe I Wasn't clear. Q1 was an either or question. Which is preferrable, or does it matter? On Q3, your answer ignores 2 things: the bootstrap problem, and also how exactly do I copy an ACL?
Cheeso
A: 

Why not make it user configurable? Some users don't like temp files polluting their current directory.

Tyrone Slothrop
Presumably there will be no temp files left in the working directory, if the application does not fail. The reason to NOT make it configurable is because the answer to my Q2 is YES.
Cheeso
+1  A: 

If these are temp files that turn into permanent files, create them in the same location to avoid any risk of having to "move" files across disks/partitions, which will result in more I/O (as a copy followed by a delete).

If these are temp files that are truly temporary, create (and leave them) in the temp dir.

Joe
+1  A: 
  1. It is preferable to create a temp file using the GetTempFile routines because this creates temp files in predefined locations (e.g. C:\temp) that utilities can delete if your app crashes or makes corrupt files in. If the same thing happens in your final directory, it is unrecoverable.

  2. Yes, attributes could be different if the target file's attributes or ACL has been edited. This could happen even if you create the temp file in the same folder.

  3. You fix this by using the File.Replace routine, which performs an atomic replacement of one file with another, replacing the new file's attributes and ACLs with the old file's.

A C# method that does this is an answer to Safe stream update of file.

Dour High Arch
This is very helpful. File.Replace seems just what I want, except for one thing: the final file may not be on the same volume as that returned by GetTempFile.
Cheeso
The code I posted in the link handles that situation as well.
Dour High Arch
+1  A: 

A reason why you might want to never write a file to one directory and move it to another is because those directories might be on different filesystems. Although this is less often a problem on windows, it is still reasonably possible so long as the parent filesystem is ntfs. In unix, it is a standard practice for /tmp to be a different filesystem.

The reason this could be a problem is because that means the file has to be copied from one place to another. This significantly impacts performance for files of substantial size, and will certainly require many more seeks, even if the file is small. Additionally, there are many more ways for this to fail when moving a file across filesystem boundaries. Of coursea access permissions could be different, but also the target filesystem could be full, or any number of other additional complications that you are now deferring until much later.

TokenMacGuy