本章将围绕stat函数来说明文件的属性和修改这些属性的函数,详细地介绍文件系统的结构以及对目录进行操作的各个函数。
一 stat、fstat和lstat函数
#include<sys/stat.h> int stat( const char *restrict pathname, struct stat *restrict buf ); int lstat( const char *restrict pathname, struct stat *restrict buf ); int fstat( int file_des, struct stat *buf ); 这三个函数将与文件相关的信息结构填入由指针buf指向的stat结构中。当pathname是一个符号链接时,lstat返回该符号链接本身的有关信息,stat返回该符号链接指向的文件的有关信息。二 设置用户ID和设置组ID
与一个进程相关的ID有6个或更多,如下所示: 实际用户ID和实际组ID 在登录时从口令文件中获取。在一个登录会话间并不改变,只有超级用户进程可以改变它们。 有效用户ID、有效组ID和附加组ID 进程的有效用户ID通常为实际用户ID,有效用户组ID通常为实际用户组ID。 保存的设置用户ID和保存的设置组ID 有效用户ID和有效组ID的副本。 举一个例子说明设置用户ID和设置组ID的作用。当以用户名为zhu的身份登录时,实际用户ID为从口令文件中读取的zhu。当以实际用户ID为zhu的身份运行一个passwd进程时,该进程的有效用户ID为zhu,该进程要读写口令文件/etc/passwd或/etc/shadow,但是此文件的所有者是root,只有root才可以修改此文件,要想读写此文件,必须拥有root的权限。怎么使zhu拥有root的权限?在文件passwd的文件模式字(st_mode)中有一个设置用户ID(set-user-ID)位,如果该位被设置,那么在用户zhu运行passwd进程时,该进程的有效用户IDzhu就会被设置为root,从而获得了修改/etc/passwd或/etc/shadow的权限。设置组ID也是类似情况。 设置用户ID和设置组ID都包含在st_mode值中,这两个位可以用常量S_ISUID和S_ISGID测试。三 新文件和目录的所有权
新文件的用户ID设置为进程的有效用户ID,新文件的组ID采用以下选择之一实现: 1 新文件的组ID可以是进程的有效组ID; 2 新文件的组ID可以是它所在目录的组ID。四 access函数
#include<unistd.h> int access( const char *pathname, int mode ); 以实际用户ID和实际组ID测试访问权限。mode参数按下列常量的按位或: R_OK 测试读权限 W_OK 测试写权限 X_OK 测试执行权限 F_OK 测试文件是否存在五 umask函数
#include<sys/stat.h> mode_t umask( mode_t mask ); 为进程创建文件模式屏蔽字。返回值:以前的文件模式创建屏蔽字。更改进程的文件模式创建屏蔽字并不影响父进程的屏蔽字。六 chmod和fchmod函数
#include<sys/stat.h> int chmod( const char *path_name, mode_t mode ); int fchmod( int file_des, mode_t mode ); chmod对指定的文件进行操作,fchmod对已经打开的文件进行操作。要改变一个文件的访问权限位,进程的有效用户ID必须等于文件所有者的用户ID,或者该进程具有超级用户权限。七 粘住位(保存正文位,saved-text bit)
如果对一个目录设置了粘住位(常量S_ISVTX),则只有对该目录具有写权限的用户在下列情况之一才能删除或重命名该目录下的文件: 该用户拥有此目录;该用户拥有此文件;该用户是超级用户。八 chown、fchown和lchown函数
#include<unistd.h> int chown( const char *path_name, uid_t owner, gid_t group ); int fchown( int file_des, uid_t owner, gid_t group ); int lchown( const char *path_name, uid_t owner, gid_t group ); lchown更改的是符号链接本身的所有者,而不是符号链接所指向的文件。如果参数owner或group中的任一一个是-1,则对应的ID不变。九 文件长度
文件长度由stat结构成员st_size表示,以字节为单位,此字段只对普通文件、目录文件和符号链接有意义。字段st_blksize表示对文件I/O较适合的块长度,st_blocks表示所分配的实际块数量。十 文件截短
#include<unistd.h> int truncate( const char *path_name, off_t length ); int ftruncate( int file_des, off_t length ); 把现有的文件长度截短为length,如果文件以前的长度超过length,那么超过的部分将不能再访问;如果文件以前的长度小于length,可能会增加文件的长度至length或者再文件中创建一个空洞。十一 link、unlink、remove和rename函数
#include<unistd.h> int link( const char *existing_path, const char *new_path ); int unlink( const char *path_name ); link函数创建一个新目录项new_path并增加链接计数,如果new_path已经存在,返回出错,只创建new_path的最后一个分量,其他部分应当已经存在,existing_path和new_path应该在同一个文件系统中。unlink函数删除目录项并减少链接计数,link和unlink操作的都是硬链接。 #include<stdio.h> int remove( const char *path_name ); int rename( cosnt char *old_name, const char *new_name ); 对于文件,remove的功能和unlink相同,对于目录,remove的功能和rmdir相同。rename对文件或目录重命名。十二 symlink和readlink函数
#include<unistd.h> int symlink( const char *actual_path, const char *sym_link ); ssize_t readlink( const char *restrict path_name, char *restrict buf, size_t buf_size ); symlink函数为actual_path创建一个符号链接sym_link,actual_path可以不存在,actual_path和sym_link可以不在同一个文件系统中。readlink函数将符号链接path_name文件的内容读入到buf指向的缓冲区中,缓冲区大小为buf_size,符号链接的内容不以null终止。十三 文件的时间
与文件相关的三个时间值: st_atime 文件数据的最后访问时间 st_mtime 文件数据的最后修改时间 st_ctime i节点状态的最后修改时间 十四 utime函数 #include<utime.h> int utime( const char *path_time, cosnt struct utimebuf *times ); 更改文件的访问时间和修改时间。struct utimebuf的数据结构是: struct utimebuf { time_t actime; //访问时间 time_t modtime; //修改时间 } 两个时间值是Unix时间戳。此函数的操作及执行它所要求的特权取决于times参数是否为NULL: 1 如果times是NULL,则访问时间和修改时间都设置为当前时间,执行此操作必须满足:进程的有效用户ID和该文件的所有者ID必须相等,或者进程对该文件必须具有写权限。 2 如果times非NULL,则访问时间和修改时间都设置为times所指向结构中的值,执行此操作必须满足:进程的有效用户ID和该文件的所有者ID必须相等,或者进程是超级进程,对文件仅有写权限是不够的。 当调用utime时,ctime字段被自动更新。十五 mkdir和rmdir函数
#include<sys/stat.h> int mkdir( const char *path_name, mode_t mode ); int rmdir( const char *path_name ); mkdir创建一个新的空目录,.和..目录项自动创建,mode参数至少要设置一个执行权限位,以允许访问该目录中的文件名。rmdir删除一个空目录,空目录只包含.和..两项。十六 chdir、fchdir和getcwd函数
#include<unistd.h> int chdir( const char *path_name ); int fchdir( int file_des ); int *getcwd( char *buf, size_t size );