/****************************************************
包含头文件: #include <sys/stat.h>
结构体 struct stat
{
mode_t st_mode; // 文件模式及类型
ino_t st_ino; //inode节点号
dev_t st_dev; //设备号
dev_t st_rdev; //特殊设备号
nlink_t st_nlink; //文件的连接数
uid_t st_uid; //文件所有者用户ID
gid_t st_gid; //文件所有者用户组ID
off_t st_size; //普通文件对应的文件字节数
struct timespec st_atime;// 文件最后被访问的时间
struct timespec st_mtime;//文件内容最后被修改的时间
struct timespec st_ctime;//文件状态改变时间
blksize_t st_blksize; //文件内容对应的块大小
blkcnt_t st_blocks; //文件被分配的块数量
}
*****************************************************/
/********************************************************
文件类型信息包含在stat结构体成员st_mode中
用下列宏(将st_mode作为参数)可确定文件类型:
宏 文件类型
S_ISREG() 普通文件
S_ISDIR() 目录文件
S_ISCHR() 字符特殊文件
S_ISBLK() 块特殊文件
S_ISFIFO() 管道或FIFO
S_ISLNK() 符号链接
S_ISSOCK() 套接字
******************************************************/
/***************************************************
包含头文件: #include <sys/stat.h>
函数原型:int stat(const char* restrict pathname,struct stat* restrict buf);
函数说明: 返回pathname命名的文件的有关的信息结构
返回值: 成功返回0出错返回-1
**************************************************/
/*********************************************************
包含头文件: #include <sys/stat.h>
函数原型: int fstat(int fd,struct stat* restrict buf);
函数说明: 获得已在描述符上打开文件的相关信息
返回值:
***************************************************/
/*************************************************
包含头文件: #include <sys/stat.h>
函数原型: int lstat(const char* restrict pathname,struct stat* buf);
函数说明: 类似于stat,但当命名的文件是一个符号链接时,lstat返回该符号链接的有关信息,而不是由该符号链接引用的文件信息
**************************************************/
/****************************************************
包含头文件: #include <sys/stat.h>
函数原型: int fstatat(int fd,const char* restrict pathname,struct stat* restrict buf,int flag);
函数说明:flag参数为AT_SYSLINK_NOFOLLOW时,fstatat不会跟随符号链接,而是直接返回符号链接的信息
*************************************************/
实例代码4.1.c
1 #include
2 #include
3 #include
4
5 int main(int argc,char *argv[])
6 {
7 int i;
8 struct stat buf;
9 char *ptr;
10
11 for (i = 1; i < argc; ++i)
12 {
13 printf("%s: ",argv[i]);
14
15 if (lstat(argv[i],&buf) < 0)
16 {
17 printf("lstat error");
18 continue;
19 }
20
21 if (S_ISREG(buf.st_mode))
22 ptr = "普通文件";
23
24 else if (S_ISDIR(buf.st_mode))
25 ptr = "目录文件";
26
27 else if (S_ISCHR(buf.st_mode))
28 ptr = "字符特殊文件";
29
30 else if (S_ISBLK(buf.st_mode))
31 ptr = "块特殊文件";
32
33 else if (S_ISFIFO(buf.st_mode))
34 ptr = "管道或FIFO";
35
36 else if (S_ISLNK(buf.st_mode))
37 ptr = "符号链接";
38
39 else if (S_ISSOCK(buf.st_mode))
40 ptr = "套接字";
41 else
42 ptr = "unknown type";
43 printf("类型: %s\n",ptr);
44 }
45 exit(0);
46 }
运行:
/*****************************************
包含头文件: #include <unsitd.h>
函数原型: int access(const char* pathname,int mode);
函数说明: 按照实际用户ID和实际组ID进行访问权限测试
返回值: 若成功,返回0,若出错,返回-1
---------------------------------------------------------------
包含头文件: #include <unistd.h>
函数原型:int faccessat(int fd,const char* name,int mode,int flag);
函数说明:按实际用户ID和实际组ID进行访问权限测试
返回值: 若成功,返回0,若失败,返回-1;
参数说明: mode :若测试文件是否存在 mode就为F_OK
否则为下列值的或结果: mode 说明
R_OK 测试读权限
W_OK 测试写权限
X_OK 测试执行权限
flag参数可以用于改变faccessat的行为,若flag设置为AT_EACCESS,访问检查用的是有效ID和有效组ID,而不是实际ID和实际组ID
注:若在这两种情况下:
1.pathname是绝对路径
2.fd为AT_FDCWD,pathname为相对路名
access 和faccessat效果是相同的,否则
faccessat计算打开目录(fd指向的)的相对路径pathname
**********************************************************/
实例4.2.c
1 #include
2 #include
3 #include "apue.h"
4 int main(int argc,char *argv[])
5 {
6 if (argc != 2)
7 err_quit("usage: a.out " );
8 if (access(argv[1],R_OK) < 0)
9 err_ret("access error for %s",argv[1]);
10 else
11 printf("read access OK\n");
12
13 if (open(argv[1],O_RDONLY) < 0)
14 err_ret("open error for %s",argv[1]);
15 else
16 printf("open for reading ok\n");
17
18 exit(0);
19 }
实例:
#include
#include
#include
#include
int main(int argc,char* argv[])
{
if (argc != 2)
{
printf("执行请加参数: \n" );
exit(0);
}
if (access(argv[1],F_OK) < 0)
{
printf("%s 文件不存在\n",argv[1]);
}
else
{
if (access(argv[1],R_OK) < 0)
printf("实际用户ID和实际组ID无读权限\n");
else
printf("实际用户ID和实际组ID有读权限\n");
if (access(argv[1],W_OK) < 0)
printf("实际用户ID和实际组ID无写权限\n");
else
printf("实际用户ID和实际组ID有写权限\n");
if (access(argv[1],X_OK) < 0)
printf("实际用户和实际组ID无执行权限\n");
else
printf("实际用户和实际组ID有执行权限\n");
}
if (faccessat(AT_FDCWD,argv[1],F_OK,AT_EACCESS) < 0)
{
printf("%s 文件不存在\n",argv[1]);
}
else
{
if (faccessat(AT_FDCWD,argv[1],R_OK,AT_EACCESS) < 0)
printf("有效用户ID和有效组ID无读权限\n");
else
printf("有效用户ID和有效组ID有读权限\n");
if (faccessat(AT_FDCWD,argv[1],W_OK,AT_EACCESS) < 0)
printf("有效用户ID和有效组ID无写权限\n");
else
printf("有效用户ID和有效组ID有写权限\n");
if (faccessat(AT_FDCWD,argv[1],X_OK,AT_EACCESS) < 0)
printf("有效用户ID和有效组ID无执行权限\n");
else
printf("有效用户ID和有效组ID有执行权限\n");
}
exit(0);
}
运行:
/************************************************************
包含头文件: #include <sys/stat.h>
函数原型: int chmod(const char* pathname,mode_t mode);
函数说明: 更改现有文件的访问权限
返回值: 若成功返回0,若出错返回-1
注: 为了改变一个文件的权限位,进程的有效ID必须等于文件所有者ID,或者该进程必须具有超级用户权限
************************************************************/
/****************************************************
包含头文件: #include <sys/stat.h>
函数原型: int fchmod(const char* pathname,mode_t mode);
函数说明: 对已打开的文件进行操作
返回值: 若成功,返回0,若失败返回-1
*****************************************************/
/***********************************************************
二、设置用户ID位和设置组ID位。
在文件模式字(st_mode)中,有两个位(bit10和bit11)分别称为设置用户组ID位和设置用户ID位,分别有两个测试常量S_ISGID和S_ISUID与其对应。若此文件为可执行文件:
(1)当设置用户组ID位为1,则文件执行时,内核将其进程的有效用户组ID设置为文件的所有组ID。
(2)当设置用户ID位为1,则文件执行时,内核将其进程的有效用户ID设置为文件所有者的用户ID。
*****************************************************/
/***************************************************
包含头文件: #include <sys/stat.h>
函数原型: int fchmodat(int fd,const char* pathname,mode_t mode,int flag);
函数说明: 在下面两种情况:
1.pathname参数为绝对路径
2.fd取值为AT_FDCWD,pathname为相对路径
fchmodat和chmod和效果相同
否则,fchmodat相对于打开目录(由fd指向)pathname
参数flag可该fchmodat函数的行为,当设置了AT_SYMLINK_NOFOLLOW标志时,fchmodat并不会
跟随符号链接
**********************************************/
/*****************************************
包含头文件: #include <unistd.h>
函数原型:int chown(const char* pathname,uid_t owner,gid_t group);
函数说明: 用于更改文件的用户ID和组ID,如果两个参数owner或group任意一个是-1,则对应ID不变
返回值: 若成功,返回0,若失败-1
*****************************************/
/****************************************
包含头文件: #include <unistd.h>
函数原型: int fchown(int fd,uid_t owner,gid_t group);
函数说明: fchown用于由fd指向的已打开文件,改变其所有者(既然它作用于已打开文件,那么此函数就不能用于改变符号链接的所有者)
*****************************************************/
/****************************************************
包含头文件: #include<unistd.h>
函数原型: int fchownat(int fd,const char* pathname,uid_t owner,gid_t group);
函数说明:fchownat在下列两种情况:
1.pathname为绝对路径
2.fd取值为AT_FDCWD,pathname为相对路径
和chown,lchown功能相同
如果参数flag设置了AT_SYSLINK_NOFOLLOW,则lchown和fchownat行为相同
如果清除了AT_SYSLINK_NOFOLLOW标志,则fchownat和chown行为相同
否则,fd指向打开目录,pathname为相对路径名,fchownat函数计算相对于打开目录的pathname
*******************************************************/
/*****************************************************
包含头文件: #include <unistd.h>
函数原型: int lchown(const char* pathname,uid_t owner,gid_t group);
函数说明: 更改文件的所有者,在文件是符号链接的情况下,会修改符号链接的所有者,而不是修改符号链接所引用文件的所有者
******************************************************/
/****************************************************
注: 如果这些函数由非超级用户调用,则在成功返回时,
该文件的设置用户ID位和设置组ID位会被清除
***************************************************/
测试代码(注意设置用户ID位和设置ID位被清除)
4.6.c
#include
#include
#include
#include
int main(int argc,char* argv[])
{
struct stat statbuf;
if (argc != 2)
{
printf("add " );
exit(0);
}
if (stat(argv[1],&statbuf) < 0)
{
printf("get stat error\n");
exit(0);
}
if (chmod(argv[1],statbuf.st_mode | S_ISUID | S_ISGID) < 0)
{
printf("chmod error\n");
exit(0);
}
if (lchown(argv[1],27,1000) < 0)
{
printf("lchown error\n");
exit(0);
}
exit(0);
}
4.7.c
#include
#include
#include
#include
int main(int argc,char* argv[])
{
if (argc != 2)
{
printf("add " );
}
struct stat statbuf;
if (stat(argv[1],&statbuf) < 0)
{
printf("stat error\n");
exit(0);
}
if (statbuf.st_mode & S_ISUID)
{
printf("文件有设置用户ID权限\n");
}
else
printf("文件无设置用户ID权限\n");
if (statbuf.st_mode & S_ISGID)
printf("文件有设置用户组ID权限\n");
else
printf("文件无设置用户组ID权限\n");
printf("用户ID:%d\n",statbuf.st_uid);
printf("用户组ID: %d\n",statbuf.st_gid);
exit(0);
}
运行:
/*****************************************
文件长度: stat结构成员st_size表示以字节为单位的文件长度,此字段只对普通文件,目录文件和符号链接有意义。
注: 对于符号链接,文件长度是在文件名的实际字节数
(因为符号链接文件长度总是由st_size指示,所以它并不包含通常C语言用作名字结尾的null字节)
**********************************************************/
文件截断
/*********************************************************
包含头文件: #include <unistd.h>
函数原型: int truncate(const char* pathname,off_t length);
int ftruncate(int fd,off_t length);
函数说明: 将一个现有文件长度截断为length,如果该文件以前长度大于length,则length以后的字节都不可访问,如果小于length,以前文件尾和新文件尾之间之间的数据读做0(也就是在文件里创建了个空洞)
******************************************************/
实例代码:
#include
#include
#include
int main(int argc,char* argv[])
{
if (argc != 3)
{
printf("add \n" );
exit(0);
}
off_t length = atoi(argv[2]);
if (truncate(argv[1],length) < 0)
{
printf("truncate error\n");
exit(0);
}
exit(0);
}
运行:
/********************************************************
包含头文件: #include <unistd.h>
函数原型: int link(const char* existingpath,const char* newpath);
int linkat(int efd,const char* existingpath,int nfd,const char* newpath,int flag);
函数说明: 创建一个新目录项newpath,它引用现有文件existingpath.如果newpath已存在,则返回出错.只
创建newpath中的最后一个分量,路径中的其他部分应当已经存在
注: 当现有文件是符号链接时,可通过flag参数指定来控制linkat是创建指向符号链接的链接,还是创建指向符号链接所指向文件的链接
返回值: 若成功,返回0,若出错,返回-1
*******************************************************/
/********************************************************
包含头文件:#include <unistd.h>
函数原型: int unlink(const char* pathname);
int unlinkat(int fd,const char* pathname,int flag);
函数说明: 删除目录项,并将由pathname所引用文件的链接计数减一
注:为了解除对文件的链接,必须对包含该目录项的目录具有写和执行权限。
如果对该目录设置了粘帖位,则对该目录必须具有写权限,并且具备下面三个条件之一:
1.拥有该文件
2.拥有该目录
3.具有超级用户权限
当flag设置为AT_REMOVEDIR,unlinkat函数可以类似于rmdir一样删除目录,如果这个标志被清除,unlinkat与unlink执行相同操作
********************************************************/
实例:
4.9.1.c
#include
#include
#include
int main(int argc,char* argv[])
{
if (argc != 3)
{
printf("add \n" );
exit(0);
}
if (link(argv[1],argv[2]) < 0)
{
printf("link error");
exit(0);
}
exit(0);
}
4.9.2.c
#include
#include
#include
int main(int argc,char* argv[])
{
if (argc != 2)
{
printf("add \n" );
exit(0);
}
if (unlink(argv[1]) < 0)
{
printf("unlink error");
exit(0);
}
exit(0);
运行:
/********************************************************
包含头文件: #include <stdio.h>
函数原型: int rename(const char* oldname,const char* newname);
int renameat(int oldfd,const char* oldname,int newfd,const char* newname);
函数说明:(1)如果oldname指的是一个文件而不是目录,
那么为该文件或符号链接重命名。在这种情况下,如果
newname已存在,则它不能引用一个目录,此时,则现将该目录项删除,然后将oldname命名为newname
(对包含oldname和newname的目录,调用进程必须具有写权限)
(2)如果oldname指的是一个目录,那么为该目录重命名
,如果newname已存在,则newname必须引用一个目录,并且该目录应当是空目录(空目录指的是该目录只有.和..项,如果newname已存在(而且引用一个空目录),则现将其删除,然后将oldname重命名为newname.
注: 当为一个目录重命名时,newname不能包含oldname作为其路径前缀
(3)如若oldname或newname引用符号链接,则处理符号链接本身,而不是符号链接所引用的文件
******************************************************/
实例:
#include
#include
int main(int argc,char* argv[])
{
if (argc != 3)
{
printf("add \n" );
exit(0);
}
if (rename(argv[1],argv[2]) < 0)
{
printf("rename error\n");
exit(0);
}
exit(0);
}
若newdir里有文件,那么olddir会被移动到上层目录,并重命名,无上层目录,则出错且此上层目录不能为/
/*****************************************
包含头文件: #include <unistd.h>
函数原型: int symlink(const char* actualpath,const
char* sympath);
int symlinkat(const char* actualpath,int fd,const char*
sympath);
函数说明: 创建一个符号链接
注: 在创建此符号链接时,并不要求actualpath已经存在,并且,并不要求actualpath和sympath并不需要位于同一文件系统中。
返回值:若成功,返回0,若失败,返回-1
*****************************************/
/***********************************************************
包含头文件: #include <unistd.h>
函数说明: ssize_t readlink(const char* restrict pathname,
const char* restrict buf,size_t bufsize);
ssize_t readlinkat(int fd,const char* restrict pathname,char *restrict buf,size_t bufsize);
函数说明: 打开该链接本身,并读该链接中的名字
(如果函数成功执行,则返回读入buf的字节数,在buf
中返回的符号链接的内容不以null字节终止)
返回值: 若成功,返回读取的字节数,若失败返回-1
**********************************************************/
实例:
4.11.c
#include
#include
#include
int main(int argc,char* argv[])
{
if (argc != 3)
{
printf("add \n" );
exit(0);
}
if (symlink(argv[1],argv[2]) < 0)
{
printf("symlink error\n");
exit(0);
}
exit(0);
}
4.12.c
#include
#include
#include
#define BUFFERSIZE 4096
int main(int argc,char* argv[])
{
if (argc != 2)
{
printf("add \n" );
exit(0);
}
char buf[BUFFERSIZE];
int n;
if ((n = readlink(argv[1],buf,BUFFERSIZE)) < 0)
{
printf("readlink error\n");
exit(0);
}
printf("sympath actual content: %s\n",buf);
exit(0);
}
/******************************************************
包含头文件: #include <sys/stat.h>
函数原型: int futimens(int fd,const struct timespec[2]);
int utimensat(int fd,const char* path,const struct timespec times[2],int flag);
函数说明: 更改文件的访问和修改时间
注: (1)如果times参数是空指针,则访问时间和修改时间
都设置为当前时间
(2)如果times是非空指针,并且任一tv_nsec字段的值既不是UTIME_NOW也不是UTIME_OMIT,则进程的有效用户ID必须等于该文件所有者的ID,或者进程必须是一个超级用户进程,对文件只具有写权限是不够的
(3) futimens函数需要打开文件来更改它的时间,utimensat的flag参数如果设置了AT_SYMLINK_NOFOLLOW,则符号链接本身会被修改,否则默认下跟随符号链接,并把文件的时间改成符号链接的时间
*********************************************************/
/**********************************************************
包含头文件: #include <sys/stat.h>
函数原型: int mkdir(const char* pathname,mode_t
mode);
int mkdirat(int fd,const char* pathname,mode_t mode);
函数说明: 创建一个空目录,其中.和..目录项是自动创建的,所指定的文件访问权限mode由进程的文件模式创建屏蔽字修改
注:对于目录通常至少要设置一个执行权限位,以访问该目录中的文件名
返回值:若成功,返回0,若失败,返回-1
***********************************************************/
/**********************************************************
包含头文件: #include <unistd.h>
函数原型: int rmdir(const char* pathname);
函数说明: 删除空目录,空目录是指只包含.和..这两项的目录
返回值: 若成功,返回0,若出错,返回-1
**********************************************************/
实例:
#include
#include
#include
#define MODE (S_IRWXU | S_IRWXG | S_IRWXO)
int main(int argc,char* argv[])
{
if (argc != 2)
{
printf("add \n" );
exit(0);
}
umask(0);
if (mkdir(argv[1],MODE) < 0)
{
printf("mkdir error\n");
exit(0);
}
exit(0);
}
运行:
/********************************************************
包含头文件: #include <dirent.h>
函数原型: DIR *opendir(const char pathname);
DIR *fdopendir(int fd);
函数说明: 打开目录
返回值: 若成功,返回DIR指针,若出错,返回NULL
********************************************************/
/********************************************************
包含头文件: #include <dirent.h>
函数原型: struct dirent* readdir(DIR *dp);
函数说明: 读取目录
返回值: 返回参数dp目录流的下个目录项进入点(指针),
到达目录项结尾返回NULL
*******************************************************/
/******************************************************
包含头文件: #include <dirent.h>
函数原型: void rewinddir(DIR *dp);
函数说明: 设置参数dp目前读取的位置为原来开头的读取位置
*******************************************************/
/*********************************************************
包含头文件: #include <dirent.h>
函数原型: int closedir(DIR* dp);
函数说明: 关闭目录
返回值: 若成功,返回0,若失败,返回-1
*********************************************************/
/*******************************************************
包含头文件: #include <dirent.h>
函数原型: long telldir(DIR *dp);
函数说明:与dp关联目录的当前位置
******************************************************/
/**********************************************************
包含头文件: #include <dirent.h>
函数原型: void seekdir(DIR *dp,long loc);
函数说明: 设置读取目录参数dp当前位置,loc为偏移量,则下次readdir从新当前位置开始
***********************************************************/
实例: 4.15.cpp
#include
#include
#include
#include
using namespace std;
int main(int argc,char* argv[])
{
try
{
if (argc != 2)
throw domain_error("add \n" );
DIR *dp;
if ((dp = opendir(argv[1])) == NULL)
throw domain_error("dirname is no sense\n");
struct dirent* dt;
long offset;
while ((dt = readdir(dp)) != NULL)
{
offset = telldir(dp);
cout <<"目录第" << offset << "项" << dt->d_name << endl;
}
}
catch(const exception& e)
{
cout << e.what() << endl;
}
}
/***********************************************************
包含头文件: #include <unistd.h>
函数原型: int chdir(const char* pathname);
int fchdir(int fd);
函数说明: 分别用pathname或打开文件描述符来指定新的当前工作目录
返回值: 若成功,返回0,若失败,返回-1
***********************************************************/
/***********************************************************
包含头文件: #include <unistd.h>
函数原型: char* getcwd(char* buf,size_t size);
函数说明: 得到当前工作目录路径名
返回值: 若成功,返回buf,若失败,返回NULL
***********************************************************/
实例:
4.17.c
#include
#include
#include
int main()
{
if (chdir("/home/marco/o") < 0)
{
printf("chdir error\n");
exit(0);
}
printf("chdir to /home/marco/o\n");
exit(0);
}
4.18.c
#include
#include
#include
int main()
{
char *ptr;
size_t size;
if (chdir("/home/marco/o") < 0)
{
printf("chdir error \n");
exit(0);
}
ptr = (char*)malloc(50);
size = 50;
if (getcwd(ptr,size) == NULL)
{
printf("getcwd failed\n");
exit(0);
}
printf("cwd = %s\n",ptr);
exit(0);
}