APUE-文件和目录(一)

小编 2026-06-24 阅读:815 评论:0
4.1 函数stat函数stat返回与此命名文件有关的信息结构。下面的代码实现了一个工具,显示树...

4.1 函数stat

函数stat返回与此命名文件有关的信息结构。下面的代码实现了一个工具,显示树形目录结构,需要加两个参数,一个为目录名,一个为显示目录的深度。

#include <sys/stat.h>#include <sys/types.h>#include <stdio.h>#include <dirent.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <pwd.h>#include <grp.h>#include <time.h>/***************************************************************/ /*struct stat {*/ /* unsigned long   st_dev; */    /* Device.  */ /* unsigned long   st_ino;*/     /* File serial number.  */ /* unsigned int    st_mode;  */  /* File mode.  */ /* unsigned int    st_nlink;  */ /* Link count.  */ /* unsigned int    st_uid;    */ /* User ID of the file's owner.  */ /* unsigned int    st_gid;    */ /* Group ID of the file's group. */ /* unsigned long   st_rdev;    *//* Device number, if device.  */ /* unsigned long   __pad1;   */ /* long        st_size;    *//* Size of file, in bytes.  */ /* int     st_blksize; *//* Optimal block size for I/O.  */ /* int     __pad2;         */ /* long        st_blocks;*/  /* Number 512-byte blocks allocated. */ /* long        st_atime;  */ /* Time of last access.  */ /* unsigned long   st_atime_nsec; */ /* long        st_mtime;  */ /* Time of last modification.  */ /* unsigned long   st_mtime_nsec;*/ /* long        st_ctime;  */ /* Time of last status change.  */ /* unsigned long   st_ctime_nsec;  */ /* unsigned int    __unused4;     */ /* unsigned int    __unused5;*/ /*                 };    */ /* *************************************************************/void printMode(unsigned int st_mode,int indent){    int num = 0;    for(;num<indent;num++)    {        printf("  ");    }    printf(S_ISDIR(st_mode)?"d":"-");    printf(st_mode&S_IRUSR?"r":"-");    printf(st_mode&S_IWUSR?"w":"-");    printf(st_mode&S_IXUSR?"x":"-");    printf(st_mode&S_IRGRP?"r":"-");    printf(st_mode&S_IWGRP?"w":"-");    printf(st_mode&S_IXGRP?"x":"-");    printf(st_mode&S_IROTH?"r":"-");    printf(st_mode&S_IWOTH?"w":"-");    printf(st_mode&S_IXOTH?"x":"-");}void printFileName(char *name){    printf(" %s
",name);}void printUserName(unsigned int userId){    struct passwd *pwd = getpwuid(userId);    printf(" %s", pwd->pw_name);}void printGroupName(unsigned int grpId){    struct  group *grp = getgrgid(grpId);    printf(" %s" ,grp->gr_name);}void printSize(long size){    printf(" %lu",size);}void printModifyTime(long mtime){    /*char buf[100]={0};    ctime_s(buf,26,mtime);    printf(" %s",buf);*/    printf(" %lu",mtime);}int ls(char *path,int depth,int indent){    DIR *dhandle;    struct dirent *file;    struct stat st;    if(!(dhandle=opendir(path)))    {        printf("error opendir %s
",path);        return -1;    }    while((file = readdir(dhandle))!=NULL)    {        int fullPathLen = strlen(path)+strlen(file->d_name)+1;        if(strncmp(file->d_name,".",1)==0)          continue;        char *fullpath = (char*)malloc(fullPathLen+1);        memset(fullpath,0,fullPathLen+1);        strcpy(fullpath,path);        strcat(fullpath,"/");        strcat(fullpath,file->d_name);        int rv = stat(fullpath,&st);        if(rv<0)        {            return -1;        }        printMode(st.st_mode,indent);        printUserName(st.st_uid);        printGroupName(st.st_gid);        printSize(st.st_size);        printModifyTime(st.st_mtime);        printFileName(file->d_name);        if(S_ISDIR(st.st_mode)&& (depth-1>0))        {        ls(fullpath,depth-1,indent+1);        }        free(fullpath);    }    closedir(dhandle);    return 0;}int main(int argc,char *argv[]){    int dep = atoi(argv[2]);    ls(argv[1],dep,0);    return 0;}

