利用系统调用 stat()、lstat()以及 fstat(),可获取与文件有关的信息,其中大部分提取自文件 i 节点。
#include   int stat(const char *pathname, struct stat *statbuf);	/* 成功返回0,失败返回-1 */ int lstat(const char *pathname, struct stat *statbuf);	/* 成功返回0,失败返回-1 */ int fstat(int fd, struct stat *statbuf);				/* 成功返回0,失败返回-1 */  以上 3 个系统调用之间仅有的区别在于对文件的描述方式不同。
系统调用 stat()和 lstat()无需对其所操作的文件本身拥有任何权限,但针对指定pathname 的父目录要有执行(搜索)权限。而只要供之以有效的文件描述符,fstat()系统调用总是成功。
stat类型结构体如下:
struct stat {     dev_t st_dev;				/* 文件驻留的设备的ID,包括设备的主、辅ID */     ino_t st_ino;				/* 文件的i节点号 */     mode_t st_mode;				/* 文件类型和文件权限,内含位掩码,低12位定义了文件权限,     最低9位分别用来表示文件属主属组以及其他用户的读、写、执行权限 */     nlink_t st_nlink;			/* 指向文件的(硬)链接数 */     uid_t st_uid;				/* 文件的属主 */     gid_t st_gid;				/* 文件的属组 */     dev_t st_rdev;				/* 设备专用文件的ID,包括设备的主、辅ID */     off_t st_size;				/* 文件从大小(字节数) */     blksize_t st_blksize;		/* 针对文件系统上文件继续I/O操作时的最优块大小 */     blkcnt_t st_blocks;			/* 分配给文件的总块数,块大小为512 字节 */     time_t st_atime;			/* 上次访问时间 */     time_t st_mtime;			/* 上次修改时间 */     time_t st_ctime;			/* 上次文件状态发生改变的时间 */ } 下表为st_mode检查文件类型的宏:
| 常量 | 测试宏 | 文件类型 | 
|---|---|---|
| S_IFREG | S_ISREG() | 常规文件 | 
| S_IFDIR | S_ISDIR() | 目录 | 
| S_IFCHR | S_ISCHR() | 字符设备 | 
| S_IFBLK | S_ISBLK() | 块设备 | 
| S_IFIFO | S_ISFIFO() | FIFO 或管道 | 
| S_IFSOCK | S_ISSOCK() | 套接字 | 
| S_IFLNK | S_ISLNK() | 符号链接 | 
程序示例:获取并解释文件的stat信息
#include  #include  #include  #include "file_perms.h" #include "tlpi_hdr.h"  static void displayStatInfo(const struct stat *sb) {     printf("File type:                "); 	     /* 判断文件类型 */     switch (sb->st_mode & S_IFMT) {     case S_IFREG:  printf("regular file\n");            break;     case S_IFDIR:  printf("directory\n");               break;     case S_IFCHR:  printf("character device\n");        break;     case S_IFBLK:  printf("block device\n");            break;     case S_IFLNK:  printf("symbolic (soft) link\n");    break;     case S_IFIFO:  printf("FIFO or pipe\n");            break;     case S_IFSOCK: printf("socket\n");                  break;     default:       printf("unknown file type?\n");      break;     }      printf("Device containing i-node: major=%ld   minor=%ld\n",                 (long) major(sb->st_dev), (long) minor(sb->st_dev));      printf("I-node number:            %ld\n", (long) sb->st_ino);      printf("Mode:                     %lo (%s)\n",             (unsigned long) sb->st_mode, filePermStr(sb->st_mode, 0));      if (sb->st_mode & (S_ISUID | S_ISGID | S_ISVTX))         printf("    special bits set:     %s%s%s\n",                 (sb->st_mode & S_ISUID) ? "set-UID " : "",                 (sb->st_mode & S_ISGID) ? "set-GID " : "",                 (sb->st_mode & S_ISVTX) ? "sticky " : "");      printf("Number of (hard) links:   %ld\n", (long) sb->st_nlink);      printf("Ownership:                UID=%ld   GID=%ld\n",             (long) sb->st_uid, (long) sb->st_gid);      if (S_ISCHR(sb->st_mode) || S_ISBLK(sb->st_mode))         printf("Device number (st_rdev):  major=%ld; minor=%ld\n",                 (long) major(sb->st_rdev), (long) minor(sb->st_rdev));      printf("File size:                %lld bytes\n", (long long) sb->st_size);     printf("Optimal I/O block size:   %ld bytes\n", (long) sb->st_blksize);     printf("512B blocks allocated:    %lld\n", (long long) sb->st_blocks);      printf("Last file access:         %s", ctime(&sb->st_atime));     printf("Last file modification:   %s", ctime(&sb->st_mtime));     printf("Last status change:       %s", ctime(&sb->st_ctime)); }  int main(int argc, char *argv[]) {     struct stat sb;     Boolean statLink;           /* True if "-l" specified (i.e., use lstat) */     int fname;                  /* Location of filename argument in argv[] */      statLink = (argc > 1) && strcmp(argv[1], "-l") == 0;                                 /* Simple parsing for "-l" */     fname = statLink ? 2 : 1;      if (fname >= argc || (argc > 1 && strcmp(argv[1], "--help") == 0))         usageErr("%s [-l] file\n"                 "        -l = use lstat() instead of stat()\n", argv[0]);      if (statLink) {         if (lstat(argv[fname], &sb) == -1)             errExit("lstat");     } else {         if (stat(argv[fname], &sb) == -1)             errExit("stat");     }      displayStatInfo(&sb);      exit(EXIT_SUCCESS); }    echo 'All operating systems provide services for programs they run'> apue chmod g+s apueTurn on set-group-ID bit; afects last status change time cat apue Afects last file access timeAll operating systems provide services for programs they run ./t_stat apue File type:				 regular file Device containing i-node: major=3	minor=11 I-node number:			 234363 Mode:					102644(rw-r--r--) 	special bits set:	 set-GID Number of (hard) links:	 7 Ownership:				UID=1000GID=100 File size:				61 bytes Optimal I/0 block size:	 4096 bytes 512B blocks allocated:	 8 Last file access:		Mon Jun 809:40:07 2011 Last file modification:	 Mon Jun 809:39:25 2011 Last status change:		Mon Jun 8 09:39:51 2011 使用 utime()或与之相关的系统调用集之一,可显式改变存储于文件 i 节点中的文件上次访问时间戳和上次修改时间戳。utime()与 utimes()之间最显著的差别在于后者可以以微秒级精度来指定时间值。解压文件时,tar(1)和 unzip(1)之类的程序会使用这些系统调用去重置文件的时间戳。
#include   int utime(const char *pathname, const struct utimbuf *buf);		/* 成功返回0,失败返回-1 */ int utimes(const char *pathname, const struct timeval tv[2]);	/* 成功返回0,失败返回-1 */  参数 pathname 用来标识欲修改时间的文件。若该参数为符号链接,则会进一步解除引用。参数 buf 既可为 NULL,也可为指向 utimbuf 结构的指针。
struct utimbuf {     time_t actime;		/* 访问时间 */     time_t modtime;		/* 修改时间 */ } utime()的运作方式则视以下两种不同情况而定。
为更改文件时间戳中的一项,可以先利用 stat()来获取两个时间,并使用其中之一来初始化 utimbuf 结构,然后再将另一时间置为期望值。下列代码演示了这一操作,将文件的上次修改时间改为与上次访问时间相同。
struct stat sb; struct utimbuf utb;  if(stat(pathname, &sb) == -1)     errExit("stat"); utb.actime = sb.st_atime; utb.modtime = sb.st_atime; if(utime(pathname, &utb) == -1)     errExit("utime"); 只要调用 utime()成功,总会将文件的上次状态更改时间置为当前时间。
futimes()和 lutimes()库函数的功能与 utimes()大同小异。前两者与后者之间的差异在于,用来指定要更改时间戳文件的参数不同。调用 lutimes()时,使用路径名来指定文件,有别于调用 utimes()的是:对于 lutimes(),若路径名指向一符号链接,则调用不会对该链接进行解引用,而是更改链接自身的时间戳。
#include   int futimes(int fd, const struct timeval tv[2]);	/* 成功返回0,失败返回-1 */ int lutimes(const char *pathname, const struct timeval tv[2]);	/* 成功返回0,失败返回-1 */  utimensat()系统调用会把由 pathname 指定文件的时间戳更新为由数组 times 指定的值。使用 futimens()库函数可更新打开文件描述符 fd 所指代文件的各个文件时间戳。
#include   /* 成功返回0,失败返回-1 */ int utimensat(int dirfd, const char *pathname, const struct timespec time[2], int flags); int futimes(int fd, const struct timespec time[2]);  若将 times 指定为 NULL,则会将以上两个文件时间戳都更新为当前时间。若 times 值为非 NULL,则会针对指定文件在 times[0]中放置新的上次访问时间,在 times[1]中放置新的上次修改时间。数组 times 所含的每一元素都是如下格式的一个结构:
struct timespec {     time_t tv_sec;     long tv_nsec; } 若有意将时间戳之一置为当前时间,则可将相应的 tv_nsec 字段指定为特殊值UTIME_NOW。若希望某一时间戳保持不变,则需把相应的 tv_nsec 字段指定为特殊值UTIME_OMIT。无论是上述哪一种情况,都将忽略相应 tv_sec 字段中的值。
flags 参数可以为 0,或者 AT_SYMLINK_NOFOLLOW,意即当 pathname 为符号链接时,不会对其解引用(也就是说,改变的是符号链接自身的时间戳)。相形之下,utimes()总是对符号链接进行解引用。
以下代码片段在将对文件的上次访问时间置为当前时间的同时,上次修改时间则保持不变。
struct timespec times[2]; time[0].tv_sec = 0; time[0].tv_nsec = UTIME_NOW; time[1].tv_sec = 0; time[1].tv_nsec = UTIME_OMIT; if(utimesat(AT_FDCWD, "myfile", times, 0) == -1)     errExit("utimesat"); 文件创建时,其用户 ID“取自”进程的有效用户 ID。而新建文件的组 ID 则“取自”进程的有效组 ID(等同于 System V 系统的默认行为),或父目录的组 ID(BSD 系统的行为)。当为项目创建目录时,需要该目录下的所有文件隶属于某一特定组,并且可为该组所有成员所访问。这时,采用后一种行为就非常实用。新建文件的组 ID 在这两者间如何取舍是由多种因素决定的,新文件所在文件系统的类型就是其中之一
系统调用 chown()、lchown()和 fchown()可用来改变文件的属主(用户 ID)和属组(组ID)。
#include   int chown(const char *pathname, uid_t owner, gid_t group); int lchown(const char *pathname, uid_t owner, gid_t group); int fchown(int fd, uid_t owner, gid_t group);  以上 3 个系统调用之间的区别类似于 stat()系统调用一族。
只有特权级进程(CAP_CHOWN)才能使用 chown()改变文件的用户 ID。非特权级进程可使用 chown()将自己所拥有文件的组 ID 改为其所从属的任一属组的 ID,前提是进程的有效用户ID 与文件的用户 ID 相匹配。特权级进程则可将文件的组 ID 修改为任意值。
【注】如果文件组的属主或属组发生了改变,那么 set-user-ID 和 set-group-ID 权限位也会随之关闭。这一安全举措是为了防止如下行为:普通用户若能打开某一可执行文件的 set-user-ID(或 set-group-ID)位,然后再设法令其为某些特权级用户(或组)所拥有,就能在执行该文件时获得特权用户身份。
改变文件的属主和属组时,如果已然屏蔽了属组的可执行权限位,或者要改变的是目录的所有权时,那么将不会屏蔽 set-group-ID 权限位。在上述两种情况下,set-group-ID 位的用途并非是去创建一个启用了 set-group-ID 的程序,因此将该位屏蔽并不可取。set-group-ID 的其他用途如下所示。
程序示例:改变文件的属主和属组
#include  #include  #include "ugid_functions.h"             /* Declarations of userIdFromName()                                            and groupIdFromName() */ #include "tlpi_hdr.h"  int main(int argc, char *argv[]) {     uid_t uid;     gid_t gid;     int j;     Boolean errFnd;      if (argc < 3 || strcmp(argv[1], "--help") == 0)         usageErr("%s owner group [file...]\n"                 "        owner or group can be '-', "                 "meaning leave unchanged\n", argv[0]);      if (strcmp(argv[1], "-") == 0) {            /* "-" ==> don't change owner */         uid = -1;     } else {                                    /* Turn user name into UID */         uid = userIdFromName(argv[1]);         if (uid == -1)             fatal("No such user (%s)", argv[1]);     }      if (strcmp(argv[2], "-") == 0) {            /* "-" ==> don't change group */         gid = -1;     } else {                                    /* Turn group name into GID */         gid = groupIdFromName(argv[2]);         if (gid == -1)             fatal("No such group (%s)", argv[2]);     }      /* Change ownership of all files named in remaining arguments */      errFnd = FALSE;     for (j = 3; j < argc; j++) {         if (chown(argv[j], uid, gid) == -1) {             errMsg("chown: %s", argv[j]);             errFnd = TRUE;         }     }      exit(errFnd ? EXIT_FAILURE : EXIT_SUCCESS); }   stat 结构中 st_mod 字段的低 12 位定义了文件权限。其中的前 3 位为专用位,分别是 set-user-ID 位、set-group-ID 位和 sticky 位(在图 15-1 中分别被标注为 U、G、T位),将在 15.4.5 节中详细介绍。其余 9 位则构成了定义权限的掩码,分别授予访问文件的各类用户。文件权限掩码分为 3 类。
可为每一类用户授予的权限如下所示。
执行 ls–l 命令,可查看文件的权限和所有权,如下所示:
vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/fileio$ ls -l seek_io -rwxr-xr-x 1 vainx vainx 21872 Jul 19 19:35 seek_io 在以上输出中,将文件权限显示为“rwxr-xr-x”(该字符串起始处的连接号“-”表明该文件属于普通文件)。在解释该字符串时,需将其一剖为三,以 3 个字符为一组,分别表示读、写、可执行权限具备与否。第一组字符用来表示文件属主的权限,在本例中,则是读、写、执行权限俱全。第二组字符用来表示属组权限,对于本例,组内用户具有读和可执行权限,但不具有写权限。最后一组字符用来表示其他用户的权限,本例中的其他用户具有读和可执行权限,但不具有写权限。
头文件
| 常量 | 其他值 | 权限位 | 
|---|---|---|
| S_ISUID | 04000 | Set-user-ID | 
| S_ISGID | 02000 | Set-group-ID | 
| S_ISVTX | 01000 | Sticky | 
| S_IRUSR | 0400 | User-read | 
| S_IWUSR | 0200 | User-write | 
| S_IXUSR | 0100 | User-execute | 
| S_IRGRP | 040 | Group-read | 
| S_IWGRP | 020 | Group-write | 
| S_IXGRP | 010 | Group-execute | 
| S_IROTH | 04 | Other-read | 
| S_IWOTH | 02 | Other-write | 
| S_IXOTH | 01 | Other-execute | 
函数 char *filePermStr(mode_t perm, int flags),会针对给定的文件权限掩码返回一个静态分配的字符串,以 ls(1)所采用的风格来表示该掩码。如果在 filePermStr()的 flag 参数中设置了 FP_SPECIAL 标志,那么返回的字符串将包括set-user-ID、set-group-ID,以及 sticky 位的设置信息,其表现形式同样会沿袭 ls(1)的风格。
目录与文件拥有相同的权限方案,只是对 3 种权限的含义另有所指。
访问文件时,需要拥有对路径名所列所有目录的执行权限。例如,想读取文件/home/mtk/x,则需拥有对目录/、/home 以及/home/mtk 的执行权限(还要有对文件 x 自身的读权限)。若当前的工作目录为/home/mtk/sub1,访问相对路径名…/sub2/x 时,需握有/home/mtk 和/home/mtk/sub2 这两个目录的可执行权限(不必有对/或/home 的执行权限)。
拥有对目录的读权限,用户只是能查看目录中的文件列表。要想访问目录内文件的内容或是这些文件的 i 节点信息,还需握有对目录的执行权限。反之,若拥有对目录的可执行权限,而无读权限,只要知道目录内文件的名称,仍可对
 其进行访问,但不能列出目录下的内容(即目录所含的其他文件名)。在控制对公共目录内容的访问时,这是一种常用技术,简单而且实用。要想在目录中添加或删除文件,需要同时拥有对该目录的执行和写权限。
