Slide 1: Lecture 02: File Systems, APIs, and System Calls

Principles of Computer Systems

Fall 2019

Stanford University

Computer Science Department

Instructors: Chris Gregg

and Nick Troccoli

Image:

Stanford University Oval

End of Image

PDF of this presentation

Slide 2: Assignment 1: Amazon Search

cgregg@myth57:$ ./amazon_search "best thing since sliced bread"
Found 258 matching reviews out of 3093869 reviews in the database.
**********
Review index: 3092071
Product title: Ceiva Internet-Enabled Photo Frame
Product category: Electronics
Star rating: 5 stars
Review headline: Rave Review !   Perfect for mom and grandma !
Review body: This product is the best thing since sliced bread !   I bought 5 of 
them for family and friends.  The best application for a ceiva is my grandmothers 
room, at the retirement home.  She is too old to use AOL or  WebTV.  Ceiva is the 
perfect bedside companion for her.  Everyday, she gets  a new set of 10 pictures 
downloaded from the 250 I have  "uploaded" to her album storage section.  
She has no computer  skills and doesn't know a jpeg from a gif, but she loves the 
pictures I  have sent to her via her Ceiva frame...
Date: 2000-5-10

**********

Slide 3: Assignment 1: Amazon Search

cgregg@myth57:/usr/class/cs110/staff/master_repos/assign1$ ./amazon_search '"almost killed me"' -k bodysize -r -n 1
Total number of keywords: 483621
Found 4 matching reviews out of 3093869 reviews in the database.
**********
Review index: 3043273
Product title: Segway Human Transporter (HT) p Series
Product category: Electronics
Star rating: 1 stars
Review headline: Segway Danger - almost Killed me.
Review body: I want to worn you before you get an the Segway and take off...I bought mine 
here from Amazon and at that time took 4 months to get it...then I started riding it with 
no problem everyday I could to get the mail up our 600 feet concrete driveway...when I 
returned everytime I hooked it up to the power source. This one day while going up the driveway 
which is on an incline...it powered down..and slammed me to the ground....without any notice..
I layed there until my brother came along and help me to the house....my back was brused...and 
it knocked some bone spurs loose in my neck....I contacted Amazon/Segway ..and SEGWAY said 
there was a recall to the computer system and I sent it back...and sold it ASAP...Segway never 
offered and relief on my bills..etc...MY advise to riders is they nee some sort of fail safe 
system for backway fails....I know how one could rig up a devise for the forward fall..but 
short of some sort of backward fall...I don't...I have played sports in school but never have 
been slammed a hard as that fall....I would say..be very careful and don't look for Segway to 
offer any type of help if you are hurt. <br />RDM
Date: 2005-8-10

**********

Slide 4: Assignment 1: Amazon Search

Slide 5: Assignment 1: Amazon Search

Slide 6: Assignment 1: Amazon Search: Virtual Memory for memory mapped files

Image:

This diagram demonstrates virtual memory. A file that is memory-mapped gets loaded into main memory as needed. If one program requests data from a memory-mapped file, that data is loaded into memory. Let's say that this address is 0xff00. The program has a pointer, say 0xAB00, that will get the data at 0xff00 when dereferenced. The operating system translates the program's pointer value to the physical address. If a second program also memory maps the file and requests the same portion of the file, it will have a different pointer value to the data, say, 0xDE00, and when it requests the data, the OS will translate the pointer value to 0xff00 in physical memory. Both programs are accessing the same physical memory through different pointer values that get translated.

End of Image

Slide 7: Assignment 1: Lambda Functions

void qsort(void *base, size_t nmemb, size_t size,
                  int (*compar)(const void *, const void *));
int add(int x, int y) { return x + y; }
int sub(int x, int y) { return x - y; }

void modifyVec(vector<int> &vec, int val, function<int(int, int)>op) {
   for (int &v : vec) {
      v = op(v,val);
   }
}

int main(int argc, char *argv[]) {
    string opStr = string(argv[1]);
    int val = atoi(argv[2]);

    vector<int> vec = {1, 2, 3, 4, 5, 10, 100, 1000};
    printVec("Original",vec);
    cout << "Performing " << opStr << " on vector with value " << val << endl;

    if (opStr == "add") modifyVec(vec, val, add);
    else if (opStr == "sub") modifyVec(vec, val, sub);

    printVec("Result",vec);

    return 0;
}
./fun_pointer add 12
Original: 1, 2, 3, 4, 5, 10, 100, 1000,
Performing add on vector with value 12
Result: 13, 14, 15, 16, 17, 22, 112, 1012,