运行如下命令

gcc stat.c

生成一个a.out可执行文件,运行如下命令:

harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ./a.out /github/ 2        drwxrwxrwx harlan harlan 0 1494143291 3202C                                           drwxrwxrwx harlan harlan 0 1494143273 Doc                                           -rw-rw-rw- harlan harlan 828 1494143273 Readme.txt                                  drwxrwxrwx harlan harlan 0 1494143279 SRC                                           drwxrwxrwx harlan harlan 0 1494143281 inc                                           -rw-rw-rw- harlan harlan 9700 1494143282 m3327.mdf                                  -rw-rw-rw- harlan harlan 1182 1494143282 m3327boot.mdf                              drwxrwxrwx harlan harlan 0 1494143290 prj                                           drwxrwxrwx harlan harlan 0 1494143292 sdk                                         drwxr-xr-x harlan harlan 0 1495673220 APUE                                            -rw-r--r-- harlan harlan 6 1493303590 README.md                                     -rwxrwxrwx root root 17478 1494424916 a.out                                         -rw-rw-rw- harlan harlan 4352 1494167949 apue.h                                     -rw-rw-rw- harlan harlan 2660400 1493735585 apue.h.gch                              drwxrwxrwx harlan harlan 0 1494248815 chapter_1                                     drwxrwxrwx harlan harlan 0 1495117067 chapter_2                                     drwxrwxrwx harlan harlan 0 1494509690 chapter_3                                     drwxrwxrwx harlan harlan 0 1495113400 chapter_4                                     drwxrwxr-x harlan harlan 0 1494944116 chapter_5                                     -rw-rw-rw- harlan harlan 2220 1494167949 err.c                                      drwxrwxr-x harlan harlan 0 1494769702 foo                                           -rw-rw-r-- harlan harlan 399 1494424891 go.c                                        -rw------- harlan harlan 1675 1494512317 key                                        -rw-r--r-- harlan harlan 404 1494512317 key.pub                                     -rw-rw-rw- harlan harlan 1501 1494116048 print.c                                    -rwx------ harlan harlan 1457 1493733958 tags                                       drwxrwxr-x harlan harlan 0 1494769702 testdir                                       -rw-r--r-- harlan harlan 4790 1495671977 vimrc.txt                                -rw------- harlan harlan 1679 1493304485 pub                                        -rw-r--r-- harlan harlan 402 1493304485 pub.pub                                     drwxrwxr-x harlan harlan 0 1494511444 test                                          

4.2 文件类型

文件类型包括以下几种:

  1. 普通文件
  2. 目录文件
  3. 块特殊文件
  4. 字符特殊文件
  5. FIFO
  6. 套接字
  7. 符号链接

可以用图4-1中的宏确定文件类型,这些宏的参数是stat结构中的st_mode成员。
APUE-文件和目录(一)
可以用图4-2中的宏来从stat结构中确定IPC对象的类型。,它们的参数是指向stat结构的指针。

APUE-文件和目录(一)

4.3 设置用户ID和设置组ID

APUE-文件和目录(一)

  • 实际用户ID和实际组ID标识我们究竟是谁。
  • 有效用户ID、有效组ID以及附属组ID决定了我们的文件访问权限。
  • 保存的设置用户ID和保存的设置组ID在执行一个程序时包含了有效用户ID和有效组ID的副本。

通常,有效用户ID等于实际用户ID,有效组ID等于实际组ID。

我们可以在文件模式字(st_mode)中设置一个特殊标志,其含义是“当执行此文件时,将进程的有效用户ID设置为文件所有者的用户ID(st_uid)”,组ID也一样。在文件模式字中的这两位被称为设置用户组ID(set-user=ID)位设置组ID(set-group-ID)位

例如,passwd允许任意用户改变其口令,该程序是一个设置用户ID程序。见下面的展示:

harlan@DESKTOP-KU8C3K5:~$ ll /etc/passwd-rw-r--r-- 1 root root 1219  5月  8 21:34 /etc/passwd
harlan@DESKTOP-KU8C3K5:~$ ll /usr/bin/passwd-rwsr-xr-x 1 root root 47032  1月 27  2016 /usr/bin/passwd

