tags:

views:

218

answers:

5

I have a program that accepts two file names as arguments: it reads the first file in order to create the second file. How can I ensure that the program won't overwrite the first file?

Restrictions:

  • The method must keep working when the file system supports (soft or hard) links
  • File permissions are fixed and it is only required that the first file is readable and the second file writeable
  • It should preferably be platform-neutral (although Linux is the primary target)
+3  A: 

If possible, open the first file read-only, (O_RDONLY) in LINUX. Then, if you try to open it again to write to it, you will get an error.

tvanfosson
You will get false positives if the second file is already open read-only by another process. I'm not even sure the universal solution is possible (you have to resort to file-system-specific features like getting file IDs).
Costique
+8  A: 

The best bet is not to use filenames as identities. Instead, when you open the file for reading, lock it, using whatever mechanism your OS supports. When you then also open the file for writing, also lock it - if the lock fails, report an error.

anon
Not very unixy, but nice meta logic that will work on most platforms,
dmckee
+9  A: 

On linux, open both files, and use fstat to check if st_ino (edit:) and st_dev are the same. open will follow symbolic links. Don't use stat directly, to prevent race conditions.

Tobu
The race condition means that the file status might change between stat(2) and open(2). You do stat, and then some user unlinks the file you've just stated and links your second file to the one you're just about to open(2). Just a clarification.
Tadeusz A. Kadłubowski
Also make sure the `st_dev` fields match. There's nothing preventing different files on two different volumes from having the same inode number.
Mike DeSimone
A: 

You can use stat to get the file status, and check if the inode numbers are the same.

reko_t
A: 

Maybe you could use the system() function in order to invoke some shell commands?

In bash, you would simply call:

stat -c %i filename

This displays the inode number of a file. You can compare two files this way and if their inodes are identical, it means they are hard links. The following call:

stat -c %N filename

will display the file's name and if it's a symbolic link, it'll print the file name it links to as well. It prints out only one name, even if the file it points to has hard links, so checking the symbolic link would require comparing inode numbers for the 2nd file and the file the symbolic links links to in order to make sure.

You could redirect stat output to a text file and then parse the file in your program.

mingos
Not my downvote, but there is rarely a point in shelling out to run a command to convert data to text and then parsing the text. On unix systems the SEE ALSO section of the man page will generally tell you what function the command line utilities are calling to achieve their work. In this case `man 1 stat` tells me about `lstat(2)` and `stat(2)` which share a man page with `fstat(2)`, so you can get to the optimal answer pretty easily.
dmckee
In general, I thing calling system() is a Bad Thing (tm). Just suggested a possibility, although I recognise it's suboptimal.
mingos