CS 241 Section Week #8 (10/29/09)
Outline MP5 Overview Files & I/O UNIX File Systems inodes Directories Links
MP5 Overview
You are to create a “deadlock resilient semaphore” library. You should implement six functions. Since we only allow one instance of each resource, you do not need to implement the Banker’s algorithm for deadlock prevention. You may use a resource allocation graph instead. In deadlock detection mode, once a deadlock is detected, you need only send a SIGINT signal. The library does NOT need to worry about how SIGINT is handled. The given test cases are far from complete. You should derive your own test cases.
Files and I/O
Unix File Structure / /bin/ /home/ /home/someuser/ /home/someuser/somefile.txt /usr/ /usr/bin/ /usr/lib/
Internal File Structure A file is just a series of bytes: Thiswnixfile.
Internal File Structure A file is just a series of bytes: Thiswnixfile. Start of FileEnd of FileCurrent Offset
I/O Libraries in C kernel system call handler file I/O terminal I/O pipe I/O network I/O audio I/O open, read, write, close, select, poll,... (direct to kernel I/O) stdio: fopen, fread, fwrite, fclose,... (buffered I/O) User Process Kernel
I/O Libraries in C kernel system call handler file I/O terminal I/O pipe I/O network I/O audio I/O open, read, write, close, select, poll,... (direct to kernel I/O) stdio: fopen, fread, fwrite, fclose,... (buffered I/O) User Process Kernel
Buffered I/O Advantages We’ve previously used: – printf(…) – fprintf(…) Why use buffers? – I/O operations are SLOW! – Every time you write just one byte, you don’t want to have to access your hard drive.
File Descriptors The UNIX operating system uses a file descriptor table to store information about open files: 0stdin… (sof, eof, offset values, etc) 1stdout… 2stderr… 36/usr/home/myfile.txt…
open() int open(const char *pathname, int flags); – returns an int, which is the file descriptor – takes in either a relative or full path name – various flag options allow a file to only be appended to (O_APPEND), opened as write only (O_WRONLY), and more.
open() To open a file for reading: int ifd = open(“./input.txt”, O_RDONLY); To open OR create a file for writing, with given permissions: – int ofd = open(“output.txt”, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
fopen() FILE *fopen( const char *filename, const char *mode); Rather than an int (file descriptor), fopen returns a FILE stream.
File Permissions In UNIX, the file permissions system is relatively basic. – Each file has a single owner and a single group associated with it. – Each file also has permissions associated with itself for the owner, members of the group the file is in, and for everyone else.
File Permissions These permissions are stored as a three-octal- digit number (000 to 777). 755
File Permissions The most-significant number is the owner’s permission. 755 Owner
File Permissions The middle number is the group’s permission. 755 Group
File Permissions The least-significant number is everyone else’s permission. 755 Other
File Permissions Each octal number is simply three bits: a read bit, a write bit, and an execute bit Read: Write: Execute:
File Permissions Thus: – 755 means “everyone can read and execute by file, but only the owner can write to (edit) my file” – 644 means “everyone can read my file, only the owner can write to my file, and no one can execute it” – 660 means “only members of the file’s group and the file’s owner may read or edit the file; others cannot even read it”
Other C file commands! close(int fd) – Close the file associated with the given file descriptor number. – Can you close stdout? Try it. fclose(FILE *stream) – fclose can close stdout.
Other C file commands! ssize_t read(int fd, void *buf, size_t count); – Read up to count bytes from a file descriptor into the buffer buf. ssize_t write(int fd, void *buf, size_t count); – Write count bytes to a file descriptor from the buffer buf.
Buffered I/O versions… size_t fread(void *ptr, size_t size, size_t count, FILE* stream); – Read up to count*size bytes from a file descriptor into the buffer ptr. size_t fwrite(void *ptr, size_t size, size_t count, FILE* stream); – Write count*size bytes to a file descriptor from the buffer ptr.
Other C file commands! off_t lseek(int fd, off_t offset, int whence); – Seek to a different point in the file. – lseek(fd, 4, SEEK_SET) Seek four bytes after the beginning of the file. – lseek(fd, -4, SEEK_END) Seek four bytes before the end of the file. – lseek(fd, 16, SEEK_CUR) Seek sixteen bytes ahead of the current position.
Other C file commands! int fseek(FILE *stream, long int offset, int origin); – fseek(stream, 4, SEEK_SET) Seek four bytes after the beginning of the file. – fseek(stream, -4, SEEK_END) Seek four bytes before the end of the file. – fseek(stream, 16, SEEK_CUR) Seek sixteen bytes ahead of the current position.
UNIX File Systems
inode: per-file data structure Advantage Efficient for small files Flexible if the size changes Disadvantage File must fit in a single disk partition
UNIX File Systems inode (continued) Storing Large Files
Directories are files too! Directories, like files, have inodes with attributes and pointers to disk blocks
Directories are files too! Directories, like files, have inodes with attributes and pointers to disk blocks Each directory contains the name and i- node for each file in the directory.
Directories are files too! Directories, like files, have inodes with attributes and pointers to disk blocks Each directory contains the name and i- node for each file in the directory.
Directory functions #include Change the directory int chdir(const char *path); Get the current working directory char *getcwd(char *buf, size_t size);
Directory reading functions #include Open the directory DIR *opendir(const char *dirname); Close the directory int closedir(DIR *dirp); Read the directory struct dirent *readdir(DIR *dirp);
What’s in a directory entry? struct dirent Member Fields char d_name[256] Null-terminated file name ino_t d_ino inode number unsigned char d_reclen Length of this record unsigned char d_type Type of file (DT_REG, DT_DIR, DT_FIFO, DT_SOCK, DT_CHR, DT_BLK, DT_UNKNOWN)
Example 1 Use opendir and readdir to print all the filenames in the current directory: #include … DIR *dir; struct dirent *entry; dir = opendir(“.”); while(entry = readdir(dir)){ printf(“%s\n”,entry->d_name); } closedir(dir); Remember to include error checking!!
Example 2 Modify Example 1 to use the member fields of struct dirent to display the inode for each file, as well as whether the file is a directory or a regular file. #include … DIR *dir; struct dirent *entry; dir = opendir(“.”); while(entry = readdir(dir)){ printf(“%s %lu\n”,entry->d_name, entry->d_ino); if(entry->d_type == DT_DIR) printf(“Directory “); else if(entry->d_type == DT_REG) printf(“File ”); } closedir(dir); Remember to include error checking!!
More Directory Functions #include Set the position of next readdir void seekdir(DIR *dir, off_t offset); Set the position back to the start of the directory void rewinddir(DIR *dirp); Get the current location of directory stream off_t telldir (DIR *dir);
Warning! opendir and readdir are NOT thread- safe. DO NOT open two directories at the same time!
How to recursively traverse a directory tree 1.Open the directory ( opendir ) 2.Read each entry ( readdir ) If the file is a directory ( d_type == DT_DIR ), store it (e.g. in an array of strings). 3.Close the directory ( closedir ) 4.Traverse each saved subdirectory, EXCEPT '.' and '..'
File information: stat Use the stat functions to view the file’s inode’s attributes. #include For a file: int stat(const char *restrict path, struct stat *restrict buf); For a link: int lstat(const char *restrict path, struct stat *restrict buf); For a file descriptor: int fstat(int fildes, struct stat *buf);
Useful fields and macros in struct stat stat.st_size File size, in bytes stat.st_mode File type S_ISDIR(stat.st_mode) Is this a directory? User permissions Etc. stat.st_mtime Time of last modification
Example 3 Modify Example 2 to also give file information about each file. How large is each file? Which files are world-readable? Which files have been modified in the last 24 hours? Hint: man 2 stat
#include int main(int argc, char **argv) { DIR *dir; struct dirent *entry; time_t now = time(NULL); if((dir = opendir(".")) == NULL) { perror("Can't open directory"); exit(-1); } while((entry = readdir(dir)) != NULL) { struct stat status; if(entry->d_type == DT_DIR) printf("Directory "); else printf("File "); printf("%s is at inode %d\n", entry->d_name, entry->d_ino); if(stat(entry->d_name, &status)) { perror("\tCan't get stat info"); continue; } printf("\t %d bytes, ", status.st_size); if(status.st_mode & S_IROTH) printf("World-readable, "); if(difftime(now,status.st_mtime)<86400) printf("Recently updated, "); } closedir(dir); }
Links Hard Link Directory Entry e.g. all regular files Symbolic Link Also called a Soft Link A special file that serves as a reference to another file
Link Functions #include To create a new link: int link(const char *oldpath, const char *newpath); Same as ln To remove an entry from the directory: int unlink(const char *path); Same as rm Returns 0 if successful, -1 with errno set if unsuccessful
Hard Link Example Command Line ln /dirA/name1 /dirB/name2 C Code Segments if (link("/dirA/name1", "/dirB/name2") == -1) perror("Failed to make a new link in /dirB");
Hard Link Example (contd) Q: What happens if /dirA/name1 is deleted and recreated?
Hard Link Example (contd) A: /dirA/name1 and /dirB/name2 are now two distinct files.
Symbolic Link Function #include To create a symbolic link: int symlink(const char *oldpath, const char *newpath); Same function as command ln –s Returns 0 if successful, -1 with errno set if unsuccessful
Soft Link Example Command Line ln –s /dirA/name1 /dirB/name2 C Code Segments if (symlink("/dirA/name1", "/dirB/name2") == -1) perror("Failed to create a symbolic link in /dirB");
Soft Link Example (contd) Q: What happens if /dirA/name1 to is deleted and recreated?
Soft Link Example (contd) A: /dirA/name1 has a different inode, but /dir/name2 still links to it.
Link number The link number (the st_nlink field in stat ) tells how many directory entries link to this inode. The link number is: Set to 1 when a file is created Incremented when link is called Decremented when unlink is called The link number appears in the second column of the output of ls –l. Try it! The link number only counts hard links, not soft links.