C4 文件和目录:APUE 笔记

C4: 文件和目录

  本章主要讨论stat函数及其返回信息,通过修改stat结构字段,了解文件属性。

  struct stat结构定义如下:

 1 struct stat
 2   {
 3     __dev_t st_dev;        /* Device.  */
 4 #ifndef __x86_64__
 5     unsigned short int __pad1;
 6 #endif
 7 #if defined __x86_64__ || !defined __USE_FILE_OFFSET64
 8     __ino_t st_ino;        /* File serial number.    */
 9 #else
10     __ino_t __st_ino;            /* 32bit file serial number.    */
11 #endif
12 #ifndef __x86_64__
13     __mode_t st_mode;            /* File mode.  */
14     __nlink_t st_nlink;            /* Link count.  */
15 #else
16     __nlink_t st_nlink;        /* Link count.  */
17     __mode_t st_mode;        /* File mode.  */
18 #endif
19     __uid_t st_uid;        /* User ID of the file's owner.    */
20     __gid_t st_gid;        /* Group ID of the file's group.*/
21 #ifdef __x86_64__
22     int __pad0;
23 #endif
24     __dev_t st_rdev;        /* Device number, if device.  */
25 #ifndef __x86_64__
26     unsigned short int __pad2;
27 #endif
28 #if defined __x86_64__ || !defined __USE_FILE_OFFSET64
29     __off_t st_size;            /* Size of file, in bytes.  */
30 #else
31     __off64_t st_size;            /* Size of file, in bytes.  */
32 #endif
33     __blksize_t st_blksize;    /* Optimal block size for I/O.  */
34 #if defined __x86_64__  || !defined __USE_FILE_OFFSET64
35     __blkcnt_t st_blocks;        /* Number 512-byte blocks allocated. */
36 #else
37     __blkcnt64_t st_blocks;        /* Number 512-byte blocks allocated. */
38 #endif
39 #ifdef __USE_XOPEN2K8
40     /* Nanosecond resolution timestamps are stored in a format
41        equivalent to 'struct timespec'.  This is the type used
42        whenever possible but the Unix namespace rules do not allow the
43        identifier 'timespec' to appear in the <sys/stat.h> header.
44        Therefore we have to handle the use of this header in strictly
45        standard-compliant sources special.  */
46     struct timespec st_atim;        /* Time of last access.  */
47     struct timespec st_mtim;        /* Time of last modification.  */
48     struct timespec st_ctim;        /* Time of last status change.  */
49 # define st_atime st_atim.tv_sec    /* Backward compatibility.  */
50 # define st_mtime st_mtim.tv_sec
51 # define st_ctime st_ctim.tv_sec
52 #else
53     __time_t st_atime;            /* Time of last access.  */
54     __syscall_ulong_t st_atimensec;    /* Nscecs of last access.  */
55     __time_t st_mtime;            /* Time of last modification.  */
56     __syscall_ulong_t st_mtimensec;    /* Nsecs of last modification.  */
57     __time_t st_ctime;            /* Time of last status change.  */
58     __syscall_ulong_t st_ctimensec;    /* Nsecs of last status change.  */
59 #endif
60 #ifdef __x86_64__
61     __syscall_slong_t __glibc_reserved[3];
62 #else
63 # ifndef __USE_FILE_OFFSET64
64     unsigned long int __glibc_reserved4;
65     unsigned long int __glibc_reserved5;
66 # else
67     __ino64_t st_ino;            /* File serial number.    */
68 # endif
69 #endif
70   };

 1 函数stat、fstat、fstatat、lstat

  获取文件属性,头文件 sys/stat.h。成功返回0,失败返回-1。

 1 /* Get file attributes for FILE and put them in BUF.  */
 2 extern int stat (const char *__restrict __file,
 3          struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
 4 
 5 /* Get file attributes for the file, device, pipe, or socket
 6    that file descriptor FD is open on and put them in BUF.  */
 7 extern int fstat (int __fd, struct stat *__buf) __THROW __nonnull ((2));
 8 
 9 /* Get file attributes about FILE and put them in BUF.
10    If FILE is a symbolic link, do not follow it.  */
11 extern int lstat (const char *__restrict __file,
12           struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
13 
14 /* Similar to stat, get the attributes for FILE and put them in BUF.
15    Relative path names are interpreted relative to FD unless FD is
16    AT_FDCWD.  */
17 # ifndef __USE_FILE_OFFSET64
18 extern int fstatat (int __fd, const char *__restrict __file,
19             struct stat *__restrict __buf, int __flag)
20      __THROW __nonnull ((2, 3));

 

  以上4个函数区别:

  •   stat返回文件名相关的文件属性
  •   fstat返回文件描述符相关的文件属性
  •   lastat与符号链接有关,如果输入参数文件名是一个文件链接,则返回符号链接的信息,而非文件信息
  •   fstatat为相对一个打开目录,flag参数控制是否跟随一个符号链接

2 文件类型

  对应stat结构的字段 __mode_t  st_mode; /* File mode. */

  UNIX的文件类型有以下几种:

类型  类型识别宏 释义
普通文件 S_ISREG() 文本或者二进制文件
目录文件 S_ISDIR() 目录
块特殊文件 S_ISBLK() 此类型文件提供对设备带缓冲的访问
字符特殊文件 S_ISCHR() 此类型文件提供对设备不带缓冲的访问
FIFO S_ISFIFO() 进程间通信,也称管道
套接字 S_ISSOCK() 网络通信
符号链接 S_ISLINK() 此类型文件指向另一个文件

  用法为S_ISREG(stat.st_mode)

 3 设置用户ID和组ID

  注意,此为进程属性。

  通常,进程的有效用户ID就是实际用户ID,有效组ID就是实际组ID。stat中的两个ID是文件拥有者ID和组ID

  19 __uid_t st_uid; /* User ID of the file's owner. */

  20 __gid_t st_gid; /* Group ID of the file's group.*/

4 文件访问权限

   stat结构的st_mode也包含了文件的访问权限。文件都有9个访问权限位,stat.h中定义为9个宏,如下图:

  上图前3行,用户指文件所有者。用u表示用户,g表示组,o表示其他,与chmod命令保持一致。

  文件权限规则:

  •   执行权限:名字路径中的任一目录,包括它可能隐含的当前工作目录都应有执行权限。其中,目录读权限指的是访问目录内容(读目录文件列表),目录执行权限指的是搜索(通过该目录)
  •   读权限:是否能够打开文件进行读操作
  •   写权限:是否能够打开文件进行写操作。如果open中对一个文件制定O_TRUNK,则必须对该文件具有写权限
  •   如需创建一个新文件,则必须对文件所在目录具有写权限和执行权限
  •   如需删除一个文件,则必须对文件所在目录具有写权限和执行权限,对文件本身不需要有读写权限

  文件有拥有者ID  st_uid和拥有者组ID st_gid,此为文件属性。

  进程有有效ID和组ID。

  访问文件时,两组ID进行判断,觉得进程是否拥有文件使用权。规则为:

  •   若进程的有效用户ID是0(超级用户),则允许访问
  •   若进程的有效ID等于文件所有者ID,则允许访问
  •   若进程的组ID等于文件所有者组ID,则允许访问
  •   其他用户的访问权限位被设置,则允许访问,否则拒绝

  创建新文件时

  •   新文件的用户ID设置为进程有效用户ID
  •   新文件的组ID可以设置为进程的有效组ID,或者是所在目录的组ID,依赖系统

5 函数access和faccessat

  按照进程实际用户ID和实际组ID进行访问权限测试文件权限,头文件 unistd.h。成功返回0,失败返回-1

1 /* Test for access to NAME using the real UID and real GID.  */
2 extern int access (const char *__name, int __type) __THROW __nonnull ((1));
3 
4 /* Test for access to FILE relative to the directory FD is open on.
5    If AT_EACCESS is set in FLAG, then use effective IDs like `eaccess',
6    otherwise use real IDs like `access'.  */
7 extern int faccessat (int __fd, const char *__file, int __type, int __flag)

   操作类型为:

操作类型 说明
F_OK 测试文件是否存在
R_OK 测试读权限
W_OK 测试写权限
X_OK 测试执行权限

  faccessat函数,如果flag设置为AT_EACCESS,访问检查用的是调用有效用户ID和有效组ID,而不是实际用户ID和实际组ID。

6 函数umask

  为进程设置文件模式创建屏蔽字,并返回之前的值。头文件sys/stat.h,返回之前的文件屏蔽字

1 /* Set the file creation mask of the current process to MASK,
2    and return the old creation mask.  */
3 
4 extern __mode_t umask (__mode_t __mask) __THROW;

 

  参数mask为表4-4按位或运算得来。

7 函数chmod、fchmod、fchmodat

  更改现有文件的访问权限,头文件sys/stat.h。成功返回0,失败返回-1。

 1 /* Set file access permissions for FILE to MODE.
 2    If FILE is a symbolic link, this affects its target instead.  */
 3 extern int chmod (const char *__file, __mode_t __mode)
 4      __THROW __nonnull ((1));
 5 
 6 /* Set file access permissions of the file FD is open on to MODE.  */
 7 #if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED
 8 extern int fchmod (int __fd, __mode_t __mode) __THROW;
 9 #endif
10 
11 /* Set file access permissions of FILE relative to
12    the directory FD is open on.  */
13 extern int fchmodat (int __fd, const char *__file, __mode_t __mode,
14              int __flag)
15      __THROW __nonnull ((2)) __wur;

 

  参数mode是下图所示常量的按位或。

8 函数chown、fchown、fchownat、lchown

  用于改变文件的用户ID和组ID,头文件 unistd.h。成功返回0,失败返回-1。

 1 /* Change the owner and group of FILE.  */
 2 extern int chown (const char *__file, __uid_t __owner, __gid_t __group)
 3      __THROW __nonnull ((1)) __wur;
 4 
 5 /* Change the owner and group of the file that FD is open on.  */
 6 extern int fchown (int __fd, __uid_t __owner, __gid_t __group) __THROW __wur;
 7 
 8 /* Change the owner and group of FILE relative to the directory FD is open
 9    on.  */
10 extern int fchownat (int __fd, const char *__file, __uid_t __owner,
11              __gid_t __group, int __flag)
12      __THROW __nonnull ((2)) __wur;
13 
14 /* Change owner and group of FILE, if it is a symbolic
15    link the ownership of the symbolic link is changed.  */
16 extern int lchown (const char *__file, __uid_t __owner, __gid_t __group)
17      __THROW __nonnull ((1)) __wur;

 

  如果两个参数中任意一个是-1,则对于ID不变。

9 文件长度

  stat结构成员st_size表示以字节为单位的文件长度,此字段对普通文件、目录文件、符号链接有效。

10 函数truncate文件截断

  可以改变文件长度,头文件unistd.h。成功返回0,失败返回-1。

1 /* Truncate FILE to LENGTH bytes.  */
2 # ifndef __USE_FILE_OFFSET64
3 extern int truncate (const char *__file, __off_t __length)
4      __THROW __nonnull ((1)) __wur;

 

11 函数link、linkat、unlink、unlinkat、remove

  创建一个指向现有文件i节点的链接,头文件unistd.h。成功返回0,失败返回-1。

  这种链接方式,直接指向文件i节点,使得文件i节点上的链接计数__nlink_t st_nlink; /* Link count. */增加。

1 /* Make a link to FROM named TO.  */
2 extern int link (const char *__from, const char *__to) __THROW __nonnull ((1, 2)) __wur;
3 
4 /* Like link but relative paths in TO and FROM are interpreted relative
5    to FROMFD and TOFD respectively.  */
6 extern int linkat (int __fromfd, const char *__from, int __tofd, const char *__to, int __flags)
7      __THROW __nonnull ((2, 4)) __wu  

   unlink可以删除一个现有目录项,将所引文件的链接计数减1。成功返回0,失败返回-1。

1 /* Remove the link NAME.  */
2 extern int unlink (const char *__name) __THROW __nonnull ((1));
3 
4 /* Remove the link NAME relative to FD.  */
5 extern int unlinkat (int __fd, const char *__name, int __flag)
6      __THROW __nonnull ((2));

   只有文件的链接计数达到0,文件的内容才可以被删除。

  如果unlinkat的参数flag被设置为AT_REMOVEDIR时,unlinkat函数可以类似rmdir一样删除目录。

  remove函数解除对一个文件或者目录的链接,头文件stdio.h。成功返回0,失败返回-1。

  对于文件,remove的功能与unlink类似。对于目录,remove的功能与rmdir类似。

1 /* Remove file FILENAME.  */
2 
3 extern int remove (const char *__filename) __THROW;

  open\creat创建新临时文件后,立即调用unlink,可以保证临时文件在程序奔溃时也可以被删除。

12 函数rename、renameat

  rename、renameat可用于对文件或者目录重命名,头文件stdio.h。成功返回0,失败返回-1。

1 /* Rename file OLD to NEW.  */
2 extern int rename (const char *__old, const char *__new) __THROW;
3 
4 /* Rename file OLD relative to OLDFD to NEW relative to NEWFD.  */
5 extern int renameat (int __oldfd, const char *__old, int __newfd,   const char *__new) __THROW;

 

13 符号链接

  符号链接比i节点的链接更加灵活,有以下两个原因:

  •  i节点链接通常要求链接和文件在同一文件系统
  •  通常只有超级用户才能创建i节点的链接   

  可以用symlink或symlinkat函数创建一个符号链接,头文件unistd.h。成功返回0,失败返回-1。

1 /* Make a symbolic link to FROM named TO.  */
2 extern int symlink (const char *__from, const char *__to)
3      __THROW __nonnull ((1, 2)) __wur;
4 
5 /* Like symlink but a relative path in TO is interpreted relative to TOFD.  */
6 extern int symlinkat (const char *__from, int __tofd,
7               const char *__to) __THROW __nonnull ((1, 3)) __wur;

 

  函数创建一个指向from文件路径的新目录项to。

  由于open方法访问符号链接时,将访问到符号链接引用的文件。为了访问符号链接本身,需要使用readlink和readlinkat函数,头文件unistd.h。成功返回读取的字节数,失败返回-1。

 1 /* Read the contents of the symbolic link PATH into no more than
 2    LEN bytes of BUF.  The contents are not null-terminated.
 3    Returns the number of characters read, or -1 for errors.  */
 4 extern ssize_t readlink (const char *__restrict __path,
 5              char *__restrict __buf, size_t __len)
 6      __THROW __nonnull ((1, 2)) __wur;
 7 
 8 /* Like readlink but a relative PATH is interpreted relative to FD.  */
 9 extern ssize_t readlinkat (int __fd, const char *__restrict __path,
10                char *__restrict __buf, size_t __len)
11      __THROW __nonnull ((2, 3)) __wur;

 

 

14 文件时间

  stat结构有3个时间:

  • struct timespec st_atim; /* Time of last access. */            文件访问时间
  • struct timespec st_mtim; /* Time of last modification. */   文件修改时间,指的是文件内容被修改
  • struct timespec st_ctim; /* Time of last status change. */    i节点状态变更时间,节点最后修改时间,如访问权限、用户ID、链接数等

  文件访问时间和修改时间可以用futimens和utimensat函数更改,头文件sys/stat.h。成功返回0,失败返回-1。

1 /* Set file access and modification times of the file associated with FD.  */
2 extern int futimens (int __fd, const struct timespec __times[2]) __THROW;
3 
4 /* Set file access and modification times relative to directory file
5    descriptor.  */
6 extern int utimensat (int __fd, const char *__path, const struct timespec __times[2], int __flags) __THROW __nonnull ((2));

 

  timespec结构定义为:

1 struct timespec
2 {
3   __time_t tv_sec;        /* Seconds.  */
4   __syscall_slong_t tv_nsec;    /* Nanoseconds.  */
5 };

 

  函数futimens数组参数的第一个元素包含访问时间,第二个参数包含修改时间。

  •   如果times是空指针,则设置访问时间和修改时间为当前时间
  •   如果times数组的任一元素tv_nsec为UTIME_NOW,则忽略tv_sec字段,时间戳设置为当前时间
  •   如果times数组的任一元素tv_nsec为UTIME_OMIT,则忽略tv_sec字段,时间戳保持不变
  •   如果times数组的任一元素tv_nsec不是UTIME_OMIT和TIME_NOW,则设置时间戳为tv_sec和tv_nsec

 

15 目录操作:创建、删除、读取、切换

  使用函数mkdir、mkdirat、rmdir可以创建或者删除目录,头文件sys/stat.h。成功返回0,失败返回-1。

 1 /* Create a new directory named PATH, with permission bits MODE.  */
 2 extern int mkdir (const char *__path, __mode_t __mode)
 3      __THROW __nonnull ((1));
 4 
 5 /* Like mkdir, create a new directory with permission bits MODE.  But
 6    interpret relative PATH names relative to the directory associated
 7    with FD.  */
 8 extern int mkdirat (int __fd, const char *__path, __mode_t __mode)
 9      __THROW __nonnull ((2));
10 
11 /* Remove the directory PATH.  */
12 extern int rmdir (const char *__path) __THROW __nonnull ((1));

 

  注意:

  •   创建目录至少应该指定一个执行权限位
  •   rmdir只能删除空目录

  对某一目录具有访问权限的任一用户都可以读目录,但是只有内核才可以写目录。目录操作头文件dirent.h。

 1 /* Open a directory stream on NAME.
 2    Return a DIR stream on the directory, or NULL if it could not be opened.
 3    This function is a possible cancellation point and therefore not
 4    marked with __THROW.  */
 5 extern DIR *opendir (const char *__name) __nonnull ((1));
 6 
 7 
 8 /* Same as opendir, but open the stream on the file descriptor FD.
 9    This function is a possible cancellation point and therefore not
10    marked with __THROW.  */
11 extern DIR *fdopendir (int __fd);
12 
13 
14 /* Read a directory entry from DIRP.  Return a pointer to a `struct
15    dirent' describing the entry, or NULL for EOF or error.  The
16    storage returned may be overwritten by a later readdir call on the
17    same DIR stream.
18    If the Large File Support API is selected we have to use the
19    appropriate interface.
20    This function is a possible cancellation point and therefore not
21    marked with __THROW.  */
22 extern struct dirent *readdir (DIR *__dirp) __nonnull ((1));
23 
24 
25 /* Rewind DIRP to the beginning of the directory.  */
26 extern void rewinddir (DIR *__dirp) __THROW __nonnull ((1));
27 
28 
29 /* Close the directory stream DIRP.
30    Return 0 if successful, -1 if not.
31    This function is a possible cancellation point and therefore not
32    marked with __THROW.  */
33 extern int closedir (DIR *__dirp) __nonnull ((1));
34 
35 
36 /* Return the current position of DIRP.  */
37 extern long int telldir (DIR *__dirp) __THROW __nonnull ((1));
38 
39 
40 /* Seek to position POS on DIRP.  */
41 extern void seekdir (DIR *__dirp, long int __pos) __THROW __nonnull ((1));

 

  每个进程都有一个初始工作目录。起始目录是登录名的属性,而当前工作目录是进程的属性。

  使用chdir可以切换当前工作目录,头文件unistd.h。成功返回0,失败返回-1。

1 /* Change the process's working directory to PATH.  */
2 extern int chdir (const char *__path) __THROW __nonnull ((1)) __wur;
3 
4 /* Change the process's working directory to the one FD is open on.  */
5 extern int fchdir (int __fd) __THROW __wur;

 

  使用getcwd可以获取当前工作目录,头文件unistd.h。成功返回0,失败返回-1。

1 /* Get the pathname of the current working directory,
2    and put it in SIZE bytes of BUF.  Returns NULL if the
3    directory couldn't be determined or SIZE was too small.
4    If successful, returns BUF.  In GNU, if BUF is NULL,
5    an array is allocated with `malloc'; the array is SIZE
6    bytes long, unless SIZE == 0, in which case it is as
7    big as necessary.  */
8 extern char *getcwd (char *__buf, size_t __size) __THROW __wur;

 

posted on 2018-09-10 10:52  炽离  阅读(444)  评论(0编辑  收藏  举报

导航