When does a file keep its identity?
◈ 8 cardsWhat `mv` really does within one file system, what it has to do across two, and how to prove which one just happened using `ls -i` and `df`.
mv is two different operations wearing one name
The command reads as though it moves data. Usually it does not.
If the source and the destination are on the same file system, mv does not touch a single byte of the file's contents. It creates a new directory entry pointing at the same inode number, then removes the old entry. Nothing is copied, nothing is read, and the operation costs the same whether the file is 8 kilobytes or 8 gigabytes. The inode number is unchanged — and since every attribute except the name lives in the inode, so are the permissions, the owner, the size and the timestamps.
If the source and the destination are on different file systems, that is impossible. A directory entry on file system B cannot name an inode number belonging to file system A, because an inode number is only an index into one i-list. So mv falls back to what it must do: copy the data to a brand-new file on B, then delete the original on A. The new file gets a fresh inode number from B's i-list, the copy costs time proportional to the file's size, and — a detail that matters in the next lesson — any other hard links to the original stay behind on A, still pointing at the old inode with the old contents.
One command, two mechanisms, and the deciding question is never "how far did it move?" but "did it cross a mount point?"
Worked example — the three-part experiment
This is the experiment the assignment asks for, done end to end. Create a file and record its identity:
$ echo 'draft notes' > ~/notes.txt
$ ls -i ~/notes.txt
4271 /home/ada/notes.txt
Inode 4271. Now rename it into a subdirectory of the same home directory:
$ mkdir -p ~/docs
$ mv ~/notes.txt ~/docs/notes.txt
$ ls -i ~/docs/notes.txt
4271 /home/ada/docs/notes.txt
Still 4271. The file did not move; a name did. Two directory entries were touched — one created in docs, one removed from the home directory — and the inode and every block it points at were left exactly where they were.
Now move it to /tmp, and first establish that /tmp really is somewhere else:
$ df /tmp .
Filesystem 1K-blocks Used Available Use% Mounted on
tmpfs 8123456 12288 8111168 1% /tmp
/dev/sda2 480123456 91234567 364512000 21% /home
Different devices, different mount points: two file systems. So:
$ mv ~/docs/notes.txt /tmp/notes.txt
$ ls -i /tmp/notes.txt
9130 /tmp/notes.txt
Inode 9130. A different number, because it is a different i-list, and — more precisely than that — it is a different file: the bytes were copied into a newly created file and the original was deleted. The inode number could not have been preserved even if the kernel had wanted to, since 4271 on /home and 4271 on /tmp are unrelated slots in unrelated tables.
Saying it in one sentence
When the exam asks why the inode number survived one move and not the other, the load-bearing sentence is: inode numbers are only meaningful within a single file system. A same-file-system mv is a link-and-unlink on directory entries, so identity is preserved; a cross-file-system mv is a copy-and-delete, so a new identity is created. df is the evidence for which case you are in.
A useful corollary to keep for the next lesson: because a cross-file-system move creates a new file, everything that depended on the old file's identity is quietly left behind. Other hard links keep the old data. And because the destination file is new, it takes a fresh set of timestamps and, if permissions cannot be reproduced, may not match the original exactly.