Slide 8: Assignment 1: Lambda Functions

void modifyVec(vector<int> &vec, int val, function<int(int, int)>op) {
   for (int &v : vec) {
      v = op(v,val);
   }
}

int main(int argc, char *argv[]) {
    string opStr = string(argv[1]);
    int val = atoi(argv[2]);


    vector<int> vec = {1, 2, 3, 4, 5, 10, 100, 1000};
    printVec("Original", vec);
    cout << "Performing " << opStr << " on vector with value " << val << endl;

    if (opStr == "add") modifyVec(vec, val, [](int x, int y) {
                return x + y;
            });
    else if (opStr == "sub") modifyVec(vec, val, [](int x, int y) {
                return x - y;
            });

    printVec("Result", vec);

    return 0;
}

Slide 9: Assignment 1: Lambda Functions

void modifyVec(vector<int> &vec, int val, function<int(int, int)>op) {   
   for (int &v : vec) {
      v = op(v,val);
   }
}

Slide 10: Assignment 1: Lambda Functions

void modifyVec(vector<int> &vec, function<int(int)>op) {
   for (int &v : vec) {
      v = op(v);
   }
}

To this:

void modifyVec(vector<int> &vec, std::function<int(int v)>op) {
   for (int &v : vec) {
      v = op(v);
   }
}

int main(int argc, char *argv[]) {
    string opStr = string(argv[1]);
    int val = atoi(argv[2]);

    vector<int> vec = {1, 2, 3, 4, 5, 10, 100, 1000};
    printVec("Original", vec);
    cout << "Performing " << opStr << " on vector with value " << val << endl;

    if (opStr == "add") modifyVec(vec, [val](int x) {
                return x + val;
            });
    else if (opStr == "sub") modifyVec(vec, [val](int x) {
                return x - val;
            });

    printVec("Result", vec);

    return 0;
}

Slide 11: Assignment 1: Lambda Functions

    if (opStr == "add") modifyVec(vec, [&val](int x) {
                return x + val;
            });

Slide 12: Assignment 1: Lambda Functions

Slide 13: Implementing copy to emulate cp

Slide 14: UNIX Filesystem APIs

Slide 15: Back to file systems: Implementing copy to emulate cp

int main(int argc, char *argv[]) {
  int fdin = open(argv[1], O_RDONLY);
  int fdout = open(argv[2], O_WRONLY | O_CREAT | O_EXCL, 0644);
  char buffer[1024];
  while (true) {
    ssize_t bytesRead = read(fdin, buffer, sizeof(buffer));
    if (bytesRead == 0) break;
    size_t bytesWritten = 0;
    while (bytesWritten < bytesRead) {
      bytesWritten += write(fdout, buffer + bytesWritten, bytesRead - bytesWritten);
    }
  }
  close(fdin); 
  close(fdout)
  return 0;
}

Slide 16: Pros and cons of file descriptors over FILE pointers and C++ iostreams

Slide 17: Implementing t to emulate tee

$ cat alphabet.txt | ./tee one.txt two.txt three.txt
abcdefghijklmnopqrstuvwxyz
$  cat one.txt 
abcdefghijklmnopqrstuvwxyz
$  cat two.txt
abcdefghijklmnopqrstuvwxyz
$  diff one.txt two.txt
$  diff one.txt three.txt
$
$ cat vowels.txt | ./tee one.txt
aeiou
$  cat one.txt 
aeiou
Image:

This image is of the 'tee' program. For the command 'ls -l | tee file.txt | less', the output of ls will go into the tee program and the output will go to both file.txt and to the less program. In other words, tee makes a disk copy of its input while also sending the data to stdout.

End of Image

Source: https://commons.wikimedia.org/wiki/File:Tee.svg

Slide 18: Implementing t to emulate tee

int main(int argc, char *argv[]) {
  int fds[argc];
  fds[0] = STDOUT_FILENO;
  for (size_t i = 1; i < argc; i++)
    fds[i] = open(argv[i], O_WRONLY | O_CREAT | O_TRUNC, 0644);

  char buffer[2048];
  while (true) {
    ssize_t numRead = read(STDIN_FILENO, buffer, sizeof(buffer));
    if (numRead == 0) break;
    for (size_t i = 0; i < argc; i++) writeall(fds[i], buffer, numRead);
  }

  for (size_t i = 1; i < argc; i++) close(fds[i]);
  return 0;
}

