1
System Programming
Chapter 4Files and Directories
2
Fun Projects
• Communicating intimacy vs. communicating verbal messages
• Lovers’ cups, drinking interfaces (MIT media Lab)
• Emotional (Crying) Décor (NYU)
• Interactive Pillow (TII, Sweden)
• Hand holding (Cornell)
3
More Fun Project
• Do you feel confused in the classroom?• Do you feel bored in the classroom?• Do you feel ignored in the classroom? • Do you feel unfairness that only the speaker has
control of the slides?
• Now … you can express frustration with the Active Slides!
4
Files and Directories
• Objectives– Additional Features of the File System– Properties of a File.
• Three major functions:
#include <sys/types.h>
#include <sys/stat.h>
int stat(const char *pathname, struct stat *buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
5
Files and Directories
• Differences on stat(), fstat(), lstat():– lstat() returns info regarding the symbolic link, instead of the referen
ced file, if it happens.struct stat {
mode_t st_mode; /* type & mode */
ino_t st_ino; /* i-node number */
dev_t st_dev; /* device no (filesystem) */
dev_t st_rdev; /* device no for special file */
nlink_t st_nlink; /* # of links */
uid_t st_uid; gid_t st_gid;
off_t st_size; /* sizes in byes */
time_t st_atime; /* last access time */
time_t st_mtime; /* last modification time */
time_t st_ctime; /* time for last status change */
long st_blk_size; /* best I/O block size */
long st_blocks; /* number of 512-byte blocks allocated */
};
6
File Types
• Encoded in st_mode• Regular Files: text, binary, etc.• Directory Files: Only Kernel can update these files – { (f
ilename, pointer) }.• Character Special Files, e.g., tty, audio, etc.• Block Special Files, e.g., disks, etc.• FIFO – named pipes• Sockets – not POSIX.1 or SVR4
– SVR4 uses library of socket functions, instead. 4.3+BSD has a file type of socket.
• Symbolic Links – not POSIX.1 or SVR4
7
File Type Macro in <sys/stats.h>
S_ISREG() // regular file
S_ISDIR()
S_ISCHR()
S_ISBLK()
S_ISFIFO()
S_ISLNK()
S_ISSOCK()
8
Figure 4.3#include "apue.h"
Int main(int argc, char *argv[]){
int i;struct stat buf;char *ptr;
for (i = 1; i < argc; i++) {printf("%s: ", argv[i]);if (lstat(argv[i], &buf) < 0) {
err_ret("lstat error");continue;
}if (S_ISREG(buf.st_mode))
ptr = "regular ";else if (S_ISDIR(buf.st_mode))
ptr = "directory";
else if (S_ISCHR(buf.st_mode))ptr = "character special";
if (S_ISBLK(buf.st_mode))ptr = "block special";
else if (S_ISFIFO(buf.st_mode))ptr = "fifo";
else if (S_ISLNK(buf.st_mode))ptr = "symbolic link";
else if (S_ISSOCK(buf.st_mode))ptr = "socket";
elseptr = "** unknown mode **";
printf("%s\n", ptr);}exit(0);
}
9
File Access Permissions
• All files have access permissions– st_mode mask – owner, group, other
#define S_IRWXU 00700 /* read, write, execute: owner */
#define S_IRUSR 00400 /* read permission: owner */
#define S_IWUSR 00200 /* write permission: owner */
#define S_IXUSR 00100 /* execute permission: owner */
#define S_IRWXG 00070 /* read, write, execute: group */
#define S_IRGRP 00040 /* read permission: group */
#define S_IWGRP 00020 /* write permission: group */
#define S_IXGRP 00010 /* execute permission: group */
#define S_IRWXO 00007 /* read, write, execute: other */
#define S_IROTH 00004 /* read permission: other */
#define S_IWOTH 00002 /* write permission: other */
#define S_IXOTH 00001 /* execute permission: other */
10
File Operations vs. Access Permissions
• File Operations: read, write, execute, etc.• File Access Permissions: who (process) can perform what operations
• Directory file– X – pass through the dir (search bit), e.g., /usr/dict/words.– R – list of files under the dir.– W – update the dir, e.g., delete or create a file.
• Regular file– X – execute a file (which must be a regular file)– R – O_RDONLY or O_RDWR– W – O_WRONLY, O_RDWR, or O_TRUNC
• What are the needed file access permissions?– ls /home/professor/hchu– cd /home/professor/hchu– rm /home/professor/hchu/foo– cat /home/professor/hchu/foo– echo 123 >> /home/professor/hchu/foo
11
Process IDs
• How to check if a process can perform an operation on file access permissions?– File access test: check (process IDs, file APs, OP)
• A process can have more than one ID.– Real user/group ID // who we really are, e.g., hchu– Effective user/group ID // used for file access
// permission checks– Supplementary group IDs– Saved set-user/group-ID // saved by exec function
12
Access Permissions & UID/GID
• File Access Test – each time a process creates/opens/deletes a file– If the effective UID == 0 superuser!– If the effective UID == UID of the file
• Check appropriate access permissions!– If the effective GID == GID of the file
• Check appropriate access permissions!– Check appropriate access permissions for others!
• Related Commands: chmod & umask
13
hchu@linux1:/> ls -l /etc/shadow-rw-r----- 1 root shadow 843 2006-03-07 10:01 /etc/shadowhchu@linux1:/> cat /etc/shadow
hchu@linux1:/> ls -al .drwxr-xr-x 22 root root 4096 2006-01-20 13:33 ./drwxr-xr-x 22 root root 4096 2006-01-20 13:33 ../drwxr-xr-x 2 root root 4096 2006-03-13 18:23 bin/
hchu@linux1:/> cd bin
hchu@linux1:/usr/include> which passwd/usr/bin/passwd
hchu@linux1:/usr/include> ls -l /usr/bin/passwd-rwsr-xr-x 1 root root 28224 2006-02-22 14:05 /usr/bin/passwd
hchu@linux1:/usr/include> rm /usr/bin/passwd hchu@linux1:/usr/include> passwd
14
Set-User-ID/Set-Group-ID
• st_mode: st_uid/st_gid– Setting user/group ID of the owner.
• How can a user change his/her password without having the write permission to /etc/passwd and /etc/shadow?
• A process can have more than one ID. – Real user/group ID– Effective user/group ID– Supplementary group IDs– Saved set-user/group-ID
-rw-r--r-- 1 root root 1746 2/21 13:00 /etc/passwd-r-------- 1 root root 1142 2/21 13:01 /etc/shadow
15
Ownership of a New File
• Rules:– UID of a file = the effective UID of the creating pro
cess– GID of a file – options under POSIX
1. GID of the file = the effective GID of the process2. GID of the file = the GID of the residing dir
– 4.3BSD and Mac OS X do (2).– SVR4 needs to set the set-group-ID bit of the residing
dir (mkdir)!
16
Function – access • Test a file accessibility before accessing it.
#include <unistd.h>int access(const char *pathname, int mode);
– R_OK // test for read permission– W_OK– X_OK– F_OK– Check the real UID/GID!
17
Figure 4.8 Program#include "apue.h"#include <fcntl.h>
intmain(int argc, char *argv[]){
if (argc != 2)err_quit("usage: a.out <pathna
me>");if (access(argv[1], R_OK) < 0)
err_ret("access error for %s", argv[1]);else
printf("read access OK\n");if (open(argv[1], O_RDONLY) < 0)
err_ret("open error for %s", argv[1]);else
printf("open for reading OK\n");exit(0);
}
>ls -l fig4.8.exe-rwxr-xr-x 1 hchu users 9487 200
6-03-21 19:53 fig4.8.exe>fig4.8.exe fig4.8.exeread access OKopen for reading OK>ls -l /etc/shadow-rw-r----- 1 root shadow 843 200
6-03-07 10:01 /etc/shadow>fig4.8.exe /etc/shadowaccess error for /etc/shadow: Pe
rmission deniedopen error for /etc/shadow: Per
mission denied
18
Function – umask• Set file mode creation mask (default file permissions)
#include <sys/types.h>#include <sys/stat.h>mode_t umask(mode_t cmask);
– Any bits that are on in the cmask are turned off in the file’s mode
• cmask = bitwise-OR file access permissions (e.g., S_I[RWX]USR) • Examples: cmask = S_IRWXO, cmask = S_IWOTH | S_IWGRP
– The mask goes with the process only.• Inheritance from the parent!
19
Figure 4.9 Program
#include "apue.h"#include <fcntl.h>
#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
intmain(void){
umask(0);if (creat("foo", RWRWRW) < 0)err_sys("creat error for foo");umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);if (creat("bar", RWRWRW) < 0)err_sys("creat error for bar");exit(0);
}
>umask22>fig4.9.exe>ls -al foo bar-rw------- 1 hchu users 0 2006-03-21 20:
14 bar-rw-rw-rw- 1 hchu users 0 2006-03-21
20:14 foo>umask22
20
Function – chmod & fchmod• Change file access permissions for an existing file.
#include <sys/types.h>#include <sys/stat.h>int chmod(const char *pathname, mode_t mode);int fchmod(int filedes, mode_t mode);
– fchmod() is not in POSIX.1, but in SVR4/4.3+BSD– Callers must be a superuser or effective UID = file UID.– Mode = bitwise-OR S_I[RWX]USR, S_ISVTX (sticky bit), S_IS[U
G]ID, etc (Fig 4.6).
21
Figure 4.10 Program#include "apue.h"
Int main(void){
struct stat statbuf;
/* turn on set-group-ID and turn off group-execute */
if (stat("foo", &statbuf) < 0)err_sys("stat error for foo");
if (chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)
err_sys("chmod error for foo");
/* set absolute mode to "rw-r--r--" */
if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0)
err_sys("chmod error for bar");
exit(0);}
>ls -al foo bar-rw------- 1 hchu users 0 2006-03-2
1 20:14 bar-rw-rw-rw- 1 hchu users 0 2006-0
3-21 20:14 foo>fig4.12.exe>ls -al foo bar-rw-r--r-- 1 hchu users 0 2006-03-2
1 20:14 bar-rw-rwSrw- 1 hchu users 0 2006-0
3-21 20:14 foo
// what is strange here?
22
Function – chmod & fchmod
• set-group-ID – If the GID of a newly created file is not equal to the
effective GID of the creating process (or one of the supplementary GID’s), or the process is not a superuser, clear the set-group-ID bit!
– Clear up set-user/group-ID bits if a non-superuser process writes to a set-uid/gid file.
23
Function – chmod & fchmod
• Sticky Bit (S_ISVTX) – saved-text bit– For frequently executed binaries– Not POSIX.1 – by SVR4 & 4.3+BSD– Only superusers can set it!– S_ISVTX executable file
• Used to save a copy of a S_ISVTX executable in the swap area to speed up the execution next time.
– S_ISVTX directory file, e.g., /tmp• Remove/rename its file only if w permission of the dir is se
t, and the process is belonging to superusers/owner of the file/dir
24
Function – chown, fchown, lchown
• Change the user/group ID of a file
#include <sys/types.h>#include <unistd.h>int chown(const char *pathname, uid_t owner, gid_t, grp);int fchown(int filedes, uid_t owner, gid_t, grp);int lchown(const char *pathname, uid_t owner, gid_t, grp);
– lchown() is unique to SVR4. Under non-SVR4 systems, if the pathname to chown() is a symbolic link, only the ownership of the symbolic link is changed.
– -1 for owner or grp if no change is wanted.
• Why would one want to give away file ownership?
25
Function – chown, fchown, lchown
• _POSIX_CHOWN_RESTRICTED is in effect (check pathconf())– Superuser the UID of the file can be changed!– The GID of the file can be changed if
• the process owns the file, and• Parameter owner = UID of the file & Parameter grp = the pr
ocess GID or is in supplementary GID’s• set-user/group-ID bits would be cleared if chown is called b
y non-super users.
26
File Size
• File Sizes – st_size– Regular files – 0~max (off_t)– Directory files – multiples of 16/512– Symbolic links – pathname length– /* a pipe’s file size for SVR4 */
• File Holes– st_blocks vs st_size (st_blksize)– Commands:
• “ls –l file.hole” == “wc –c file.hole”• du –s file.hole actual size• cat file.hole > file.hole.copy
27
Functions – truncate & ftruncate
#include <sys/types.h>#include <unistd.h>int truncate(const char *pathname, off_t length);int ftruncate(int filedes, off_t length);
– Not POSIX.1– SVR4 creates a hole if length > fsize.– 4.3+BSD only truncates files.– Portability?
28
System ProgrammingChapter 4
朱浩華教授 / 施吉昇教授臺灣大學資訊工程系
29
Administration Misc. (4/12)
• The mid-term will be held on April 26, 2006 in class. It will cover Chapter 1 to 6.
• MP2 is out today and due on April 28, 2006 (Friday).
• Some of your email address on website have been deleted due to a bug for the web site. Please visit the site to update your email address.
30
Playing with Shadow(Tokyo University)
31
Filesystem• A disk can be divided into logical partitions.• Each partition has a filesystem.• Each filesystem contains a list of inodes (i-list) as well as the actu
al directory- and data blocks• Every inode has a link count (st_nlink): it shows how many “thin
gs” point to this inode. Only if this link count is 0 are the data blocks freed. Each name <-> inode association is called a hard link.
• inode contains most of information found in the stat structure.• inode number in a directory entry must point to an inode on the
same file system (no hardlinks across filesystems)• To move a file within a single filesystem, we can just ”move” th
e directory entry (actually done by creating a new entry, and deleting the old one).
32
BSD UNIX File System (UFS)
33
BSD UNIX File System (UFS)Figure 4.14 (hard links)
34
Filesystem – 4.4BSD i-node
* “Operating system concept”, Silberschatz and Galvin, Addison Wesley, pp. 380.
mode
owner
timestamp
size block
ref-count
triple indirect
double indirect
single indirect
direct blocks
data
data
data
…
…
data
data
data…
…
…
…
data
data…
data…
• 4KB block size• 12 direct pointers
• 48KB• 1 single indirect
• 4-byte block ptr• 1K * 4KB = 4MB
• >> 4GB for the largest file! (offset = 32 bits, 4G=232)
35
BSD UNIX File System (UFS)(> mkdir testdir ; link count, leaf vs. intermediate dirs)
36
Hard Link v.s. Soft Link• Hard Link
– Cannot link to different mounted file system. – is a different name for the same set of data blocks.– Only superuser can create a link to a directory.
• Soft Link (or Symbolic link)– Can be a directory or file– Is a pointer to a set of data blocks. – File type is S_IFLINK
• What’s the difference on their i-nodes?
37
Hard vs. Soft Links• Hard Link
– Each directory entry creates a hard link of a filename to the i-node that describes the file’s contents.
– Normally require that link & file on the same file system
• Symbolic Link (Soft Link)– It is implemented as a file
that contains a pathname.– Filesize = pathname length– Example: Shortcut on
Windows– Get around with filesystem li
mitation & linking dirs
foo
bar
/usr/joe
/usr/sueFile i-node:
#Reference = 2
foo
bar
/usr/sue
File i-node:#Reference = 1
/usr/joe
File i-node:#Reference = 1
data block:“ /usr/joe/foo”
38
Hard vs. Soft Links• Problems with links
– Infinite loops– Dangling pointers– Unable to remove
foo
bar
/usr/joe
/usr/sueFile i-node:
Reference = 2
foo
bar
/usr/sue
File i-node:Reference = 1
/usr/joe
File i-node:Reference = 1
data block:“ /usr/joe/foo”
39
Symbolic Links: infinite loops
> mkdir foo> touch foo/a> ln –s ../foo foo/testdir> ls –l foo> ls –R • List subdirectories recursive
ly
foofoo/afoo/testdirfoo/testdir/?
foo
a testdir
40
BSD UNIX File System (UFS)(> mv testdir testdir2 -> only update inode)
41
Functions – link, unlink, rename, remove
#include <unistd.h>int link(const char *existingpath, const char *newpath);int unlink(const char *pathname);
– Atomic action for link – hard link• POSIX.1 allows linking across filesystems• Only superusers could create a link to a dir
– Error if newpath exists– Unlink – WX right at the residing dir
• Remove the dir entry & delete the file if link count reaches zero and no one still opens the file (Remark: sticky bit & dir rights).
42
Functions – link, unlink, rename, remove
• Program 4.16 – Page 110– Open & unlink a file
#include "apue.h"#include <fcntl.h>
intmain(void){
if (open("tempfile", O_RDWR) < 0)err_sys("open error");
if (unlink("tempfile") < 0)err_sys("unlink error");
printf("file unlinked\n");sleep(15);printf("done\n");exit(0);
}
43
Functions – link, unlink, rename, remove
• Unlink a file– Sticky bits set for a residing dir, we must have
the write permission for the directory and either owner of the file, the dir, or super users.
– If pathname is a symbolic link, unlink references the symbolic link.
44
Functions – link, unlink, rename, remove
#include <stdio.h>int remove(const char *pathname);int rename(const char *oldname, const char *newname);
– remove = rmdir if pathname is a dir. (ANSI C)– Rename – ANSI C
• File: both files, newname is removed first, WX permission for both residing directories
• Directory: both dir, newname must be empty, newname could not contain oldname.
– > rename /usr/foo /usr/foo/testdir ???
45
Symbolic Links
#include <unistd.h>int symlink(const char *actualpath, const char *s
ympath);int readlink(const char *pathname, char *buf, int
bufsize);– actualpath does not need to exist!
• They do not need to be in the same file system.– readlink is an action consisting of open, read, and c
lose – not null terminated.
46
File Times
• Three Time Fields:
• Changing the access permissions, user ID, link count, etc, only affects the i-node!
• ctime is modified automatically! (stat, access)• Example: reading/writing a file only affects the file, instead of th
e residing dir (Fig4.13).
Field Description Example ls-optionst_atime last-access-time Read -u
st_mtime last-modification-time Write default
st_ctime last-i-node-change-time chmod, chown -c
47
File Times
#include <sys/types.h>#include <utime.h>int utime(const char *pathname, const struct uti
mbuf *times);– time values are in seconds since the Epoch– times = null set as the current time
• Effective UID = file UID or W right to the file– times != null set as requested
• Effective UID = (file UID or superuser) and W right to the file.
– Program 4.21
struct utimbuf { time_t actime; time_t modtime; }
48
#include "apue.h"#include <fcntl.h>#include <utime.h>
Int main(int argc, char *argv[]){
int i, fd;struct stat statbuf;struct utimbuf timebuf;
for (i = 1; i < argc; i++) {if (stat(argv[i], &statbuf) < 0) { /* fetch curr
ent times */err_ret("%s: stat error", argv[i]);continue;
}if ((fd = open(argv[i], O_RDWR | O_TRUNC)) <
0) { /* truncate */err_ret("%s: open error", argv[i]);continue;
}close(fd);timebuf.actime = statbuf.st_atime;timebuf.modtime = statbuf.st_mtime;if (utime(argv[i], &timebuf) < 0) { /
* reset times */err_ret("%s: utime error", argv[i]);continue;
}}exit(0);
}
• Change: atime, mtime, ctime?
> ls -l changemod -rw-r--r-- 1 hchu professor 0 Apr 12 00:35
changemod
> ls -lu changemod-rw-r--r-- 1 hchu professor 0 Apr 12 00:36
changemod
> dateWed Apr 12 00:40:55 CST 2006
> ./fig4.21.exe changemod
> ls -l changemod-rw-r--r-- 1 hchu professor 0 Apr 12 00:35
changemod
> ls -lu changemod-rw-r--r-- 1 hchu professor 0 Apr 12 00:36
changemod
> ls -lc changemod-rw-r--r-- 1 hchu professor 0 Apr 12 00:41
changemod
49
Functions – mkdir and rmdir#include <sys/types.h>#include <sys/stat.h>int mkdir(const char *pathname, mode_t mode);
– umask, UID/GID setup (Sec 4.6)– From 4.2BSD & SVR3 (SVR4 – inheritance of the S_ISGI
D bit)#include <unistd.h>int rmdir(const char *pathname);
– An empty dir is deleted.– Link count reaches zero, and no one still opens the di
r.
50
Functions – opendir, readdir, rewinddir, closedir
#include <sys/types.h>#include <dirent.h>DIR *opendir(const char *pathname);struct dirent *readdir(DIR *dp); void rewinddir(DIR *dp); int closedir(DIR *dp);
– Only the kernel can write to a dir!!!– WX for creating/deleting a file!– Implementation-dependent!
51
Functions – opendir, readdir, rewinddir, closedir
• dirent struct is very implementation-dependent, e.g.,struct dirent {
ino_t d_ino; /* not in POSIX.1 */char d_name[NAME_MAX+1];
} /* fpathconf() */
• Program 4.22: traverse a file hierarchy and count # of files for each file type
52
#include "apue.h"#include <dirent.h>#include <limits.h>
/* function type that is called for each filename */typedef int Myfunc(const char *, const
struct stat *, int);
static Myfunc myfunc;static int myftw(char *, Myfunc *);static int dopath(Myfunc *);
static long nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot;
intmain(int argc, char *argv[]){
int ret;
if (argc != 2)err_quit("usage: ftw <starting-pathnam
e>");
ret = myftw(argv[1], myfunc); /* does it all */
ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock;if (ntot == 0)
ntot = 1; /* avoid divide by 0; print 0 for all counts */printf("regular files = %7ld, %5.2f %%\n", nreg, nreg*100.0/ntot);
printf("directories = %7ld, %5.2f %%\n", ndir, ndir*100.0/ntot);printf("block special = %7ld, %5.2f %%\n", nblk, nblk*100.0/ntot);printf("char special = %7ld, %5.2f %%\n", nchr, nchr*100.0/ntot);printf("FIFOs = %7ld, %5.2f %%\n", nfifo, nfifo*100.0/ntot);printf("symbolic links = %7ld, %5.2f %%\n", nslink, nslink*100.0/ntot);printf("sockets = %7ld, %5.2f %%\n", nsock, nsock*100.0/ntot);
exit(ret);}
53
/* * Descend through the hierarchy, starting at "pathnam
e". * The caller's func() is called for every file. */#define FTW_F 1
/* file other than directory */#define FTW_D 2
/* directory */#define FTW_DNR 3
/* directory that can't be read */#define FTW_NS 4
/* file that we can't stat */
static char *fullpath; /* contains full pathname for every file */
static int/* we return whatever fu
nc() returns */myftw(char *pathname, Myfunc *func){
int len;fullpath = path_alloc(&len); /* malloc's for PATH_MAX+1 bytes */
/* ({Prog pathalloc}) */strncpy(fullpath, pathname, len); /* protect against */fullpath[len-1] = 0;
/* buffer overrun */
return(dopath(func));}
54
/* * Descend through the hierarchy, starting at "fullpath". * If "fullpath" is anything other than a directory, we lsta
t() it, * call func(), and return. For a directory, we call ourself * recursively for each name in the directory. */static int
/* we return whatever func() returns */
dopath(Myfunc* func){
struct stat statbuf;struct dirent *dirp;DIR
*dp;int
ret;char *ptr;
if (lstat(fullpath, &statbuf) < 0) /* stat error */
return(func(fullpath, &statbuf, FTW_NS));if (S_ISDIR(statbuf.st_mode) == 0) /* not a directory */
return(func(fullpath, &statbuf, FTW_F));
/* * It's a directory. First call func() for the directory, * then process each filename in the directory. */if ((ret = func(fullpath, &statbuf, FTW_D)) != 0)
return(ret);
ptr = fullpath + strlen(fullpath); /* point to end of fullpath */*ptr++ = '/';*ptr = 0;
if ((dp = opendir(fullpath)) == NULL) /* can't read directory */
return(func(fullpath, &statbuf, FTW_DNR));
while ((dirp = readdir(dp)) != NULL) {if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
continue; /* ignore dot and dot-dot */
strcpy(ptr, dirp->d_name); /* append name after slash */
if ((ret = dopath(func)) != 0) /* recursive */
break; /* time to leave */}ptr[-1] = 0; /* erase everything from slash onwards */
if (closedir(dp) < 0)err_ret("can't close directory %s", fu
llpath);
return(ret);}
55
static intmyfunc(const char *pathname, const struct st
at *statptr, int type){
switch (type) {case FTW_F:
switch (statptr->st_mode & S_IFMT) {
case S_IFREG: nreg++;break;
case S_IFBLK: nblk++;break;
case S_IFCHR: nchr++;break;
case S_IFIFO: nfifo++;break;case S_IFLNK: nslink++;break;case S_IFSOCK: nsock++;break;case S_IFDIR:
err_dump("for S_IFDIR for %s",
pathname);
/* directories should have type = FTW_D */
}break;
case FTW_D:ndir++;break;
case FTW_DNR:err_ret("can't read directory %
s", pathname);break;
case FTW_NS:err_ret("stat error for %s", pat
hname);break;
default:err_dump("unknown type %d f
or pathname %s", type, pathname);}
return(0);}
56
Functions – chdir, fchdir, getcwd
#include <unistd.h>int chdir(const char *pathname);int fchdir(int filedes);
– Every process has its own current working directory– Per-process attribute – working dir!– chdir must be built into shells (pwd)!– The kernel only maintains the i-node number and dev ID for t
he current working directory!• Program 4.23
57
#include "apue.h"
intmain(void){
if (chdir("/tmp") < 0)err_sys("chdir failed");
printf("chdir to /tmp succeeded\n");exit(0);
}
> pwd/usr/lib> mycd>chdir to /tmp succeeded> pwd?
58
Functions – chdir, fchdir, getcwd
#include <unistd.h>char *getcwd(char *buf, size_t size);
– The buffer must be large enough, or an error returns!
– chdir follows symbolic links, and getcwd has not idea of symbolic links!
• Program 4.24 – getcwd
59
Special Device Files
• Device Number – dev_t– Major and minor numbers: 8 bit each under 4.3+BSD– macro definition <sysmacros.h> @ntucsa#define L_BITSMINOR 18 /* # of SVR4 minor device bits */#define L_MAXMAJ 0x3fff /* SVR4 max major value */#define major(x) (int)((unsigned)((x)>>O_BITSMINOR) & O_MAXMAJ)
• Program 4.25– st_dev vs st_rdev
60
Major Number vs. Minor Number
Driver
Controller 1Major #1
Controller 2Major #2
Controller 3Major #3
Device 1Minor #1
Device 2Minor #2
Device 1Minor #1
Device 2Minor #2
Device 1Minor #1
Device 2Minor #2
USB Controller
USB KB USB Cam
61
#include "apue.h"#ifdef SOLARIS#include <sys/mkdev.h>#endif
intmain(int argc, char *argv[]){
int i;struct stat buf;
for (i = 1; i < argc; i++) {printf("%s: ", argv[i]);if (stat(argv[i], &buf) < 0) {
err_ret("stat error");continue;
}
printf("dev = %d/%d", major(buf.st_dev), minor(buf.st_dev));
if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) {printf(" (%s) rdev = %d/%d",
(S_ISCHR(buf.st_mode)) ? "character" : "block",major(buf.st_rdev), minor(buf.st_rdev));
}printf("\n");
}
exit(0);}