只要在访问文件或目录的系统调用中指定了路径名称,内核就会检查相应文件的权限。如果赋予系统调用的路径名还包含目录前缀时,那么内核除去会检查对文件本身所需的权限以外,还会检查前缀所含每个目录的可执行权限。内核会使用进程的有效用户 ID、有效组 ID以及辅助组 ID,来执行权限检查。
检查文件权限时,内核所遵循的规则如下。
内核会依次执行针对属主、属组以及其他用户的权限检查,只要匹配上述检查规则之一,便会停止检查。这样得出的结果可能会在意料之外,比方说,若组权限超过了属主权限,那么文件属主所拥有的权限要低于组成员的权限;若为文件的其他用户分配的权限大于文件属主或属组,上述论述也同样适用。
由于文件的权限及所有权信息都维护于文件的 i 节点之内,故而也为指向同一 i 节点的所有文件名(链接)所共享。
若进程为特权级进程,则内核在检查权限时将授予进程所有的访问权限。这一论述成立,其实还要加个限制条件。对于非目录文件,仅当该文件的 3 种权限类型(至少)之一具有可执行权限时,Linux 才会将该权限赋予一特权级进程。
如上节所述,当进程访问文件时,系统会以其 effective(有效)用户 ID、effective(有效)组ID 以及附属组 ID 来确定权限。当然,对于程序(比如,set-user-ID 或 set-group-ID 程序)来说,根据进程的 real(真实)用户 ID 和组 ID 来检查对文件的访问权限,也并非没有可能。
系统调用 access()就是根据进程的真实用户 ID 和组 ID(以及附属组 ID),去检查对pathname 参数所指定文件的访问权限。
#incldue   /* 由 pathname 所指定的文件具备mode 参数包含的所有权限,access()将返回 0; 只要有一项权限未得到满足(或者有错误发生),access()则返回−1。 */ int access(const char *pathname, int mode);  若 pathname 为符号链接,access()将对其解引用。参数 mode 是下表 中常量相或(|)而成的位掩码。
| 常量 | 描述 | 
|---|---|
| F_OK | 有这个文件吗 | 
| R_OK | 对该文件有读权限吗 | 
| W_OK | 对该文件有写权限吗 | 
| X_OK | 对该文件有执行权限吗 | 
由于对某一文件调用 access()与对同一文件的后续操作之间存在时间差,因此(不论间隔多么短暂)执行后续操作时,也无法保证在对文件的后续操作时由 access()所返回的信息依然正确。在某些应用程序设计中,上述情形可能会导致安全漏洞。比方说,假设有一 set-user-ID-root 程序,使用 access()来检查程序的真实用户 id 是否可以访问某文件,如果可以访问,就对其执行(open()或 exec()之类的)操作。问题是,若输入 access()的路径名为符号链接,而恶意用户可抢在第二步检查之前设法更改该链接,使其指向另一文件,则最终会导致 set-user-ID-root 去操作真实用户 ID 并无权限的文件。因如此,建议杜绝使用 access()
除了 9 位用来表明属主、属组和其他用户的权限之外,文件权限掩码还另设有 3 个附加位,分别为 set-user-ID (bit 04000)、set-group-ID (bit 02000)和 sticky (bit 01000)位。et-group-ID 位还有两种其他用途:对于在以 nogrpid 选项装配的目录下所新建的文件,控制其群组从属关系;可用于强制锁定文件。
作用于目录时,sticky 权限位起限制删除位的作用。为目录设置该位,则表明仅当非特权进程具有对目录的写权限,且为文件或目录的属主时,才能对目录下的文件进行删除(unlink()、rmdir())和重命名(rename())操作。(具有 CAP_FOWNER 能力的进程可省去对属主的检查。)可藉此机制来创建为多个用户共享的一个目录,各个用户可在其下创建或删除属于自己的文件,但不能删除隶属于其他用户的文件。为/tmp 目录设置 sticky 权限位,原因正在于此。
和set-user-ID位类似,可通过 chmod 命令(chmod +t file)或 chmod()系统调用来设置文件的 sticky 权限位。若对
 某文件设置了 sticky 权限位,则当执行 ls–l 命令显示该文件时,会在其他用户执行权限字段上看到字母 T,其大小写则要取决于是否对文件开启了其他用户执行权限位,如下所示:
