Users and Files: cp and tail
Prof. Brian D. Davison
Computer Science & Engineering, Lehigh University
Announcements
- Reminder of scripting project due Thursday
- Homework 5 online, due Monday (likely in lab)
- Friday's quiz: shell scripting and unix programming
- Today's schedule
- Return Project #4, range 29-100, mean 85
- Many points lost for errors that showed up with ccmalloc and electric fence
- TA was quite generous
- Continue Understanding UNIX Programming
cp (read and write)
% cp sourcefile copyfile
What does cp do?
- Answer: creates or truncates a file, then writes data into it
How does it do so?
- Answer: let's find out by searching the manual pages
Creating/truncating a file
- Creating
- fd = creat(name, 0644)
- First creates or truncates a file
- Then opens the file for writing
- If create, set mode to 0644
- returns -1 on error, otherwise a file descriptor
- Writing
- n = write(fd, buffer, num)
- sends num bytes to the file
- returns actual number sent, or -1 on error
Writing copy.c
- Want (logically):
- open sourcefile
- creat copyfile
- read source to a buffer (until eof)
- write buffer to the copy, repeat
- close both files
- Let's do it...
Control flow in copying a file
Does the size of the buffer matter?
- Could use a buffer of size 1!
- Consider a filesize of 100,000 bytes
- If buffer is 100 bytes => 1,000 read() and write() calls
- If buffer is 10000 bytes => 10 read() and write() calls
- System calls are resource intensive!
- Requires shift from user mode to kernel mode and back
- Usually want to minimize system calls
Efficiency
- Does this mean our who implementation is inefficient?
- It might if we were accessing the file directly
- Difficult to tell with the library
- In general, it is a good idea to read a bunch of records/bytes/etc at a time and then access them from the buffer
Can't the kernel do our buffering?
-
Actually, it does. The kernel keeps copies of disk blocks in memory.
It writes those blocks to disk now and then. The read() call actually
copies data from kernel buffers, not from the disk.
Consequences of buffering
- Faster "disk" I/O
- Optimal disk reads and writes
- Need to sync disks before shutdown
Another example: tail
- What does tail do?
- How does tail work?
Reading arbitrary bytes from a file
- Q: How can a program jump to the end (or any arbitrary location) of a file?
- A: lseek(fd, offset, base)
Directories, File Info, etc.
- We've now seen how to operate on the contents of a file
- open, read, write, close, lseek
- But there is more to a file than just contents
- Properties -- size, owner, permissions, type, ...
- Location -- in a directory tree
- We will write a version of ls
Writing ls (using same approach)
- What does ls do?
- Lists contents of directories and info about files
- Has many options, such as -l -a -lu -s
- Processes arguments of directories and filenames (or just current dir)
- Recall that the filesystem is organized like a tree
Writing ls (using same approach)
- So writing ls should be easy...
- Open directory
- Repeatedly read directory entry and display entry
- Close directory
- Much like the who command
Directories
- Q: What is a directory?
- A: A special kind of file that contains a list of files and/or other directories
- Note: Every directory contains special entries . and ..
- Q: Can we use file operators on directories? (e.g., open, read, etc.)
- A: Once, there was no other way
- Let's try cat /; more /tmp; od -c /etc
Reading Directories
- A2: Even if you could read all directories as files, you don't want to --
particularly since UNIX supports a variety of directory formats
- Q: So how do we read directories?
Reading Directories
- A2: Even if you could read all directories as files, you don't want to --
particularly since UNIX supports a variety of directory formats
- Q: So how do we read directories?
man -k direct
man -k direct | grep read
- A: opendir(), readdir(), closedir()
Using Directory Functions
#include <dirent.h>
opendir(name)
- Creates a connection, returns a DIR *
readdir(DIR *)
- Gets next record from directory, returns struct dirent *
closedir(DIR *)
Writing first version of ls.c
main()
opendir()
while ( readdir() )
print d_name
closedir()
return 0
- Let's compile and run the code