任意用户修改口令需要写入/etc/passwd文件中,而此文件只有root用户才有写权限,/usr/bin/passwd用来执行写操作,可以看到这个程序将root用户指定为设置用户组ID,因此任意用户当执行此程序进行写文件的时候将拥有root权限。

4.5 文件访问权限

所有文件类型(目录·字符特别文件等)都有访问权限(access permission)。每个文件有9个访问权限,将它们分为3类,见图4-6。

APUE-文件和目录(一)

我们用chmod命令修改这9个权限位。它允许我们用u表示用户,用g表示组,用o表示其他
图4-6中的3类访问权限(读、写和执行)以各种不同的方式由不同函数使用。

  • 规则一,我们用名字打开任一类型的文件时,对该名字中包含的每一个目录,包括它可能隐含的当前工作目录都应具有执行权限。这就是为什么对于目录其执行权限位常被称为搜索位的原因。

    读权限允许我们读目录,获得在该目录中所有文件名的列表,这是原书中的话,看下面的例子:

    drwxr-xr-- root root 0 1496278552 test-rw-r--r-- root root 0 1496278548 1.txt-rw-r--r-- root root 0 1496278552 2.txt

    test文件夹的路径为/,我们现在在普通用户(harlan)下执行ls,看是否可以将test下面的文件名列出来。可以看到test文件夹和下面的两个文件对于其他用户有读权限。

先执行一个cd.

harlan@DESKTOP-KU8C3K5:~$ cd /testbash: cd: /test: 权限不够

可见cd是需要执行权限的。

harlan@DESKTOP-KU8C3K5:~$ ls /test1.txt  2.txtharlan@DESKTOP-KU8C3K5:~$ ls -l /testls: 无法访问/test/1.txt: 权限不够ls: 无法访问/test/2.txt: 权限不够总用量 0-????????? ? ? ? ?             ? 1.txt-????????? ? ? ? ?             ? 2.txt

可见普通的ls是可以的,以列表方式列出文件信息就只列出了文件名。

为文件夹加上执行权限:

drwxr-xr-x root root 0 1496278552 test  -rw-r--r-- root root 0 1496278548 1.txt  -rw-r--r-- root root 0 1496278552 2.txt
harlan@DESKTOP-KU8C3K5:/$ cd /testharlan@DESKTOP-KU8C3K5:/test$harlan@DESKTOP-KU8C3K5:/test$cd ..harlan@DESKTOP-KU8C3K5:/$ ls -l /test总用量 0-rw-r--r-- 1 root root 0  6月  1 08:55 1.txt-rw-r--r-- 1 root root 0  6月  1 08:55 2.txt

cd执行成功,ls -l 也执行成功。

  • 对于一个文件的读权限决定了我们是否能够打开现有文件进行读操作。这与open函数的O_RDONLY和O_RDWR标志相关。
  • 对于一个文件的写权限决定了我们是否能够打开现有文件进行写操作。这与open函数的O_WRONLY和O_RDWR标志相关。
  • 为了在open函数中对一个文件指定O_TRUNC标志,必须对该文件具有写权限。
  • 为了在一个目录中创建新文件,必须对该目录具有写权限和执行权限。
  • 为了删除一个现有文件,必须对包含该文件的目录具有写和执行权限。对该文件不需要有读写权限。
    看下面的例子:
drwxr-xrwx root root 0 1496278552 test  -rw-r----- root root 0 1496278548 1.txt  -rw-r--r-- root root 0 1496278552 2.txt

在普通用户下删除1.txt:

harlan@DESKTOP-KU8C3K5:/test$ ll总用量 0-rw-r----- 1 root root 0  6月  1 08:55 1.txt-rw-r--r-- 1 root root 0  6月  1 08:55 2.txtharlan@DESKTOP-KU8C3K5:/test$ rm 1.txtrm:是否删除有写保护的普通空文件 "1.txt"? yharlan@DESKTOP-KU8C3K5:/test$ ll总用量 0-rw-r--r-- 1 root root 0  6月  1 08:55 2.txt
  • 如果用7个exec函数中的任何一个执行某个文件,都必须对该文件具有执行权限。该文件还必须是一个普通文件。

