chdir: the unportable system call

davmac.org > Techblog

One highly requested feature for the java API is a way to change the current working directory. Apart from the havoc this potentially causes with relative File references, it does seem like a good idea. Or so I thought until recently.

Thing is, it's really, really hard to do a cross-platform version of chdir because:

The first point probably applies mainly to embedded systems, though theoretically a desktop operating system might not have a concept relating to the current working directory (and perhaps, arguably, it shouldn't).

The second point is ultimately the more problematic one, however. Suppose we implement a "chdir" function in java (or in any other supposedly cross-platform library or API). We use the unix model, ie. there is a single current working directory and all relative file references are normally resolved against it.

There is one operating system which already breaks that model, and it's an extremely popular one: it is, of course, Microsoft Windows. Specifically, a Windows process has a current directory, which consists of a drive designator plus a directory path within that drive (ignoring UNC paths for the moment). However, a path under Windows can consist of a drive letter followed by a colon but then not immediately followed by a (back)slash - for instance:

D:afile.txt
Now, that example path is not a relative path in the normal sense (that is, it's not relative to "the" current working directory) but neither is it an absolute path. In fact, the equivalent absolute path cannot be determined without further information (although we know that it begins with D: and ends with afile.txt).

The exact way it works depends on which version of Windows is running. In Windows 95 (and presumably 98 and ME) the system maintains a per-process current directory for each drive, and current drive for the process. Putting these together yields the current directory for the process. Note that changing the current directory for the process therefore also involves changing the current directory for a particular drive.

Windows NT/2000/XP on the other hand maintains a single current directory for each process as a complete entity. Drives still have a notional current directory as well, but these are stored in environment variables ("!C" contains the current directory for the C: drive, for instance) and are not affected by a regular chdir system call. However, a relative file path with a drive specifier resolves the relative path against the (process) current directory if the current directory is on the specified drive (and resolves against the drives current directory as obtained from the environment variables otherwise). This means that more modern versions of Windows mimic the behaviour of Windows 95 to a certain degree.

So, for a unix process there is a single current working directory. On Windows 95 there is one directory for each drive (and there is a current drive). On Windows NT there is one directory for each drive, plus a process current directory. What a mess.

So what is the solution? Well, the way I see it, the main use for a chdir call is not so much a useful thing for the current application - a good portable program should not depend on the notion of a current directory even existing - but mainly for purposes of executing other programs. And once you're doing that you're almost of the realm of applications programming anyway (and into the realm of systems programming).

What does that mean for the java API? Well, if the designers wanted to stay true to the notion of java not being a systems programming language, they shouldn't include a chdir method. On the other hand, it seems to be a line that's been crossed already - it's already possible to execute other programs and the result is very, very system dependent.

But that really gives a clue to the real answer. If chdir is a system dependent call, then make it available on a system-dependent basis, and document it as such. Why hobble java in such a way as to make it useless (or at least much harder to use) for a particular class of problems, by not including functionality that is so basic on many platforms?