4.17. symlink and readlink Functions
#include <unistd.h> int symlink(const char *actualpath, const char *sympath); A new directory entry, sympath, is created that points to actualpath. It is not required that actualpath exist when the symbolic link is created. Also, actualpath and sympath need not reside in the same file system. #include <unistd.h> ssize_t readlink(const char* restrict pathname, char *restrict buf, size_t bufsize); 如果读取readlink成功,buf里保存着link里的内容,返回link的长度。(注意:不是以0结尾)
4.18. File Times
Three time fields are maintained for each file.
Field | Description | Example | ls(1) option |
---|---|---|---|
st_atime | last-access time of file data | read | -u |
st_mtime | last-modification time of file data | write | default |
st_ctime | last-change time of i-node status | chmod, chown | -c |
Note that the system does not maintain the last-access time for an i-node. This is why the functions access and stat, for example, don't change any of the three times.
4.19. utime Function
The access time and the modification time of a file can be changed with the utime function.
#include <utime.h> int utime(const char *pathname, const struct utimbuf *times); struct utimbuf { time_t actime; /* access time */ time_t modtime; /* modification time */ } If times is a null pointer, the access time and the modification time are both set to the current time. 当需要真正设置时间时,必须有root权限,只拥有文件的权限是不够的。
4.20. mkdir and rmdir Functions
#include <sys/stat.h> int mkdir(const char *pathname, mode_t mode); The user ID of a new file is set to the effective user ID of the process. The group ID of a new file can be the effective group ID of the process. The group ID of a new file can be the group ID of the directory in which the file is being created. Solaris 9 and Linux 2.4.22 also have the new directory inherit the set-group-ID bit from the parent directory. #include <unistd.h> int rmdir(const char *pathname); An empty directory is deleted with the rmdir function.
4.21. Reading Directories
#include <dirent.h> DIR *opendir(const char *pathname); struct dirent *readdir(DIR *dp); void rewinddir(DIR *dp); int closedir(DIR *dp); long telldir(DIR *dp); void seekdir(DIR *dp, long loc); struct dirent { ino_t d_ino; /* i-node number */ char d_name[NAME_MAX + 1]; /* null-terminated filename */ } ?figure 4.21
4.22. chdir, fchdir, and getcwd Functions
#include <unistd.h> int chdir(const char *pathname); int fchdir(int filedes); #include <unistd.h> char *getcwd(char *buf, size_t size); 返回的字符串以NULL结束
4.23. Device Special Files
The two fields st_dev and st_rdev are often confused.
?
4.24. Summary of File Access Permission Bits
Constant | Description | Effect on regular file | Effect on directory |
---|---|---|---|
S_ISUID | set-user-ID | set effective user ID on execution | (not used) |
S_ISGID | set-group-ID | if group-execute set then set effective group ID on execution; otherwise enable mandatory record locking (if supported) | set group ID of new files created in directory to group ID of directory |
S_ISVTX | sticky bit | control caching of file contents (if supported) | restrict removal and renaming of files in directory |
S_IRUSR | user-read | user permission to read file | user permission to read directory entries |
S_IWUSR | user-write | user permission to write file | user permission to remove and create files in directory |
S_IXUSR | user-execute | user permission to execute file | user permission to search for given pathname in directory |
S_IRGRP | group-read | group permission to read file | group permission to read directory entries |
S_IWGRP | group-write | group permission to write file | group permission to remove and create files in directory |
S_IXGRP | group-execute | group permission to execute file | group permission to search for given pathname in directory |
S_IROTH | other-read | other permission to read file | other permission to read directory entries |
S_IWOTH | other-write | other permission to write file | other permission to remove and create files in directory |
S_IXOTH | other-execute | other permission to execute file | other permission to search for given pathname in directory |
EXERCISE 4.14
st_atime是最后一次读的时间,st_mtime是最后一次接受新邮件的时间。
5.2. Streams and FILE Objects
#include <stdio.h> #include <wchar.h> int fwide(FILE *fp, int mode); Returns: positive if stream is wide-oriented, negative if stream is byte-oriented, or 0 if stream has no orientation
参数如果是正的,会试着设置stream为wide,如果是负的,会试着设置stream为byte,如果是0,显示现在的类型。
不会改变现在的类型。
不会返回错误,但是当失败时,errono会被设置。
5.4. Buffering
Three types of buffering are provided:
Fully buffered.
Line buffered. Line buffering is typically used on a stream when it refers to a terminal: standard input and standard output。
Unbuffered. The standard error stream, for example, is normally unbuffered.
Most implementations default to the following types of buffering.
-
Standard error is always unbuffered.
-
All other streams are line buffered if they refer to a terminal device; otherwise, they are fully buffered.
#include <stdio.h> void setbuf(FILE *restrict fp, char *restrict buf); int setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size);
These functions must be called after the stream has been opened,but before any other operation is performed on the stream.
To enable buffering, buf must point to a buffer of length BUFSIZ, a constant defined in <stdio.h>. Normally, the stream is then fully buffered, but some systems may set line buffering if the stream is associated with a terminal device. To disable buffering, we set buf to NULL.
With setvbuf, we specify exactly which type of buffering we want. This is done with the mode argument:
_IOFBF | fully buffered |
_IOLBF | line buffered |
_IONBF | unbuffered |
#include <stdio.h> int fflush(FILE *fp); 如果错误返回值为EOF。如果参数为NULL,所有的stream flush
5.5. Opening a Stream
#include <stdio.h> FILE *fopen(const char *restrict pathname, const char *restrict type); FILE *freopen(const char *restrict pathname, const char *restrict type, FILE *restrict fp); FILE *fdopen(int filedes, const char *type); fdopen用于将一些只能获得fd的文件转化为标准I/O
type | Description |
---|---|
r or rb | open for reading |
w or wb | truncate to 0 length or create for writing |
a or ab | append; open for writing at end of file, or create for writing |
r+ or r+b or rb+ | open for reading and writing |
w+ or w+b or wb+ | truncate to 0 length or create for reading and writing |
a+ or a+b or ab+ | open or create for reading and writing at end of file |
Output cannot be directly followed by input without an intervening fflush, fseek, fsetpos,or rewind.
Input cannot be directly followed by output without an intervening fseek, fsetpos,or rewind, or an input operation that encounters an end of file.
#include <stdio.h> int fclose(FILE *fp);
5.6. Reading and Writing a Stream
#include <stdio.h> int ferror(FILE *fp); int feof(FILE *fp); void clearerr(FILE *fp);
Input Functions
#include <stdio.h> int getc(FILE *fp); int fgetc(FILE *fp); int getchar(void); getc can be implemented as a macro, whereas fgetc cannot be implemented as a macro. getc is faster, unsafer. int ungetc(int c, FILE *fp); //将值放回去,最好只放回一个,可以与原值不同。 回写的c放在缓冲区中,不直接写回磁盘。
Output Functions
#include <stdio.h> int putc(int c, FILE *fp); int fputc(int c, FILE *fp); int putchar(int c);
5.7. Line-at-a-Time I/O
#include <stdio.h> char *fgets(char *restrict buf, int n, FILE *restrict fp); char *gets(char *buf); fgets 返回的buf总是以NULL结尾。不要用gets #include <stdio.h> int fputs(const char *restrict str, FILE *restrict fp); int puts(const char *str); 两者负责输出NULL结尾字符串, fputs最后会不输出换行,puts会输出换行。 建议fputs char buf[MAXLINE]; When we use the line-at-a-time functions, fgets and fputs, the data is usually copied twice: once between the kernel and the standard I/O buffer (when the corresponding read or write is issued) and again between the standard I/O buffer and our line buffer.
5.8. Standard I/O Efficiency
一般的说,选好缓冲区大小,read的效率比fgets高。但差别不大。 但fgetc和fputc比长度为1的read好。
5.9. Binary I/O
#include <stdio.h> size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp); size_t fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp); Both return: number of objects read or written The obvious generalization of these two cases is to read or write an array of structures. To do this, size would be the sizeof the structure, and nobj would be the number of elements in the array. 常用来读写结构体。
5.10. Positioning a Stream
#include <stdio.h> long ftell(FILE *fp); int fseek(FILE *fp, long offset, int whence); void rewind(FILE *fp); #include <stdio.h> off_t ftello(FILE *fp); //仅与ftell的返回值不同 int fseeko(FILE *fp, off_t offset, int whence); //仅与fseek的offset参数类型不同 #include <stdio.h> int fgetpos(FILE *restrict fp, fpos_t *restrict pos); int fsetpos(FILE *fp, const fpos_t *pos); 使用fpos_t 结构体来储存位置。
5.11. Formatted I/O
#include <stdio.h> int printf(const char *restrict format, ...); int fprintf(FILE *restrict fp, const char *restrict format, ...); int sprintf(char *restrict buf, const char *restrict format, ...); int snprintf(char *restrict buf, size_t n, const char *restrict format, ...); sprintf自动在最后加上NULL %[flags][fldwidth][precision][lenmodifier]convtype #include <stdarg.h> #include <stdio.h> int vprintf(const char *restrict format, va_list arg); int vfprintf(FILE *restrict fp, const char *restrict format, va_list arg); int vsprintf(char *restrict buf, const char *restrict format, va_list arg); int vsnprintf(char *restrict buf, size_t n, const char *restrict format, va_list arg); #include <stdio.h> int scanf(const char *restrict format, ...); int fscanf(FILE *restrict fp, const char *restrict format, ...); int sscanf(const char *restrict buf, const char *restrict format, ...); #include <stdarg.h> #include <stdio.h> int vscanf(const char *restrict format, va_list arg); int vfscanf(FILE *restrict fp, const char *restrict format, va_list arg); int vsscanf(const char *restrict buf, const char *restrict format, va_list arg);
5.12. Implementation Details
#include <stdio.h> int fileno(FILE *fp); 返回fd FILE ( _IO_file_flags; _IO_buf_base; _IO_buf_end; _IO_UNBUFFERED; _IO_LINE_BUFFERED; 。。。) 三种类型buffer大小不顾定,重定向后buffer可能改变。
5.13. Temporary Files
#include <stdio.h> char *tmpnam(char *ptr); FILE *tmpfile(void); char *tempnam(const char *directory, const char *prefix); int mkstemp(char *template); 使用tmpnam,先申请一个字符数组长度为L_tmpnam,参数为NULL时名称存储在唯一一个静态区域内。 tmpfile自动创建临时文件,返回指针。打开方式为wb+,自动删除。 Tempnam可以自定义临时文件位置和前缀 mdktemp的template以XXXXXX结尾,不自动清除,需要自己unlink。 提倡使用tmpfile和mkstemp,其他两个在返回文件名和真正创建文件时有间隙,其他可能创建同名文件。 ?
5.14. Alternatives to Standard I/O
When we use the line-at-a-time functions, fgets and fputs, the data is usually copied twice: once between the kernel and the standard I/O buffer (when the corresponding read or write is issued) and again between the standard I/O buffer and our line buffer. EXERCISE 5.6 ?fsync fflush
6.2. Password File
Description | struct passwd member |
---|---|
user name | char *pw_name |
encrypted password | char *pw_passwd(.......) |
numerical user ID | uid_t pw_uid |
numerical group ID | gid_t pw_gid |
comment field | char *pw_gecos |
initial working directory | char *pw_dir |
initial shell (user program) | char *pw_shell |
user access class | char *pw_class |
next time to change password | time_t pw_change |
account expiration time | time_t pw_expire |
Many services have separate user IDs for the daemon processes (Chapter 13) that help implement the service. The nobody user name can be used to allow people to log in to a system, but with a user ID (65534) and group ID (65534) that provide no privileges. Vipw 一个command修改passwd #include <pwd.h> struct passwd *getpwuid(uid_t uid); //根据uid返回passwd entry struct passwd *getpwnam(const char *name); //根据name返回passwd entry struct passwd *getpwent(void); //迭代返回 passwd entry void setpwent(void); //rewind void endpwent(void); //close The functions to access the shadow password file on Linux and Solaris are discussed in Section 6.3. We can't use the value returned in the pw_passwd field by the functions described in Section 6.2 to compare an encrypted password, since that field is not the encrypted password. Instead, we need to find the user's entry in the shadow file and use its encrypted password field.
6.3. Shadow Passwords
Description | struct spwd member |
---|---|
user login name | char *sp_namp |
encrypted password | char *sp_pwdp |
days since Epoch of last password change | int sp_lstchg |
days until change allowed | int sp_min |
days before change required | int sp_max |
days warning for expiration | int sp_warn |
days before account inactive | int sp_inact |
days since Epoch when account expires | int sp_expire. |
reserved | unsigned int sp_flag |
#include <shadow.h> struct spwd *getspnam(const char *name); struct spwd *getspent(void); void setspent(void); void endspent(void);
6.4. Group File
Description | struct group member |
---|---|
group name | char *gr_name |
encrypted password | char *gr_passwd |
numerical group ID | int gr_gid |
array of pointers to individual user names | char **gr_mem |
#include <grp.h> struct group *getgrgid(gid_t gid); struct group *getgrnam(const char *name); struct group *getgrent(void); void setgrent(void); void endgrent(void);
6.5. Supplementary Group IDs
#include <unistd.h> int getgroups(int gidsetsize, gid_t grouplist[]); The getgroups function fills in the array grouplist with the supplementary group IDs. Up to gidsetsize elements are stored in the array. The number of supplementary group IDs stored in the array is returned by the function. As a special case, if gidsetsize is 0, the function returns only the number of supplementary group IDs. The array grouplist is not modified. (This allows the caller to determine the size of the grouplist array to allocate.) #include <grp.h> /* on Linux */ #include <unistd.h> /* on FreeBSD, Mac OS X, and Solaris */ int setgroups(int ngroups, const gid_t grouplist[]); The setgroups function can be called by the superuser to set the supplementary group ID list for the calling process: grouplist contains the array of group IDs, and ngroups specifies the number of elements in the array. The value of ngroups cannot be larger than NGROUPS_MAX. int initgroups(const char *username, gid_t basegid);
6.7. Other Data Files
Figure 6.6. Similar routines for accessing system data files
Description | Data file | Header | Structure | Additional keyed lookup functions |
---|---|---|---|---|
passwords | /etc/passwd | <pwd.h> | passwd | getpwnam, getpwuid |
groups | /etc/group | <grp.h> | group | getgrnam, getgrgid |
shadow | /etc/shadow | <shadow.h> | spwd | getspnam |
hosts | /etc/hosts | <netdb.h> | hostent | gethostbyname, gethostbyaddr |
networks | /etc/networks | <netdb.h> | netent | getnetbyname, getnetbyaddr |
protocols | /etc/protocols | <netdb.h> | protoent | getprotobyname, getprotobynumber |
services | /etc/services | <netdb.h> | servent | getservbyname, getservbyport |
The general principle is that every data file has at least three functions:
-
A get function that reads the next record, opening the file if necessary. These functions normally return a pointer to a structure. A null pointer is returned when the end of file is reached. Most of the get functions return a pointer to a static structure, so we always have to copy it if we want to save it.
-
A set function that opens the file, if not already open, and rewinds the file. This function is used when we know we want to start again at the beginning of the file.
-
An end enTRy that closes the data file. As we mentioned earlier, we always have to call this when we're done, to close all the files.
6.8. Login Accounting
Two data files that have been provided with most UNIX systems are the utmp file, which keeps track of all the users currently logged in, and the wtmp file, which keeps track of all logins and logouts.
struct utmp { char ut_line[8]; /* tty line: "ttyh0", "ttyd0", "ttyp0", ... */ char ut_name[8]; /* login name */ long ut_time; /* seconds since Epoch */ };
6.9. System Identification
#include <sys/utsname.h> int uname(struct utsname *name); struct utsname { char sysname[]; /* name of the operating system */ char nodename[]; /* name of this node */ char release[]; /* current release of operating system */ char version[]; /* current version of this release */ char machine[]; /* name of hardware type */ };
6.10. Time and Date Routines
#include <time.h> time_t time(time_t *calptr); int gettimeofday(struct timeval *restrict tp, void *restrict tzp); tzp再不同的平台下,支持情况不同,一般为NULL struct tm *gmtime(const time_t *calptr); struct tm *localtime(const time_t *calptr); time_t mktime(struct tm *tmptr); char *asctime(const struct tm *tmptr); char *ctime(const time_t *calptr); size_t strftime(char *restrict buf, size_t maxsize, const char *restrict format, const struct tm *restrict tmptr); We mentioned that the four functions in Figure 6.8 with dashed lines were affected by the TZ environment variable: localtime, mktime, ctime, and strftime. struct timeval { time_t tv_sec; /* seconds */ long tv_usec; /* microseconds */ }; struct tm { /* a broken-down time */ int tm_sec; /* seconds after the minute: [0 - 60] */ int tm_min; /* minutes after the hour: [0 - 59] */ int tm_hour; /* hours after midnight: [0 - 23] */ int tm_mday; /* day of the month: [1 - 31] */ int tm_mon; /* months since January: [0 - 11] */ int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday: [0 - 6] */ int tm_yday; /* days since January 1: [0 - 365] */ int tm_isdst; /* daylight saving time flag: <0, 0, >0 */ };