APUE第四章学习笔记

/****************************************************
包含头文件:  #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 }

运行:

APUE第四章学习笔记_第1张图片

/*****************************************
包含头文件:  #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 }

APUE第四章学习笔记_第2张图片

实例:

#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);
}

运行:

APUE第四章学习笔记_第3张图片

APUE第四章学习笔记_第4张图片

/************************************************************
包含头文件:  #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);
}

运行:

APUE第四章学习笔记_第5张图片

/*****************************************
文件长度:   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);
}

运行:

APUE第四章学习笔记_第6张图片

APUE第四章学习笔记_第7张图片

/********************************************************
包含头文件:  #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);

运行:

APUE第四章学习笔记_第8张图片

/********************************************************
包含头文件:  #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会被移动到上层目录,并重命名,无上层目录,则出错且此上层目录不能为/
APUE第四章学习笔记_第9张图片

/*****************************************
包含头文件:  #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);
}

APUE第四章学习笔记_第10张图片

/******************************************************
包含头文件:  #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,则符号链接本身会被修改,否则默认下跟随符号链接,并把文件的时间改成符号链接的时间

*********************************************************/

APUE第四章学习笔记_第11张图片

/**********************************************************
包含头文件:  #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);
}

运行:

APUE第四章学习笔记_第12张图片

/********************************************************
包含头文件:  #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;
    }

}

APUE第四章学习笔记_第13张图片

/***********************************************************
包含头文件:  #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);
}

APUE第四章学习笔记_第14张图片

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);
}

运行:
APUE第四章学习笔记_第15张图片

你可能感兴趣的:(APUE)