static void writeall(int fd, const char buffer[], size_t len) {
  size_t numWritten = 0;
  while (numWritten < len) {
    numWritten += write(fd, buffer + numWritten, len - numWritten);
  }
}

Slide 19: Using stat and lstat

int stat(const char *pathname, struct stat *st);
int lstat(const char *pathname, struct stat *st);

Slide 20: Using stat and lstat

struct stat {
  dev_t st_dev;        // ID of device containing file
  ino_t st_ino;        // file serial number
  mode_t st_mode;      // mode of file
  // many other fields (file size, creation and modified times, etc)
};

Slide 21: Using stat and lstat

myth60$ find /usr/include -name stdio.h -print
/usr/include/stdio.h
/usr/include/x86_64-linux-gnu/bits/stdio.h
/usr/include/c++/5/tr1/stdio.h
/usr/include/bsd/stdio.h

myth60$ ./search /usr/include stdio.h
/usr/include/stdio.h
/usr/include/x86_64-linux-gnu/bits/stdio.h
/usr/include/c++/5/tr1/stdio.h
/usr/include/bsd/stdio.h
myth60$ 

Slide 22: Using stat and lstat

int main(int argc, char *argv[]) {
  assert(argc == 3);
  const char *directory = argv[1];
  struct stat st;
  lstat(directory, &st);
  assert(S_ISDIR(st.st_mode));
  size_t length = strlen(directory);
  if (length > kMaxPath) return 0; // assume kMaxPath is some #define
  const char *pattern = argv[2];
  char path[kMaxPath + 1];
  strcpy(path, directory); // buffer overflow impossible                 
  listMatches(path, length, pattern);
  return 0;
}

Slide 23: Using stat and lstat

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

Slide 24: Using stat and lstat

static void listMatches(char path[], size_t length, const char *name) {
  DIR *dir = opendir(path);
  if (dir == NULL) return; // it's a directory, but permission to open was denied
  strcpy(path + length++, "/");
  while (true) {
    struct dirent *de = readdir(dir);
    if (de == NULL) break; // we've iterated over every directory entry, so stop looping
    if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;
    if (length + strlen(de->d_name) > kMaxPath) continue;
    strcpy(path + length, de->d_name);
    struct stat st;
    lstat(path, &st);
    if (S_ISREG(st.st_mode)) {
      if (strcmp(de->d_name, name) == 0) printf("%s\n", path);
    } else if (S_ISDIR(st.st_mode)) {
      listMatches(path, length + strlen(de->d_name), name);
    }
  }
  closedir(dir);
}

Slide 25: Using stat and lstat

Slide 26: Using stat and lstat

myth60$ ./list /usr/class/cs110/WWW
drwxr-xr-x  8    70296 root       2048 Jan 08 17:16 .
drwxr-xr-x >9 root     root       2048 Jan 08 17:02 ..
drwxr-xr-x  2    70296 root       2048 Jan 08 15:45 restricted
drwxr-xr-x  4 cgregg   operator   2048 Jan 08 17:03 examples
-rw-------  1 cgregg   operator   2395 Jan 08 15:51 index.html
// others omitted for brevity
myth60$

Slide 27: Using stat and lstat

static inline void updatePermissionsBit(bool flag, char permissions[],
                                        size_t column, char ch) {
  if (flag) permissions[column] = ch;
}

static const size_t kNumPermissionColumns = 10;
static const char kPermissionChars[] = {'r', 'w', 'x'};
static const size_t kNumPermissionChars = sizeof(kPermissionChars);
static const mode_t kPermissionFlags[] = { 
  S_IRUSR, S_IWUSR, S_IXUSR, // user flags
  S_IRGRP, S_IWGRP, S_IXGRP, // group flags
  S_IROTH, S_IWOTH, S_IXOTH  // everyone (other) flags
};
static const size_t kNumPermissionFlags =
   sizeof(kPermissionFlags)/sizeof(kPermissionFlags[0]);

static void listPermissions(mode_t mode) {
  char permissions[kNumPermissionColumns + 1];
  memset(permissions, '-', sizeof(permissions));
  permissions[kNumPermissionColumns] = '\0';
  updatePermissionsBit(S_ISDIR(mode), permissions, 0, 'd');
  updatePermissionsBit(S_ISLNK(mode), permissions, 0, 'l');
  for (size_t i = 0; i < kNumPermissionFlags; i++) {
    updatePermissionsBit(mode & kPermissionFlags[i], permissions, i + 1, 
             kPermissionChars[i % kNumPermissionChars]);
  }
  printf("%s ", permissions);
}