进程每打开、创建或者删除一个文件时,内核就进行文件访问权限测试,而这种测试可能涉及文件的所有者(st_uid和st_gid)、进程的有效ID(有效用户ID和有效组ID)以及进程的附属组ID(若支持的话)。两个所有者ID是文件的性质,而两个有效ID和附属组ID则是进程的性质。内核进行的具体测试如下。

APUE-文件和目录(一)

注意: 如果进程拥有此文件,则按用户访问权限批准或拒绝该进程对文件的访问——不查看组访问权限。类似的,如果进程不拥有该文件,而是属于某个组,则按照组权限批准或拒绝访问文件——不看其他用户权限。

4.6 新文件和目录的所有权

关于新目录的所有权规则与本节将说明的新文件所有权规则相同。

新文件的用户ID设置为进程的有效用户ID。关于组ID,POSIX.1允许实现选择下列之一作为新文件的组ID。

  1. 新文件的组ID可以是进程的有效组ID。
  2. 新文件的组ID可以是它所在目录的组ID。

看下面的例子:
普通用户下写一个c程序 4-7.c

-rw-rw-r-- 1 harlan harlan  290  6月  1 22:13 4-7.c
#include <unistd.h>                                                                    #include <sys/types.h>                                                                 #include <stdio.h>                                                                     #include <fcntl.h>                                                                     #define RWRWRW  (S_IRUSR |S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)                     int main(void)                                                                         {                                                                                          int fd = creat("test4-7.txt",RWRWRW);                                                  printf("uid = %d,gid=%d,euid=%d,egid=%d
",getuid(),getgid(),geteuid(),getegid()); }                                                                                      

编译生成可执行文件a.out

gcc 4-7.c
-rwxrwxr-x 1 harlan harlan 8780  6月  1 22:13 a.out

运行程序

harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ./a.out

输出:

uid = 1000,gid=1000,euid=1000,egid=1000

查看创建的文件s所属用户(harlan用户ID为1000):

-rw-rw-r-- 1 harlan harlan    0  6月  1 22:13 test4-7.txt

修改a.out可执行程序的拥有着为root,并设置保存的设置用户ID:

harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ su密码:root@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples# chown root a.outroot@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples# ll a.out-rwxrwxr-x 1 root harlan 8780  6月  1 22:13 a.out*root@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples# chmod u+s a.outroot@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples# ll a.out-rwsrwxr-x 1 root harlan 8780  6月  1 22:13 a.out*

跳转到harlan用户执行a.out:

harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ./a.outuid = 1000,gid=1000,euid=0,egid=1000harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ll test4-7.txt-rw-rw-r-- 1 root harlan 0  6月  1 22:33 test4-7.txt

可以看到有效用户ID变为了0,因此创建的文件的用户变为了root。

在看一下新创建文件的组ID,将a.out的组设置为root,并且设置保存的设置组ID:

harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ su密码:root@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples# chgrp root a.outroot@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples# chmod g+s a.outroot@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples# ll a.out-rwxrwsr-x 1 root root 8780  6月  1 22:13 a.out*

回到harlan用户下执行a.out,可以看到生成文件所属组为root.

root@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples# su harlanharlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ./a.outuid = 1000,gid=1000,euid=1000,egid=0harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ll test4-7.txt-rw-rw-r-- 1 harlan root 0  6月  1 22:41 test4-7.txt

可执行程序a.out所在目录myexamples的组为harlan

drwxrwxr-x 2 harlan harlan     0  6月  1 22:41 myexamples```

设置myexamples文件夹的设置组ID

harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4$ chmod g+s myexamplesdrwxrwsr-x 2 harlan harlan     0  6月  1 22:41 myexamples

执行a.out之后发现生成文件的组变为了harlan,也就验证了APUE中的说法。

harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ./a.outuid = 1000,gid=1000,euid=1000,egid=0harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ll test4-7.txt-rw-rw-r-- 1 harlan harlan 0  6月  2 08:14 test4-7.txt


作者:HarlanC

博客地址:http://www.cnblogs.com/harlanc/
个人博客: http://www.harlancn.me/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接

如果觉的博主写的可以,收到您的赞会是很大的动力,如果您觉的不好,您可以投反对票,但麻烦您留言写下问题在哪里,这样才能共同进步。谢谢!

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表