Renaming Files
Let's look at how the renaming files work under the hood.
Once we have a file, it is sometimes useful to be able to give a file a different name. When typing at the command line, this is accomplished with mv
command; in this example, the file foo
is renamed bar
:
prompt> mv foo bar
Using strace
, we can see that mv
uses the system call rename(char *old, char *new)
, which takes precisely two arguments: the original name of the file (old
) and the new name (new
).
Try it out yourself:
One interesting guarantee provided by the rename()
call is that it is (usually) implemented as an atomic call with respect to system crashes. If the system crashes during the renaming, the file will either be named the old name or the new name, and no odd in-between state can arise. Thus, rename()
is critical for supporting certain kinds of applications that require an atomic update to file state.
Let’s be a little more specific here. Imagine that you are using a file editor (e.g., emacs), and you insert a line into the middle of a file. The file’s name, for example, is foo.txt
. The way the editor might update the file to guarantee that the new file has the original contents plus the line inserted is as follows (ignoring error-checking for simplicity):
int fd = open("foo.txt.tmp", O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);write(fd, buffer, size); // write out new version of filefsync(fd);close(fd);rename("foo.txt.tmp", "foo.txt");
In this example, the editor simply writes out the new version of the file under a temporary name (foo.txt.tmp)
and forces it to disk with fsync()
. Then, when the application is certain the new file metadata and contents are on the disk, rename the temporary file to the original file’s name. This last step atomically swaps the new file into place, while concurrently deleting the old version of the file, and thus an atomic file update is achieved.
Get hands-on with 1400+ tech skills courses.