文件和其元数据(metadata)
linux中每个file对应一个inode,它不仅代表磁盘上的物理对象,也是内核中的一个概念实体,并且由一个数据结构体表示。
![](https://img.haomeiwen.com/i11363834/d5fad09ebc245199.png)
The Stat Family
Unix提供了一系列函数,用于获取文件的元数据。
#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()返回由路径表示的文件的信息,而fstat()返回由文件描述符fd表示的文件的信息。lstat()与stat()相同, 除了在符号链接的情况下,lstat()返回有关链接本身的信息,而不是目标文件。
这些函数中的每一个都将信息存储在由用户提供的stat结构中。stat结构体定义在<bits/stat.h> 而这个由<sys/stat.h>包含。
struct stat{
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* permissions */
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 filesystem I/O */
blkcnt_t st_blocks; /* number of blocks allocated */
time_t st_atime; /* last access time */
time_t st_mtime; /* last modification time */
time_t st_ctime; /* last status change time */
};
成功返回0,失败返回-1并且设置errno。
//example retrive the size of a file provided on the command line:
int getFileSize(int argc, char*argv[]) {
struct stat sb;
int ret;
if(argc < 2){
fprintf(stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
ret = stat(argv[1], &sb);
if(ret){
perror("stat");
return 1;
}
printf("%s is %ld bytes\n",
argv[1], sb.st_size);
return 0;
}
int main(int argc, char*argv[])
{
getFileSize(argc, argv);
return 0;
}
![](https://img.haomeiwen.com/i11363834/1b8b2d2852f05429.png)
//example for reporting file tyoe(such as symbolick link or block device node)
int getFileType(int argc, char **argv) {
struct stat sb;
int ret;
if(argc < 2){
fprintf(stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
ret = stat(argv[1], &sb);
if(ret){
perror("stat");
return 1;
}
printf("File type: ");
switch(sb.st_mode & S_IFMT){
case S_IFBLK:
printf("block device node\n");
break;
case S_IFCHR:
printf("character device node\n");
break;
case S_IFDIR:
printf("directory\n");
break;
case S_IFIFO:
printf("FIFO\n");
break;
case S_IFLNK:
printf("symbolic link\n");
break;
case S_IFREG:
printf("regular file\n");
break;
case S_IFSOCK:
printf("socket\n");
break;
default:
printf("unknown\n");
break;
}
return 0;
}
int main(int argc, char*argv[])
{
getFileType(argc, argv);
return 0;
}
![](https://img.haomeiwen.com/i11363834/cd85d41705eded0d.png)
/*
* is_on_physical_device - returns a positive
* integer if 'fd' resides on a physical device,
* 0 if the file resides on a nonphysical or
* virtual device (e.g., on an NFS mount), and
* −1 on error.
*/
int is_on_physical_device (int fd) {
struct stat sb;
int ret;
ret = fstat (fd, &sb);
if (ret) {
perror ("fstat");
return −1;
}
return gnu_dev_major (sb.st_dev);
}
Permissions
通过stat能获得file的权限,另外两个系统调用可以设置权限
#include <sys/types.h>
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
//mode 参数
- S_IRWXU 所有者具有读取、写入和执行权限。
- S_IRUSR 所有这具有读取的权限
- S_IWUSR 所有者具有写入的权限
- S_IXUSR 所有者具有执行的权限
- S_IRWXG 组具有读取、写入和执行权限
- S_IRGRP 组具有读取的权限
- S_IWGRP 组具有写入的权限
- S_IXGRP 组具有执行的权限
- S_IRWXO 每个人都可以写入、读取和执行
- S_IROTH 每个人都可以读取
- S_IWOTH 每个人都可以写入
- S_IXOTH 每个人都可以执行
成功返回0,失败返回-1,并设置errno
//eample
int ret = chmod("./map.png", S_IRUSR | S_IWUSR);
if(ret)
perror("chmod");
int ret = fchmod(fd, S_IRUSR|S_IWUSR);
if(ret)
perror("fchmod");
Ownership
stat中st_uid和st_gid分别提供了文件的拥有者和组。下面这三个调用可以改变这两个值。
#include <sys/types.h>
#include <unistd.h>
int chown(const char*path, uid_t owner, gid_t group);
int lchown(const char*path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
成功返回0,失败返回-1,并设置errno。
只有拥有CAP_CHOWN属性(通常是root进程)的进程才可以改变文件的owner。
如果owner和group参数值是-1的话,那么这个值将不被设置。
int ret;
/*
* getgrnam() returns information on a group
* given its name.
*/
gr = getgrnam ("officers");
if (!gr) {
/* likely an invalid group */
perror ("getgrnam");
return 1;
}
/* set manifest.txt's group to 'officers' */
ret = chown("manifest.txt", -1, gr->gr_gid);
if (ret)
perror ("chown");
/*
* make_root_owner - changes the owner and group of the file
* given by 'fd' to root. Returns 0 on success and −1 on
* failure.
*/
int make_root_owner (int fd) {
int ret;
/* 0 is both the gid and the uid for root */
ret = fchown (fd, 0, 0);
if (ret)
perror ("fchown");
return ret;
}
Extended Attributes
Linux 目前定义了四个扩展的属性命名空间,将来可能会定义更多。 目前的四个项目如下:
- system
- security
- trusted
- user
Extended Attribute Operations
POSIX定义了应用程序可以对给定文件的扩展属性执行的四个操作:
- 给定一个文件,返回分配给扩展属性键的所有文件的列表。
- 给定一个文件和一个键,返回相应的值。
- 给定一个文件、一个键和一个值,将该值分配给键。
- 给定一个文件和一个键,从文件中删除该扩展属性。
对于每个操作,POSIX提供三个系统调用: - 在给定路径名上运行的版本;如果路径是指符号链接,则会在链接的实际目标上操作。
- 在给定路径名上运行的版本;如果路径是指一个符号链接,则会在链接本身上操作。
- 在文件描述符上操作的版本。
检索扩展属性
#include <sys/types.h>
#include <attr/xattr.h>
ssize_t getxattr (const char *path, const char *key,
void *value, size_t size);
ssize_t lgetxattr (const char *path, const char *key,
void *value, size_t size);
ssize_t fgetxattr (int fd, const char *key,
void *value, size_t size);
成功的调用将会把key相对应的值存储在buffer value中,size是buffer的size。
函数成功调用的话返回实际value对应的size。
如果size是零,函数会返回value的size,但不会存储金buffer value中。所以传0可以额让应用知道存储key的valued的buffer的实际大小。
失败返回-1并设置errno。
设置扩展属性
#include <sys/types.h>
#include <attr/xattr.h>
int setxattr (const char *path, const char *key,
const void *value, size_t size, int flags);
int lsetxattr (const char *path, const char *key,
const void *value, size_t size, int flags);
int fsetxattr (int fd, const char *key,
const void *value, size_t size, int flags);
- 如果flag是XATTR_CREATE,如果扩展属性已经存在,则调用将失败。
- 如果flag是XATTR_REPLACE,则如果扩展属性不存在,则调用将失败。
- 默认行为是如果标志为0,则同时允许创建和替换两个行为。
- 无论标志的值如何,除key以外的key将不受影响。
成功返回0,失败返回-1。
#### 列出文件上的扩展属性
#include <sys/types.h>
#include <attr/xattr.h>
ssize_t listxattr (const char *path,
char *list, size_t size);
ssize_t llistxattr (const char *path,
char *list, size_t size);
ssize_t flistxattr (int fd,
char *list, size_t size);
![](https://img.haomeiwen.com/i11363834/4586b433d202a7af.png)
如果size传入0的话,就可以知道实际buffer list需要的大小。
成功返回0,失败返回-1,并且设置errno。
移除一个扩展属性
#include <sys/types.h>
#include <attr/xattr.h>
int removexattr (const char *path, const char *key);
int lremovexattr (const char *path, const char *key);
int fremovexattr (int fd, const char *key);
成功返回0,失败返回-1。
网友评论