A file is an inode with meta data among which a list of pointers to where to find the data.
In order to be able to access a file, you have to link it to a directory (think of directories as phone directories, not folders), that is add one or more entries to one of more directories to associate a name with that file.
All those links, those file names point to the same file. There's not one that is the original and the other ones that are links. They are all access points to the same file (same inode) in the directory tree. When you get the size of the file (lstat
system call), you're retrieving information (that metadata referred to above) stored in the inode, it doesn't matter which file name, which link you're using to refer to that file.
By contrast symlinks are another file (another inode) whose content is a path to the target file. Like any other file, those symlinks have to be linked to a directory (must have a name) so you can access them. You can also have several links to a symlinks, or in other words, symlinks can be given several names (in one or more directories).
$ touch a
$ ln a b
$ ln -s a c
$ ln c d
$ ls -li [a-d]
10486707 -rw-r--r-- 2 stephane stephane 0 Aug 27 17:05 a
10486707 -rw-r--r-- 2 stephane stephane 0 Aug 27 17:05 b
10502404 lrwxrwxrwx 2 stephane stephane 1 Aug 27 17:05 c -> a
10502404 lrwxrwxrwx 2 stephane stephane 1 Aug 27 17:05 d -> a
Above the file number 10486707 is a regular file. Two entries in the current directory (one with name a
, one with name b
) link to it. Because the link count is 2, we know there's no other name of that file in the current directory or any other directory. File number 10502404 is another file, this time of type symlink linked twice to the current directory. Its content (target) is the relative path "a".
Note that if 10502404 was linked to another directory than the current one, it would typically point to a different file depending on how it was accessed.
$ mkdir 1 2
$ echo foo > 1/a
$ echo bar > 2/a
$ ln -s a 1/b
$ ln 1/b 2/b
$ ls -lia 1 2
1:
total 92
10608644 drwxr-xr-x 2 stephane stephane 4096 Aug 27 17:26 ./
10485761 drwxrwxr-x 443 stephane stephane 81920 Aug 27 17:26 ../
10504186 -rw-r--r-- 1 stephane stephane 4 Aug 27 17:24 a
10539259 lrwxrwxrwx 2 stephane stephane 1 Aug 27 17:26 b -> a
2:
total 92
10608674 drwxr-xr-x 2 stephane stephane 4096 Aug 27 17:26 ./
10485761 drwxrwxr-x 443 stephane stephane 81920 Aug 27 17:26 ../
10539044 -rw-r--r-- 1 stephane stephane 4 Aug 27 17:24 a
10539259 lrwxrwxrwx 2 stephane stephane 1 Aug 27 17:26 b -> a
$ cat 1/b
foo
$ cat 2/b
bar
Files have no names associated with them other than in the directories that link them. The space taken by their names is the entries in those directories, it's accounted for in the file size/disk usage of the directories.
You'll notice that the system call to remove a file is unlink
. That is, you don't remove files, you unlink them from the directories they're referenced in. Once unlinked from the last directory that had an entry to a given file, that file is then destroyed (as long as no process has it opened).
Best Answer
The second thing you said is exactly correct. The file contents only exist once on disk. A hard link is an extra reference, which costs very little space - the size of a directory entry, which is the length of the filename plus a few bytes.
I don't know if this applies to OSX, but in the version of GNU coreutils I have handy,
du
is aware of hard links, so you can use it to get an accurate report of the total size of a set of files. If it finds multiple links to a file, it only adds it to the total once.ls -l
on the other hand does the wrong thing and adds everything it sees in a directory for itstotal
line.The ultimate demonstration would be to create a huge file, more than half the size of the disk. Then see how many hard links you can create to it. Should be quite a lot.