vainx@DESKTOP-0DN0PNJ:~/wsl-code$ ls -l tfile -rw-r--r-- 1 vainx vainx 100003 Jul 20 07:08 tfile vainx@DESKTOP-0DN0PNJ:~/wsl-code$ chmod +t tfile vainx@DESKTOP-0DN0PNJ:~/wsl-code$ ls -l tfile -rw-r--r-T 1 vainx vainx 100003 Jul 20 07:08 tfile vainx@DESKTOP-0DN0PNJ:~/wsl-code$ chmod o+x tfile vainx@DESKTOP-0DN0PNJ:~/wsl-code$ ls -l tfile -rw-r--r-t 1 vainx vainx 100003 Jul 20 07:08 tfile 对于新建文件,内核会使用 open()或 creat()中 mode 参数所指定的权限。对于新建目录,则会根据 mkdir()的 mode 参数来设置权限。然而,文件模式创建掩码(简称为 umask)会对这些设置进行修改。umask 是一种进程属性,当进程新建文件或目录时,该属性用于指明应屏蔽哪些权限位。
进程的 umask 通常继承自其父 shell,其结果往往正如人们所期望的那样:用户可以使用shell 的内置命令 umask 来改变 shell 进程的 umask,从而控制在 shell 下运行程序的 umask。
大多数 shell 的初始化文件会将 umask 默认置为八进制值 022 (----w–w-)。其含义为对于同组或其他用户,应总是屏蔽写权限。因此,假定 open()调用中的 mode 参数为 0666(即令所有用户享有读、写权限,通常如此),那么对新建文件来说,其属主拥有读、写权限,所有其他用户只具有读权限(针对文件执行 ls–l 命令,会显示“rw-r–r—”)。同理,假定将 mkdir()的 mode 参数指定为 0777(即所有用户享有所有权限),那么对于新建目录来说,其属主享有所有权限,同组和其他用户则只拥有读取和执行权限(即 rwxr-xr-x)。
系统调用 umask()将进程的 umask 改变为 mask 参数所指定的值。可以以八进制数或是用来表示文件权限位的常量相或(|)来指定 mask 参数。
#inlcude   mode_t umask(mode_t mask);		/* 调用总会成功,并返回进程的前一umask */  程序示例:使用 umask()
#include  #include  #include "file_perms.h" #include "tlpi_hdr.h"  #define MYFILE "myfile" #define MYDIR  "mydir" #define FILE_PERMS    (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) #define DIR_PERMS     (S_IRWXU | S_IRWXG | S_IRWXO) #define UMASK_SETTING (S_IWGRP | S_IXGRP | S_IWOTH | S_IXOTH)  int main(int argc, char *argv[]) {     int fd;     struct stat sb;     mode_t u;      umask(UMASK_SETTING);      fd = open(MYFILE, O_RDWR | O_CREAT | O_EXCL, FILE_PERMS);     if (fd == -1)         errExit("open-%s", MYFILE);     if (mkdir(MYDIR, DIR_PERMS) == -1)         errExit("mkdir-%s", MYDIR);      u = umask(0);               /* Retrieves (and clears) umask value */      if (stat(MYFILE, &sb) == -1)         errExit("stat-%s", MYFILE);     printf("Requested file perms: %s\n", filePermStr(FILE_PERMS, 0));     printf("Process umask:        %s\n", filePermStr(u, 0));     printf("Actual file perms:    %s\n\n", filePermStr(sb.st_mode, 0));      if (stat(MYDIR, &sb) == -1)         errExit("stat-%s", MYDIR);     printf("Requested dir. perms: %s\n", filePermStr(DIR_PERMS, 0));     printf("Process umask:        %s\n", filePermStr(u, 0));     printf("Actual dir. perms:    %s\n", filePermStr(sb.st_mode, 0));      if (unlink(MYFILE) == -1)         errMsg("unlink-%s", MYFILE);     if (rmdir(MYDIR) == -1)         errMsg("rmdir-%s", MYDIR);     exit(EXIT_SUCCESS); }   vainx@DESKTOP-0DN0PNJ:~/wsl-code/tlpi-book/files$ ./t_umask Requested file perms: rw-rw---- Process umask:        ----wx-wx Actual file perms:    rw-r-----  Requested dir. perms: rwxrwxrwx Process umask:        ----wx-wx Actual dir. perms:    rwxr--r-- 可利用系统调用 chmod()和 fchmod()去修改文件权限。
#include   int chmod(const char *pathname, mode_t mode);	/* 成功返回0,失败返回-1 */ int fchmod(int fd, mode_t mode);		/* 成功返回,失败返回- */  系统调用 chmod()更改由 pathname 参数所指定文件的权限。若该参数所指为符号链接,调用 chmod()会改变符号链接所指代文件的访问权限,而非对符号链接自身的访问权限。(符号链接自创建起,其所有权限便为所有用户共享,且这些权限也不得更改。对符号链接解引用时,将忽略所有这些权限。)
系统调用 fchmod()更改由打开文件描述符 fd 所指代文件的权限。
参数 mode 用于描述文件的新权限,可以采用八进制数字形式,亦或是用来表示文件权限位的常量相或(|)而成的掩码。要想更改文件权限,进程要么具有特权级别(CAP_FOWNER),要么其有效用户 ID 于文件的用户 ID(属主)相匹配(准确说来,对于 Linux 系统上的非特权级进程,需与文件用户 ID 相匹配的是进程的文件系统用户 ID,而非其有效用户 ID)
要修改文件的特定权限位,需先调用 stat()来获取文件的现有权限,调整想修改的权限位,然后使用 chmod()去更新权限。
struct stat sb; mode_t mode;  if(stat("myfile", &sb) == -)     errExit("stat"); mode = (sb.st_mode | S_IWUSR) & ~S_IROTH; if(chmod("myfile", mode) == -1)     errExit("chmod"); 执行以上代码,等价于执行如下 shell 命令:
chmod u+w,o-r myfile 
                    上一篇:STL-list类