CS 355 - Systems Programming:
Unix/Linux with C

Files and Directories

Reference: Molay, Understanding Unix/Linux Programming, Chapter 3.1-3.5

The ls command

Our standard approach to studying a Unix system command:

  1. What does ls do?
  2. How does ls work?
  3. Can I write ls?

What does ls do?

ls (without any parameters) prints a list of file names located in the current directory. ls -l shows detailed information about each file. ls is able to distinguish between files and directories.

Read the manual:

LS(1)                    BSD General Commands Manual                   LS(1)

NAME
     ls -- list directory contents

SYNOPSIS
     ls [-ABCFGHLOPRSTUW@abcdefghiklmnopqrstuwx1] [file ...]

DESCRIPTION
     For each operand that names a file of a type other than directory, ls
     displays its name as well as any requested, associated information. For
     each operand that names a file of type directory, ls displays the names
     of files contained within that directory, as well as any requested,
     associated information.

     If no operands are given, the contents of the current directory are dis-
     played.  If more than one operand is given, non-directory operands are
     displayed first; directory and non-directory operands are sorted sepa-
     rately and in lexicographical order.

     . . .

Some of the widely used command line options include:

A disk is organized as a tree of directories. Each directory contains files and/or other directories. Every file is located somewhere in a single tree of directories.

How does ls do it?

The basic operation of ls:

open directory
while not end of directory
    read directory entry
    display file info
close directory

A directory is a special kind of file that contains a list of names of files and directories. It consists of a sequence of records, each with a well documented structure. Each record represents one item - a single file or a single directory. Directories are never empty; each one always contain two special entries: . (current directory) and .. (parent directory).

System calls to work with directory entries:

$ man opendir

DIRECTORY(3)            BSD Library Functions Manual            DIRECTORY(3)

NAME
     closedir, dirfd, opendir, readdir, readdir_r, rewinddir, seekdir, telldir
     -- directory operations

LIBRARY
     Standard C Library (libc, -lc)

SYNOPSIS
     #include <dirent.h>

     int closedir(DIR *dirp);

     DIR *opendir(const char *dirname);

     struct dirent *readdir(DIR *dirp);

     . . .

Structure of dirent:

struct dirent {
    ino_t          d_ino;       /* inode number */
    off_t          d_off;       /* offset to the next dirent */
    unsigned short d_reclen;    /* length of this record */
    unsigned char  d_type;      /* type of file; not supported
                                   by all file system types */
    char           d_name[256]; /* filename */
};

Can I write ls?

Basic structure of the C code for ls:

main () {
   opendir
   while(readdir)
      print d_name
   closedir
}

Implementation of ls:

#include <stdio.h>
#include <dirent.h>

void do_ls(char []);

int main(int ac, char *av[])
{
   if (ac == 1)
      do_ls( "." );
   else
      printf("Usage: %s\n", av[0]);
   return 0;
}

void do_ls(char dirname[])
{
   DIR           *dir_ptr;      /* the directory */
   struct dirent *direntp;      /* each entry    */

   if ((dir_ptr = opendir(dirname)) == NULL)
      fprintf(stderr,"ls1: cannot open %s\n", dirname);
   else
   {
      while ((direntp = readdir(dir_ptr)) != NULL)
         printf("%s\n", direntp->d_name);
      closedir(dir_ptr);
   }
}