struct stat {
mode_t st_mode; /* file type & mode (permissions), suid, sgid */
ino_t st_ino; /* i-node number (serial number) */
dev_t st_dev; /* device number (file system) */
dev_t st_rdev; /* device number for special files */
nlink_t st_nlink; /* number of links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
off_t st_size; /* size in bytes, for regular files */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last modification */
struct timespec st_ctim; /* time of last file status change */
blksize_t st_blksize; /* best I/O block size */
blkcnt_t st_blocks; /* number of disk blocks allocated , 512B */
};
struct timespec {
time_t tv_sec;
long tv_nsec;
}
#include <sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf );
int fstat(int fd, struct stat *buf );
int lstat(const char *restrict pathname, struct stat *restrict buf ); // 返回该符号链接本身的有关信息
int fstatat(int fd, const char *restrict pathname, struct stat *restrict buf, int flag);
All four return: 0 if OK, −1 on error
符号链接 l
每个进程关联的用户ID和组ID
,包括实际用户ID、有效用户ID、保存的设置用户ID。每个文件有一个所有者和组所有者,由stat结构中的st_uid, st_gid指定。
进程每次打开、创建或删除一个文件时,内核就进行文件访问权限测试,这种测试可能涉及文件的所有者(st_uid和st_gid)、进程的有效ID(有效用户ID和有效组ID)、进程的附属组ID。两个所有者ID是文件的性质,而两个有效ID和附属组ID则是进程的性质。
- 若进程的有效用户ID是0(超级用户),则运行访问
- 若进程的有效用户ID等于文件的所有者ID(即进程拥有此文件),那么如果所有者适当的访问权限位被设置,则运行访问;否则拒绝访问。适当的访问权限位指的是:若进程为读而打开该文件,则用户读位应为1;若进程为写而打开该文件,则用户写位应为1;若进程将执行该文件,则用户执行位应为1。
- 若进程的有效组ID或进程的附属组ID之一等于文件的组ID,那么如果组适当的访问权限位被设置,则允许访问;否则拒绝访问。
- 若其他用户适当的访问权限位被设置,则允许访问;否则拒绝访问。
按顺序执行这4步。一旦前面的被拒绝了,即使后面的组、其他用户拥有相应权限也白搭。
Linux下如果新目录的父目录的SUID被设置,则选择2
当open函数打开一个文件时,内核以进程的有效用户ID和有效组ID为基础执行其访问权限测试。
有时,进程希望以进程的实际用户ID和实际组ID为基础来执行其访问权限测试。这使用以下两个函数:
#include <unistd.h>
int access(const char *pathname, int mode);
int faccessat(int fd, const char *pathname, int mode, int flag);
Both return: 0 if OK, −1 on error
测试文件是否存在,mode为F_OK;测试读/写/执行权限,mode为R_OK、W_OK、X_OK的按位与
#include <sys/stat.h>
mode_t umask(mode_t cmask);
Returns: previous file mode creation mask
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
int fchmod(int fd, mode_t mode);
int fchmodat(int fd, const char *pathname, mode_t mode, int flag);
All three return: 0 if OK, −1 on error
- 拥有此文件;2. 拥有此目录;3. 是超级用户
- 目录/tmp 和 /var/tmp 是设置粘着位的典型候选者。
#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int fchownat(int fd, const char *pathname, uid_t owner, gid_t group, int flag);
int lchown(const char *pathname, uid_t owner, gid_t group);
All four return: 0 if OK, −1 on error
字节
为单位的文件的长度。此字段只对普通文件、目录文件和符号链接有意义。大多数现代的UNIX系统提供字段st_blksize和st_blocks。第一个是对文件I/O较合适的块长度,第二个是所分配的实际512字节块块数。
文件中的空洞
空洞是由所设置的偏移量超过文件尾端,并写入了某些数据后造成的。对于没有写过的字节位置,read函数读到的字节是0
#include <unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int fd, off_t length);
Both return: 0 if OK, −1 on error
#include <unistd.h>
int link(const char *existingpath, const char *newpath); // 只创建newpath中的最后一个分量,路径中的其他部分应当已经存在
int linkat(int efd, const char *existingpath, int nfd, const char *newpath, int flag);
Both return: 0 if OK, −1 on error
#include <unistd.h>
int unlink(const char *pathname); // 若其父目录设置了粘着位,参见上面“粘着位”
int unlinkat(int fd, const char *pathname, int flag);
Both return: 0 if OK, −1 on error
#include <stdio.h>
int remove(const char *pathname);
Returns: 0 if OK, −1 on error
#include <stdio.h>
int rename(const char *oldname, const char *newname);
int renameat(int oldfd, const char *oldname, int newfd, const char *newname);
Both return: 0 if OK, −1 on error
引入符号链接是为了避开硬链接的一些限制:
- 硬链接通常要求链接和文件位于同一个文件系统中
- 只有超级用户才能创建指向目录的硬链接(在底层文件系统支持的情况下)
#include <unistd.h>
int symlink(const char *actualpath, const char *sympath);
int symlinkat(const char *actualpath, int fd, const char *sympath);
Both return: 0 if OK, −1 on error
#include <unistd.h>
ssize_t readlink(const char* restrict pathname, char *restrict buf, size_t bufsize);
ssize_t readlinkat(int fd, const char* restrict pathname, char *restrict buf, size_t bufsize);
Both return: number of bytes read if OK, −1 on error
#include <sys/stat.h>
int futimens(int fd, const struct timespec times[2]);
int utimensat(int fd, const char *path, const struct timespec times[2], int flag);
Both return: 0 if OK, −1 on error
#include <sys/time.h>
int utimes(const char *pathname, const struct timeval times[2]);
Returns: 0 if OK, −1 on error
#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
int mkdirat(int fd, const char *pathname, mode_t mode);
Both return: 0 if OK, −1 on error
#include <unistd.h>
int rmdir(const char *pathname);
Returns: 0 if OK, −1 on error
#include <dirent.h>
DIR *opendir(const char *pathname);
DIR *fdopendir(int fd);
Both return: pointer if OK, NULL on error
struct dirent *readdir(DIR *dp);
Returns: pointer if OK, NULL at end of directory or error
void rewinddir(DIR *dp);
int closedir(DIR *dp);
Returns: 0 if OK, −1 on error
long telldir(DIR *dp);
Returns: current location in directory associated with dp
void seekdir(DIR *dp, long loc);
dirent结构至少包含以下两个成员:
struct dirent {
ino_t d_ino; /* i-node number */
char d_name[]; /* null-terminated filename */
}
#include <unistd.h>
int chdir(const char *pathname);
int fchdir(int fd);
Both return: 0 if OK, −1 on error