31

If I do the following:

touch /tmp/test

and then perform

ls -la /tmp/

I could see the test file with 0 Bytes in the directory.

But how does the Operating System handle a concept of 0 Bytes. If I put it in layman terms:

0 Bytes is no memory at all, hence nothing is created.

Creation of a file, must or should at least require certain memory, right?

63

A file is (roughly) three separate things:

  • An "inode", a metadata structure that keeps track of who owns the file, permissions, and a list of blocks on disk that actually contain the data.
  • One or more directory entries (the file names) that point to that inode
  • The actual blocks of data themselves

When you create an empty file, you create only the inode and a directory entry pointing to that inode. Same for sparse files (dd if=/dev/null of=sparse_file bs=10M seek=1).

When you create hardlinks to an existing file, you just create additional directory entries that point to the same inode.

I have simplified things here, but you get the idea.

  • 2
    nicely stated. while promoting one small conundrum by your "hard-links" paragraph: if one creates a hard-link to a empty file, which you state has no list of blocks, how can that hard-link point to the (same) list of blocks which don't exist? – Theophrastus Mar 28 '17 at 16:02
  • 4
    @Theophrastus Good point. I have made made my possible to simplify things. Actually between the list of blocks and the directory entries, there are metadata pertaining to the file (referred to by an inode number) and that contain file attributes (owner, permissions, ...) and extended attributes. The list of blocks is in there. So all the directory entries do not point directly to the list of blocks (the FAT way), but to metadata. – xhienne Mar 28 '17 at 16:16
  • 6
    Should be three separate things: A list of blocks that contain data; the blocks themselves; and a directory entry (or entries) that points to the list of blocks. – Wildcard Mar 29 '17 at 2:51
  • @Wildcard I've submitted an edit to make it three things, and referred to the inode by its name. Both the inode and directories are metadata; but they're different kinds of metadata. A file always has one inode, and at least one directory entry. That inode may include an empty list of data blocks. – Monty Harder Mar 29 '17 at 22:33
  • 1
    @Wildcard Even if you're a beginner, understanding the difference between an inode and a directory is important. When someone changes permissions/ownership of "a directory name" and thinks other links to the same inode will retain the old permissions/ownership, Something Very Bad could happen. We don't have to delve into the details of how inodes reference direct blocks, indirect blocks, doubly- and triply-indirect blocks to get that it's a list of blocks. Or that a list can be empty. – Monty Harder Mar 30 '17 at 17:05
23

touch will create an inode, and ls -i or stat will show info about the inode:

$ touch test
$ ls -i test
28971114 test
$ stat test
  File: ‘test’
  Size: 0           Blocks: 0          IO Block: 4096   regular empty file
Device: fc01h/64513d    Inode: 28971114    Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/1000)   Gid: ( 1000/1000)
Access: 2017-03-28 17:38:07.221131925 +0200
Modify: 2017-03-28 17:38:07.221131925 +0200
Change: 2017-03-28 17:38:07.221131925 +0200
 Birth: -

Notice that test uses 0 blocks. To store the data displayed, the inode uses some bytes. Those bytes are stored in the inode table. Look at the ext2 page for an example of an inode structure.

19

ls (or well, the stat(2) system call) tells you the size of the contents of the file. How much space the filesystem needs for bookkeeping is not part of that, and as an implementation detail, it's not something that programs in general should care or even know about. Making the implementation details visible would make the filesystem abstraction less useful.

9

The file, itself, does not occupy any space, but the file system does, storing the filename, location, access rights to it and the like.

  • 4
    If you look at the space occupied by the directory entry, if you have a directory containing a thousand files that are 0 bytes in size, the directory will be bigger than a directory entry that has just 2 huge files. – Mark Stewart Mar 28 '17 at 15:29
  • 2
    props for mentioning that a file is an abstract concept that is not tightly linked with its physical representation on e.g. a disk. – Florian Castellane Mar 29 '17 at 9:55
5

Simple answer: Because it's defined that way.

Longer answer: It's defined that way because some operations are conceptually simpler:

  • If a file contains 20 letters "A", and you remove all "A"s, then the file will become 20 bytes shorter. The same operation on a file that consisted of just "AAAAAAAAAAAAAAAAAAAA" would have to deal with the special case of a vanishing file.
  • More practically, deleting the last line of a text file would need to be special-cased.
  • Text editors that regularly make a backup would need special-case code to deal with the situation that the user might delete the last line, go to lunch, then come back and add another line. Further complications arise if some other users created a file with that name in the mean time.

You can do more things: * Error log files tend to be created empty, to be filled if and only if an error happens. * To find out how many errors happened, you count the number of lines in the log files. If the log file is empty, the number of errors is zero, which makes perfect sense. * Sometimes you see files where all the relevant text is in the file name, e.g. this-is-the-logging-directory. This prevents overeager administrators from deleting empty directories after installation, and it also prevents bugs where a program or a user accidentally creates a file where the program would like to see a directory later. The git program (and others) tend to ignore empty directories, and if a project/administrator/user wants to have a record that the directory exists even though it has no useful content (yet), you may see an empty file named empty or empty.directory.

No operations become more complicated:

  • Concatenating files: this is just a no-op with an empty file.
  • Searching for a string in a file: this is covered by the standard case of "if the file is shorter than the search term, it cannot contain the search term".
  • Reading from the file: programs need to deal with hitting the end of the file before they got what they expected, so again the case of a zero-length file does not involve extra thinking for the programmer: he'll just hit end-of-file from the beginning.

In the case of files, the "there is a file recorded somewhere" aspect (inode and/or file name) comes on top of the above considerations, but file systems would not do that if empty files were useless.

In general, all of the above reasons except those related to file names apply to sequences. Most notably to strings, which are sequences of characters: Zero-length strings are commonplace inside of programs. String are usually disallowed at the user level if they don't make sense: a file name is a string, and most file systems do not allow an empty string as a file name; internally, when creating file names from fragments, the program may well have an empty string as one of the fragments.

1

Using the simplest analogy:

Let's compare a file with, say, a glass of water.

'touch /tmp/test' is very much like creating an empty glass, without any water in it. The glass is empty, so it's size is zero. But the glass does exist.

In file system parlance, the glass is the meta-data, whereas the contents of the glass is the data. The meta-data contains all sorts of stuff as mentioned in the previous posts.

Zero-sized files can be useful. One example is using them as a breadcrumb, where its mere existence can be used to indicate some sort of state (i.e., if the file exists: then do something; if not: ignore).

0

Think about it this way: say that a program is tracking SQL queries sent to your server. The program wants to indicate that it is logging requests into a plain text file, but no requests have yet been logged. What should that look like? I'd argue that it should be a zero-sized file at /var/log/acme-sql-server/queries.log. That way, you could figure out when logging started (the file's creation time), when it was last updated (i.e. when it was created), how many queries were recorded (number of newlines in file = 0), and who's doing the logging (Acme SQL Server). For cases like this, it's useful to have the concept of an empty file that nevertheless exists at a particular location.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.