Files and Directories
1 stat, fstat, lstat, fstatat
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
stat: 根据path路径,获取信息。
lstat: 功能和stat类似,但如果path指向的是一个符号链接(软链接),返回的是该符号链接的信息,而不是其所指向的文件信息。
fstat: 功能和stat类似,第一参数为文件描述符。
#include <fcntl.h> /* Definition of AT_* constants */
#include <sys/stat.h>
int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags);
int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags);
-1: 如果pathname是相对路径,则是相对于dirfd的路径,不是相对于当前进程工作空间。
-2: 如果pathname是相对路径,且dirfd为AT_FDCWD,则是相对于当前进程工作空间。
-3: 如果pathname是绝对路径,则dirfd会被忽略。
第四个参数flags可以取以下值:
AT_EMPTY_PATH: pathname可以为空,此时获得的是dirfd所指向文件的信息。
AT_NO_AUTOMOUNT: 和挂载点有关,允许手机挂载点的属性。
AT_SYMLINK_NOFOLLOW: 如果path指向一个符号链接,则返回该链接信息。默认情况下,fstatat返回的就是链接信息。
补充:
软链接,硬链接信息可以参考这里:
2 File Types
regular file: 普通文件,当我们使用ls -l查看的时候,会出现例如-rw-rw-r--, 第一个符号是'-'。
directory file: 目录文件,比较特殊的文件,存放着文件名和文件索引结点之间的关联。
block special file: 提供固定大小传送数据,包括磁盘驱动,光盘驱动。
character device: 以字节流传送数据,包括终端设备和串口设备。
fifo: 也成pipe,方便进程之间通信。
socket: 方便进程之间通信,进程可以分步在不同的计算机上。
symbolic link: 符号链接,软链接。
以上可以通过传入stat结构体中的st_mode来辨认类型:
S_ISREG()
S_ISDIR()
S_ISCHR()
S_ISBLK()
S_ISFIFO()
S_ISLNK()
S_ISSOCK()
另外,还提供stat结构体指针来辨认以下类型:
S_TYPEISMQ() : 消息队列
S_TYPEISSEM() : 信号
S_TYPEISSHM() : 共享内存对象
程序用例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string>
int main(int argc, char* argv[])
{
struct stat buff;
std::string ptr;
for(int i = 0; i < argc; ++i)
{
printf("%s: ", argv[i]);
if(lstat(argv[i], &buff) == -1)
{
printf("error[%s]\n", argv[i]);
continue;
}
if(S_ISREG(buff.st_mode))
ptr = "regular";
else if(S_ISDIR(buff.st_mode))
ptr = "directory";
else if(S_ISCHR(buff.st_mode))
ptr = "character special";
else if(S_ISBLK(buff.st_mode))
ptr = "block special";
else if(S_ISLNK(buff.st_mode))
ptr = "symbolic link";
else if(S_ISSOCK(buff.st_mode))
ptr = "socket";
else if(S_TYPEISMQ(&buff))
ptr = "queue message";
else if(S_TYPEISSEM(&buff))
ptr = "semahore";
else if(S_TYPEISSHM(&buff))
ptr = "shared memory object";
else
ptr = "unknown mode";
printf("\t%s\n", ptr.c_str());
}
return 0;
}
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string>
int main(int argc, char* argv[])
{
struct stat buff;
std::string ptr;
for(int i = 0; i < argc; ++i)
{
printf("%s: ", argv[i]);
if(lstat(argv[i], &buff) == -1)
{
printf("error[%s]\n", argv[i]);
continue;
}
if(S_ISREG(buff.st_mode))
ptr = "regular";
else if(S_ISDIR(buff.st_mode))
ptr = "directory";
else if(S_ISCHR(buff.st_mode))
ptr = "character special";
else if(S_ISBLK(buff.st_mode))
ptr = "block special";
else if(S_ISLNK(buff.st_mode))
ptr = "symbolic link";
else if(S_ISSOCK(buff.st_mode))
ptr = "socket";
else if(S_TYPEISMQ(&buff))
ptr = "queue message";
else if(S_TYPEISSEM(&buff))
ptr = "semahore";
else if(S_TYPEISSHM(&buff))
ptr = "shared memory object";
else
ptr = "unknown mode";
printf("\t%s\n", ptr.c_str());
}
return 0;
}
3 real user ID/ effective user ID/ saved set-user-ID
real user ID 即进程调用者是谁,在登陆的时候就获得的值。
effective user ID 用来校验该进程执行时获得的文件访问权限,也就是当进程访问文件的时候,权限检查的时候检查的是这个值。
saved set-user-ID 在某种情况下保存effective user ID副本。
如果没有进行处理,real user ID 与effective user ID是相同的。
更多内容在8.11章涉及,日后补上。
可以先参考这里:
4 access faccessat
#include <unistd.h>
int access(const char *pathname, int mode);
#include <unistd.h>
#include <fcntl.h>
int faccessat(int dirfd, const char *pathname, int mode, int flags);
access: 检测进程对文件的操作权限
faccessat: 检测目录下文件的操作权限
mode可以取以下值:
F_OK: 文件是否存在
R_OK, W_OK, X_OK,这三个可以通过or的方式结合。
对于faccessat,dirfd和pathname之间的关系可以参考本文fstatat中的说明。
flags可以取以下值:
AT_EACCESS: 执行检测的时候,检测effective user/group ID,默认检测的是real ID
AT_SYMLINK_NOFOLLOW: 如果检测的目标是一个符号链接(symbolic link),检测进程对该链接的操作权限,而不是其所指向的文件的操作权限。no follow,别跟过去。
程序用例:
// test4.8.cc
#include <stdio.h>
#include <unistd.h>int main(int argc, char* argv[])
{
if(argc != 2)
{
printf("error 1\n");
return 1;
}
if(access(argv[1], F_OK) < 0)
printf("file[%s] is not exist\n", argv[1]);
if(access(argv[1], R_OK) < 0)
printf("file[%s] is not readable\n", argv[1]);
else
printf("file[%s] is readable\n", argv[1]);
return 0;
}
// 普通用户
g++ -o test4.8 test4.8.cc
./test4.8 /etc/passwd ---> file[/etc/passwd] is readable
./test4.8 /etc/shadow ---> file[/etc/shadow] is not readable
5 改变文件的操作权限
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
#include <fcntl.h> /* Definition of AT_* constants */
#include <sys/stat.h>
int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
#include <sys/stat.h>
int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
在进行以上操作的时候, effective user ID必须和文件的owner ID相同,或者拥有超级权限。
mode可选的值有:
S_ISUID (04000) set-user-ID
S_ISGID (02000) set-group-ID
S_ISVTX (01000) sticky bit
S_IRWXU (00700) read, write, execute by owner
S_IRUSR (00400) read by owner
S_IWUSR (00200) write by owner
S_IROTH (00004) read by others
S_IWOTH (00002) write by others
S_IXOTH (00001) execute/search by others
#include <sys/stat.h>
int main(int argc, char* argv[])
{
struct stat statBuff;
if(stat("test4.8", &statBuff) < 0)
{
printf("error 1\n");
return 1;
}
if(chmod("test4.8", (statBuff.st_mode | S_IRWXO)) < 0)
{
printf("error 2\n");
return 1;
}
return 0;
}
6 holes in a file
7 file truncation
8 creating and read symbolic link
参考:
S_IRUSR (00400) read by owner
S_IWUSR (00200) write by owner
S_IXUSR (00100) execute/search by owner
S_IRWXG (00070) read, write, execute by group
S_IRGRP (00040) read by group
S_IWGRP (00020) write by group
S_IXGRP (00010) execute/search by group
S_IWGRP (00020) write by group
S_IXGRP (00010) execute/search by group
S_IRWXO (00007) read, write, execute by others
S_IROTH (00004) read by others
S_IWOTH (00002) write by others
S_IXOTH (00001) execute/search by others
上一个程序用例中生成的可执行文件test4.8,使用ls -l查看:
-rwxrwxr-x.
程序用例:
#include <stdio.h>
#include <unistd.h>#include <sys/stat.h>
int main(int argc, char* argv[])
{
struct stat statBuff;
if(stat("test4.8", &statBuff) < 0)
{
printf("error 1\n");
return 1;
}
if(chmod("test4.8", (statBuff.st_mode | S_IRWXO)) < 0)
{
printf("error 2\n");
return 1;
}
return 0;
}
执行完test4.9后,ls -l查看test4.8:
-rwxrwxrwx.
6 holes in a file
有时候会分配一个固定大小的文件,但是并不立即往其中写入数据。如果为这部分暂时不写如数据的部分分配磁盘空间,就有些浪费了。为了解决这个问题,引入了文件洞的概念,普通文件中包含空字符的那部分,在磁盘上并不会使用任何空间来保存,只有当真正为该文件写入数据时,才真正的为该文件分配数据块。
7 file truncation
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
使文件按指定长度截断, 如果长度增大,则在这之间补充0,或者是产生file hole
在open一个文件使用的标识符:O_TRUNC是一个截断的特例。
8 creating and read symbolic link
#include <unistd.h>
int symlink(const char *oldpath, const char *newpath);
int symlink(const char *oldpath, const char *newpath);
int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
#include <unistd.h>
ssize_t readlink(const char *path, char *buf, size_t bufsiz);
ssize_t readlink(const char *path, char *buf, size_t bufsiz);
int readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);
参考: