英语水平低于一般人之下,不达供参水平。
Linux debian 3.2.0-4-686-pae #1 SMP Debian 3.2.60-1+deb7u3 i686 GNU/Linux |
stat,fstat, lstat, fstatat – 获取文件状态
#include <sys/types.h> #include <sys/stat.h> #include <unistd.h>
int stat(const char *path, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *path, struct stat *buf); |
这些函数的功能是检测目标文件相关的信息。目标文件不能有阻碍这些函数来访问的权限,并且,如果使用stat()和lstat()函数时,两函数要有搜索目标文件的路径的权限。
stat()统计path参数指向的文件的相关信息并把这些信息存入参数buf中。
lstat()的第一个参数与stat()不同,path指向的是目标文件的符号链接,统计的是符号链接的信息,并不是符号链接所链接到的目标文件。
fstat()根据目标文件的文件描述符fd检测文件的信息与buf中。
这几个系统调用函数都会返回一个stat类型的结构体(buf),这个结构体由以下元素构成:
struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device ID (if special file) */ off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for file system I/O */ blkcnt_t st_blocks; /* number of 512B blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last status change */ }; |
st_dev元素描述文件所位于的设备号。(major(3)和minor(3)宏能将保存在这个元素里的设备ID号分解出来。)
st_rdev元素描述文件节点所代表的设备。
st_size元素以字节为单位给出文件(普通文件或符号链接)的大小。链接符号的大小是其路径及其名字的长度,不包含末尾的空字符的长度。
st_blocks元素描述了为文件分配的内存单元数目,每个内存单元为512bytes。(当文件中有“洞”时,其值有可能小于st_size / 512。)
st_blksize元素为有效的I/O系统的文件给出首选的块大小。(用一种更小的块写文件可能会导致读、修改及重写的无效。)
不是所有的Linux系统都实现了关于文件时间的所有元素。一些Linux系统在st_atime中保存的是一个计数值,这个计数值是从上一次更改文件或目录到现在还未更改文件或目录的计数值。(参见mount(8)内的noatime, nodiratime及relatime参数,参见mount(2)里相关部分信息)。除此之外,如果文件是以O_NOATIME方式打开的st_atime的值不会得到更新,参见open(2)。
调用execve(2), mknod(2),pipe(2), utime(2)及read(2)等函数对文件的进行访问(访问内容超过0个字节)会修改st_atime。像其它的程序如mmap(2),不一定会更新st_atime的值。
调用mknod(2), truncate(2),utime(2)及write(2)等函数来修改文件(修改内容超过0个字节)时会改变st_mtime的值。另外,在一个目录里面创建或者删除一个文件时会修改这个目录的st_mtime的值。文件的拥有者(owner)、所属组(group)、硬链接数(hard link count)或者模式(mode)方式修改文件时,其文件的st_mtime的值不会改变。
写文件或者设置文件节点信息(如owner, group, linkcount, mode 等)时其文件的st_ctime的值会发生改变。
通常用一下POSIX宏来检查st_mode元素的值是否含有以下列举值的意义:
S_ISREG(m) 是否为一个普通文件
S_ISDIR(m) 是否为一个目录
S_ISCHR(m) 是否为字符设备
S_ISBLK(m) 是否为块设备
S_ISFIFO(m) 是否为FIFO文件(一种管道文件)
S_ISLNK(m) 是否为符号链接(在POSIX.1-1-1996.中无)
S_ISSOCK(m)是否问socket(在POSIX.1-1-1996.中无)
以下列举宏是为st_mode定义的各种标记(flag):
S_IFMT 0170000 文件类型的屏蔽位
S_IFSOCK 0140000 socket类型文件
S_IFLNK 0120000 符号链接类型文件
S_IFREG 0100000 普通文件
S_IFBLK 0060000 块设备
S_IFDIR 0040000 目录
S_IFCHR 0020000 字符设备(ASCII文件?)
S_IFIFO 0010000 FIFO文件
S_ISUID 0004000 (设置UID的位)set UID bit
S_ISGID 0002000 set-group-ID bit (see below)
S_ISVTX 0001000 sticky bit (see below)
S_IRWXU 00700 屏蔽拥有者权限的位mask for file ownerpermissions
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 mask for group permissions
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 mask for permissions for others (not in group)
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
set-group-ID位(S_ISGID)有几个特殊的用处。对于目录来说,这几个位表示BSD语法将会被用到这个目录上:在此目录内创建的文件会继承这个目录的组ID号,而不是从创建此文件的进程那里继承有效的组ID号,并且当目录被创建时S_ISGID位将会被设置。对于文件来说,它没有组执行(S_IXGRP)的设置位,set-group-ID位被强制性的锁住了。
目录的sticky位(S_ISVTX)表示其内的文件只有文件的所属者、文件的所属者以及有特权的进行才能对其进行重命名或删除。
函数执行成功则返回0。出错返回-1,响应的错误会设置在errno参数中。
没有访问path参数路径前缀的权限。
fd不存在。
地址无效。
当遍历目标文件路径时遇见过多的符号链接。
path参数过长。
path参数中的某部分不存在,或者path参数是一个空字符串。
内存越界(如访问到内核内存)。
path参数的目录前缀的某部分不是一个目录。
path或者fd指定文件的大小、节点数目、块的个数呈现不出来。在一个32位平台上不用-D FILE OFFSET BITS=64的参数编译其内调用stat()函数来检测一个文件的程序,这个文件的大小超过了1 <<32 -1 字节时这个错误就会发生。
内核为2.5.48及以上的版本,stat结构体中关于时间的三个元素支持纳秒时间戳。如果_BSD_SOURCE或者_SVID_SOURCE两个宏有定义,那么Glibc标准库将提供st_atime.tv_nsec格式的命名来提供纳秒时间戳。这些元素在POSIX.1-2008中被指定,并且,在2.12及以上版本中,如果_POSIX_C_SOURCE用200809L或者更大的数定义,或者_XOPEN_SOURCE被700或者更大的数定义,那么glibc标准库中也包含了能够使用纳秒的元素。如果以上提到的宏都没有被定义,那么纳秒时间戳被st_atimensec这样的命名提供。在文件系统尚不支持子时间戳,纳秒元素的值将会为0.
以下程序调用stat()函数来打印stat结构体的部分元素值:
#include <sys/types.h> #include <sys/stat.h> #include <time.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { struct stat sb; if (argc != 2) { fprintf(stderr, "Usage: %s <pathname>\n", argv[0]); exit(EXIT_FAILURE); } if (stat(argv[1], &sb) == -1) { perror("stat"); exit(EXIT_FAILURE); } printf("File type: "); switch (sb.st_mode & S_IFMT) { case S_IFBLK: printf("block device\n"); break; case S_IFCHR: printf("character device\n"); break; case S_IFDIR: printf("directory\n"); break; case S_IFIFO: printf("FIFO/pipe\n"); break; case S_IFLNK: printf("symlink\n"); break; case S_IFREG: printf("regular file\n"); break; case S_IFSOCK: printf("socket\n"); break; default: printf("unknown?\n"); break; } printf("I-node number: %ld\n", (long) sb.st_ino); printf("Mode: %lo (octal)\n", (unsigned long) sb.st_mode); printf("Link count: %ld\n", (long) sb.st_nlink); printf("Ownership: UID=%ld GID=%ld\n", (long) sb.st_uid, (long) sb.st_gid); printf("Preferred I/O block size: %ld bytes\n", (long) sb.st_blksize); printf("File size: %lld bytes\n", (long long) sb.st_size); printf("Blocks allocated: %lld\n", (long long) sb.st_blocks); printf("Last status change: %s", ctime(&sb.st_ctime)); printf("Last file access: %s", ctime(&sb.st_atime)); printf("Last file modification: %s", ctime(&sb.st_mtime)); exit(EXIT_SUCCESS); }
/*@Filename: file_size.c *@Function: Get the special file's size *@Author: One fish *@Date: 2014.11.4 Thu *@Last modified: 2014.11.4 Thu */ #include <sys/stat.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> /*@Function: Get the size of the path(file) *@arg: path is the special file *@revl: The size of the special file inclued path if stat() sucess, * otherwise exit(1) */ int file_size(const char* path) { struct stat buf; if ( stat(path, &buf) ) { switch(errno){ case EACCES: printf("Please chmod the permission of '%s'\n", path); break; case EFAULT: printf("'%s' is invalid\n", path); break; case ENAMETOOLONG: printf("The lengths of '%s' is too long\n", path); break; case ENOENT: printf("Check component of '%s' Or if '%s' is NULL\n", path, path); break; case ENOMEM: printf("Out of memory\n"); break; case ENOTDIR: printf("Component of Prefix of the '%s' is not dirctory\n", path); break; default: printf("Unkown errnos\n"); break; } exit(1); } return buf.st_size; } int main(int argc, char *argv[]) { if (argc != 2) printf("usage %s file\n", argv[0]); printf("The %s size = %d\n", argv[1], file_size(argv[1]) ); return 0; }
[2014.11.4 - 14:51]
Try-TNote Over.