11

Whenever I list the contents of a directory with a function like readdir, the returned file names also include "." and "..". I have the suspicion that these are just normal links in the file system and therefore indistinguishable from actual files, but I always have to filter them out because they are not actual objects in the directory I am listing. Is there a good reason for functions like readdir to include them? Do some operating systems or file systems contain more or different virtual file names? Is there a better way to filter them out other than by doing string comparison with "." and ".."?

Update: thank you all for answering. I suppose I always thought that things like ./ and ../ were mere conventions that could be handled by searching and replacing. I find it a bit surprising, though probably more efficient and transparent, to have them be part of the file system itself.

One question remains, though: since . and .. are arbitrary names for these links, are there file systems that use different ones?

Lemming
  • 834
  • 1
  • 7
  • 16

8 Answers8

14

. and .. are actually hard links in filesystems. They are needed so that you can specify relative paths, based on some reference path (consider "../sibling/file.txt"). Since these hard links are actually existing in the filesystem, it makes sense for readdir to tell you about them. (actually the term hard link just means some name that is indistinguishable from the actual directory referred to: they both point to the same inode in the filesystem).

Best way is to just strcmp and ignore them, if you don't want to list them.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Well, that's just bizarre – Sapphire_Brick May 06 '20 at 00:17
  • This does not appear to e generally true. For example, Windows long paths (prefixed with \\?\) do not allow . or .. components, but they do still allow symlinks and junctions and hardlinks. – LB-- Jul 03 '23 at 21:01
9

Originally they were hard links, and the number of special cases in the filesystem code for . and .. were minimal. That's not true for all modern filesystems, however.

But the conventions have been established so that even filesystems where these two directory entries don't actually exist still report their existence through APIs like readdir. Changing this would now would break a lot of code.

Darron
  • 21,309
  • 5
  • 49
  • 53
4

I have the suspicion that these are just normal links in the file system and therefore indistinguishable from actual files

They are. While you may perceive the file system as a hierarchy of "folders" "containing" folders, it is actually a doubly linked tree1, with directories being nodes and files being leafs. So, . and .. are needed links for accessing the leaves of the current node and for traversing the tree, and they are the same thing as all the other links.

When you call readdir, you get all the places you can directly go to from the current node. If you do not want to list places that you perceive as "up", you have to sort them out yourself. You should write a little function for that, perhaps called readdir_down. I do not know in which order readdir lists the directories, but perhaps you can just throw away the first two entries.

1) this is a first approximation, there are also "hard links" possible that make the tree actually a net.

Svante
  • 50,694
  • 11
  • 78
  • 122
3

One reason is that without them there is no way to get to the parent directory. Or get a handle to the current directory.

Without them, we cannot do such things as:

./run_this

Indeed, we couldn't add '.' to the $PATH, meaning we couldn't ever execute files that weren't already in the path.

Matthew Schinckel
  • 35,041
  • 6
  • 86
  • 121
  • 1
    On Windows, . seems to be part of the PATH implicitely, meaning you can just type run_this. Being used to this, I always found insisting on the ./ prefix a bit annoying when using Linux, although I understand its value for security. – Lemming Nov 27 '08 at 02:26
  • I hadn't really thought that much about security constraints until it was explained to me earlier this year. The nasty user could have a command in her directory called ls, which an admin, when navigating to that directory, could execute, and that command could then allow the user extra access. Bad. – Matthew Schinckel Dec 11 '08 at 03:04
2

These are normal directories, they are "hard links" to the current directory and directory above. They are present in all directories (even at the root level, where .. is exactly the same as .).

When using ls, you can filter out . and .. with ls -A (note the capital -A).

When applying a command to all dot-files, but not . or .., I often use .??* which matches only dot-file with a name of three characters or more.

touch .??*

Note this pattern also excludes any other file that begins with dot and is only two characters long (e.g. .x) but those files are uncommon.

When using programmatic file-listers like readdir() I do have to exclude . and .. manually. Since these two files are supposed to be first in the list returned by readdir() you can do this:

@files = readdir(DIR);
for (1..2) { shift @files; } # get rid of . and ..
# go on with your business
Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • Those two lines should be put into a function. – Svante Nov 27 '08 at 02:16
  • 1
    How do you know they aren't *in* a function? :-) – Bill Karwin Nov 27 '08 at 02:19
  • Oddly enough, on Windows the root directories (c:\, d:\, ...) do not contain any of the two links. While omitting the .. one might make some sense, omitting . does not. – Lemming Nov 27 '08 at 02:31
  • Bill, see my comment as a "Yes, and ...", not as a "Yes, but ...". – Svante Nov 27 '08 at 10:14
  • 1
    `..` in the root directory of a **filesystem** is a special case, at least for filesystems that are mounted within other file systems. E.g. if `/home` has its own filesystem, the **path** `/home/..` refers back to the parent filesystem, even though the actual directory entry `..` has the same inode as `.` – MSalters Jan 06 '16 at 13:39
0

They are reported because they are stored in the directory listing. That's the way unices have always worked.

Leon Timmermans
  • 30,029
  • 2
  • 61
  • 110
0

Because on Unix-like operating systems, the directory-listing commands include those, and you use them to move up and down in the filesystem hierarchy.

Something like grep { not /^.{1,2}\z/ } readdir HANDLE should work for you.

Adam Jaskiewicz
  • 10,934
  • 3
  • 34
  • 37
  • 1
    Actually, the grep string would be /^\.{1,2}$/, as the period needs to be escaped. I would probably write this as /^\.\.?$/. – Lara Dougan Jan 02 '09 at 22:13
-4

there is no good reason a directory scan should return these filenames.

Scott Evernden
  • 39,136
  • 15
  • 78
  • 84