Generic Directory Operations

Contents

Structure
Create
Delete
Opendir
Readdir
Add a file
Remove a file
Change dir
Adding files to a directory
Locating a file

Structure

Directories impose a structure onto the file system, so that it is not just a ``collection of files''. This is needed because a non-trivial system will have lots of files. A directory maintains information about other files in the file system.

The file system may be flat with just one directory. CP/M and early MSDOS had this structure.

A more common system is a hierarchical tree of directories and files, such as Windows.

A variation on this is a directed acyclic graph (like a tree but a node can have more than one parent). This is used by Unix, where one file an be ``linked'' to another so that the one file has two or more file names.

Directory operations

Directories have an internal structure, unlike a general file that is just a sequence of bytes. It is more likely to be organised as a sequence of records of some kind. The allowable operations must take this into account.

Create

When a directory is created, a file is made with a particular record structure. There are usually two initial records in this file, one for the parent directory, one for the current directory. So a directory file contains information about about where it's parent is (for traveral upwards) and also where it is (so it can be located for operations such as ls .).

Delete

Usually directories cannot be deleted if they still contain files other than `.' and `..'. If they were, files would exist without a means of accessing them. Usually any files in a directory must be removed first.

Opendir

A directory is a file and can opened for reading or writing. However, since it has a special structure, there are usally special commands to open it

Readdir

Rading a directory should be done in terms of the records it contains rather than as a set of bytes.

Add a file

Adding a file to a directory requires creating a new directory record and adding it to the directory (treating it as a file). If the file is new, the file system may also create file information space for it, such as an inode.

Remove a file

Removing a file means that its entry must be removed from the directory. If the file is no longer referenced, it's content may also be removed from the file system. If it is still referenced, then this cannot happen.

A file can be referenced by multiple names in Unix, so it can only be removed after all its names have been deleted.

A file that is still open by a process is in use, and cannot be removed till all processes have finished with it.

Change dir

A user process begins in a particular directory. It should be able to navigate the directory structure using a change dir command. If each process has its own current directory (Unix), then this will just change the directory of the process. If there is a single current directory (MSDOS) then changing the directory will be global.

Adding files to a directory

When a directory is created it will be empty except for its parent and maybe itself. The directory tree can be traversed up and down. When a file is created (eg by creat in Unix) an entry is made for the new file in the directory.

In the MSDOS file system, directory entries are 32-byte records. These hold the filename, the extension, the attributes, the date of last modification and the first block and the file size. All the principal information about the file is held in this directory

msdos

In Unix, all that kind of information is held in the inode. The directory just holds the name of the file and the inode number.

unix

The inode method allows multiple links to the same file, as the directories just hold the different file names and the same inode number. A ``link count'' within the inode keeps track of how many filenames a file has. When this count drops down to zero, the file is removed.

Locating a file

When a file needs to be accessed, say when it is opened for reading, its blocks on disk have to be found. Say the file is /usr/jan/file1. In Unix, the root directory is located at a fixed place on the disk. This directory is then read for the entry ``usr''. When it is found, its inode is known. From the inode, the location on disk of the directory is found. This is then read looking for the entry for ``jan''. When it is found its inode is given. From there the directory on disk can be found, and read for the file ``file1''. When this is found, its inode is known and the file blocks are finally located.

Directories - Unix API

Contents

mkdir
creat
link
unlink
rmdir
chdir
getcwd
Reading dirs
Examples

Unix API

Some of the Unix API for directory operations is
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int mkdir(char *path,
          mode_t mode);
int creat(char *path, 
          mode_t mode);
int link(char *path1, char *path2);
int unlink(char *path);
int rmdir(char *path);
int chdir(char *path);
char *getcwd(char *buf, int size);
and
#include <sys/types.h>
#include <dirent.h>

DIR *opendir(char *path);
struct dirent *readdir(DIR *dirp);
int closedir(DIR *dirp);

mkdir

This creates a new directory with no initial contents (apart from `.' and `..'). It returns -1 on failure

creat

This creates a new file, using a new inode. It also creates a new entry in the directory. Since this changes the directory (as a file), the last modified times of the directory are updated.

link

link adds another name to an existing file. It does not make a new inode entry, but does make a new directory entry. The link count in the inode is increased.

unlink

This removes an entry from a directory. The link count in the inode is decreased. If the count falls to zero, the file can be removed once no process has it open. Removing a file from a directory changes the last modified time of the directory (it is a file with changed contents).

rmdir

Removing a directory will fail unless the directory is empty.

chdir

This will attempt to change directory. The types of patterns that will be accepted for directory names is not specified.

getcwd

This will fill in the buffer with the current directory. This call can actually fail: if another process has succeeded in removing the current directory of a process.

Reading dirs

The call opendir() opens a directory for reading. The returned DIR value is opaque and is just passed to other functions. It is NULL on error.

Under Linux, the DIR structure is

typedef struct DIR
{
  /* file descriptor */
  int dd_fd;

  /* offset of the next dir entry in buffer */
  off_t dd_loc;

  /* bytes of valid entries in buffer */
  size_t dd_size;

  /* -> directory buffer */
  struct dirent *dd_buf;
} DIR;

The call readdir() returns a structure that you can use. It is specified to have one entry char *d_name. Under Linux it is defined as

struct dirent {
        long            d_ino;
        __kernel_off_t  d_off;
        unsigned short  d_reclen;
        char            d_name[256]; 
};

Examples

This creates a directory, puts a file into it and then removes it.
#include 
#include 
#include 

int main(void)
{  int fd;

  if (mkdir("mydir", 0777)
           == -1)
    exit(1);
  if ((fd = creat("mydir/f1",
                0777)) == -1)
    exit(2);
  close(fd);

  unlink("mydir/f1");
  exit(0);
}
A program to scan the current directory, printing its contents is
#include <iostream.h>
#include <dirent.h>

int main(int argc, char *argv[])
{
  DIR *dirp;
  struct dirent *dp;

  if ((dirp = opendir(".")) == NULL)
  {
    cerr << "Can't open .\n";
    exit(1);
  }

  for (dp = readdir(dirp);
       dp != NULL;
       dp = readdir(dirp))
    cout << "File: " <<
	   dp->d_name << endl;

  closedir(dirp);
  exit(0);
}


Home Systems Software Home
Jan Newmarch (http://jan.newmarch.name) <jan@newmarch.name>

Copyright © Jan Newmarch
Last modified: Wed Nov 19 17:55:42 EST 1997