【读书笔记--Linux】Linux文件管理

一  文件的状态信息

    每个文件都有自己的状态信息,如文件的大小、文件的所有者以及修改日期等,这些是与文件的内容分开存储的。

    Linux下使用stat函数获得一个文件的状态

int stat(const char*  file_name, struct stat*  buf)
int fstat(int fd, struct stat * buf)
int lstat (const char * file_name, struct stat * buf);

函数说明:

 stat函数的pathname指定文件的路径,该函数从内核中取得文件的状态并将其存储在stat结构中返回给用户,成功返回0,失败返回-1。fstat函数和stat函数类似,只是fstat函数使用文件描述符作为函数参数。lstat函数与stat函数作用一样,其差别在于,当文件本身为链接文件时,lstat会返回链接文件本身的状态信息。

stat的结构及说明

struct stat
{
dev_t st_dev; /*文件的设备编号*/
ino_t st_ino; /*文件的i-node*/
mode_t st_mode; /*文件的类型和存取的权限*/
nlink_t st_nlink; /*n 连到该文件的硬连接数目,刚建立的文件值为1 */
uid_t st_uid; /*文件所有者的用户识别码*/
gid_t st_gid; /*文件所有者的组识别码*/
dev_t st_rdev; /*若此文件为装置设备文件,则为其设备编号 */
off_t st_size; /*文件大小,以字节计算*/
unsigned long st_blksize; /*文件系统的I/O 缓冲区大小 */
unsigned long st_blocks; /*占用文件区块的个数,每一区块大小为512 个字节*/
time_t st_atime; /* 文件最近一次被存取或被执行的时间,一般只有在用mknod、utime、read、write与tructate时改变*/
time_t st_mtime; /*  文件最后一次被修改的时间,一般只有在用mknod、utime和write时才会改变 */
time_t st_ctime; /* 最近一次被更改的时间,此参数会在文件所有者、组、权限被更改时更新先前所描述的st_mode*/
};

 

二 文件的类型

      Linux环境下的文件共有以下七种:

  • 普通文件(regular file):常见的二进制可执行文件和文本文件都是普通文件。
  • 目录文件(directory file):目录文件中存放目录下文件的名字和指向它们信息的指针。目录虽然也是一种文件,但是必须使用特殊的目录系统调用去操作。
  • 块特殊文件(block  special file):Linux将硬件设备也抽象为文件,块特殊文件就是对带缓冲的设备的抽象。
  • 字符特殊文件(character special file):与块设备对应的是字符设备,字符设备是不带缓冲的设备的抽象。Linux中的设备不是块设备就是字符设备。
  • 命名管道(named pipe, FIFO):用于进程间通信的特殊文件,只存在与内核中。
  • 符号链接(symbolic link):指向另外一个文件的文件,分为符号链接和硬链接
  • 套接字(socket):用于网络进程之间通信的文件,也可用于同一主机内进程的通信。

     在stat结构文件类型存储在st_mode中,它是一个位向量。由于Linux中一共有七种文件,所以只要用3位二进制就可以表示所有的文件类型了。Linux用宏来去的相应的二进制位,从而判断文件的类型。如下是定义在sys/stat.h中的宏定义。

S_ISREG() 普通文件
S_ISDIR() 目录文件
S_ISCHR() 字符特殊发文件
S_ISBLK() 块特殊文件
S_ISFIFO() 命名管道
S_ISLNK() 符号链接
S_ISSOCK() 套接字

 三 文件权限

       Linux环境下所有的文件都有访问限制,成为文件的访问权限。每个文件的访问权限分为三类:

  • 文件所有者(u)
  • 文件所有者所在的组(g)
  • 其他的所有用户(o)

每类访问权限又分为三个权限标志位:

  • 可读(r)
  • 可写(w)
  • 可执行(x)

      三三得九,所以Linux下文件共有9个权限标志位。Linux提供了测试宏来判断指定的权限标志位是否有权限,方法是使用stat中st_mode域与相应的宏进行与操作,进而判断该位是否有相应的权限。如果有则宏返回true,否则返回false。

文件权限位测试宏
S_IRUSR 0400 用户-读
S_IWUSR 0200 用户-写
S_IXUSR 0100 用户-执行
S_IRGRP 0040 组-读
S_IWGRP 0020 组-写
S_IXGRP 0010 组-执行
S_IROTH 0004 其他用户-读
S_IWOTH 0002 其他用户-写
S_IXOTH 0001 其他用户-执行

 

四   设置用户ID和组ID 位

      一个进程通常属于某个用户,一个文件也是如此,与文件权限相关的进程ID分为4中情况,如下所示:

与进程有关的用户ID和组ID
进程用户ID和组ID 表示的意义
ruid 实际用户ID
euid 有效用户ID
rgid 实际组ID
egid 有效组ID
  • 实际用户ID:表示进程实际属于哪个用户,通常进程由哪个用户创建,则进程的实际用户ID就是哪个用户。该值一般不会改变,除非调用setuid()函数。
  • 有效用户ID:表示进程目前实际具有的用户权限。即该进程得到了某个用户的授权,暂时成为该用户的进程,从而具有与该用户其他进程同样的权限。
  • 实际组ID:类似与实际用户ID,应用与用户组方面。
  • 有效组ID:类似与有效用户ID,应用与用户组方面。

      文件的设置用户ID位和设置组ID位,可以使进程的有效用户ID和有效组ID等同与文件所有者的用户ID和组ID,使进程获得等同于文件所有者的权限。进程的用户ID和组ID是在调用exec函数时改变的,因此设置用户ID位和设置组ID位只对可执行文件起作用。Linux提供了宏测试来判断设置用户ID位和设置组ID位是否被设置。如下

设置用户ID和设置组ID的位测试宏
st_mode测试宏 宏的值(八进制) 意义
S_ISUID 042000 设置用户ID
S_ISGID 02000 设置组ID

进程在打开文件时所做的测试如下:

  1. 若进程的有效用户ID是0,即,该进程属于根用户或得到了跟用户的授权,则可以访问。
  2. 若进程的有效用户ID和文件所有者的用户ID一致,并且文件所有者适当的文件权限位已被设置,则可以访问。
  3. 若进程的有效用户ID和文件的组用户ID一致,并且文件的组用户文件权限位已经设置,则可以访问。
  4. 若进程的有效用户ID不满足以上三个条件,则不能访问。

五 文件权限操作   

    1 测试文件访问权限

       Linux下使用access函数对文件的访问权限进行测试。

相关函数
stat,open,chmod,chown,setuid,setgid
表头文件
#include<unistd.h>
定义函数
int access(const char * pathname,int mode);
函数说明
access()会检查是否可以读/写某一已存在的文件。参数mode有几种情况组合,R_OK,W_OK,X_OK 和F_OK。R_OK,W_OK与X_OK用来检查文件是否具有读取、写入和执行的权限。F_OK则是用来判断该文件是否存在。由于access()只作 权限的核查,并不理会文件形态或文件内容,因此,如果一目录表示为“可写入”,表示可以在该目录中建立新文件等操作,而非意味此目录可以被当做文件处理。 例如,你会发现DOS的文件都具有“可执行”权限,但用execve()执行时则会失败。
返回值
若所有欲查核的权限都通过了检查则返回0值,表示成功,只要有一权限被禁止则返回-

        access函数使用当前进程的实际用户ID和实际组ID与文件的所有者ID和组ID进行比较。比较方法如下:

  • 如果进程的实际用户ID和文件的所有者ID相等,使用参数mode指定的权限与文件所有者的权限进行比较。
  • 如果上一条件不成立,且进程的实际组ID和文件的组ID相等,则使用参数mode指定的权限与文件所有者的权限进行比较。
  • 如果上述条件都不成立,则使用参数mode与文件的其他用户权限进行比较。

测试下

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<fcntl.h>
 4 #include<unistd.h>
 5 #include<sys/stat.h>
 6 
 7 int main(void)
 8 {
 9     int fd;   //文件描述符
10     struct stat statbuf;  //存储文件状态信息
11     pid_t pid;       //进程ID
12     uid_t ruid,euid;  //进程的实际用户ID和有效用户ID  
13 
14     //取得文件状态
15     if(stat("test.txt", &statbuf) == -1){  
16         perror("获取文件状态失败: \n");
17         exit(1);
18      }
19 
20     //得到进程的实际用户ID和有效用户ID
21     if((ruid = getuid()) == -1 || (euid = geteuid()) == -1){
22         perror("获得进程有效用户ID失败\n");
23         exit(1);
24     }
25 
26     //打印进程的实际用户ID和有效用户ID
27     printf("当前进程的实际用户ID为:%u,有效用户ID为:%u\n", ruid, euid);
28 
29     //打印文件所有者的ID
30     printf("文件所有者为:%u\n", statbuf.st_uid);
31 
32     //测试文件权限
33     if(access("test.txt", R_OK) == -1){
34         perror("测试失败\n");
35         exit(1);
36     }
37 
38     printf("获取 成功\n");
39 
40   
41     return 0;
42 
43 } 

         2 文件权限屏蔽字umask

     使用umask权限屏蔽字,可以屏蔽一些不希望用户干预设置的权限位。即使用户对这些权限位进行设置,系统在创建文件时也会忽略用户对该位指定的值,将其设置为0。

umask(设置建立新文件时的权限遮罩)
相关函数
creat,open
表头文件
#include<sys/types.h>
#include<sys/stat.h>
定义函数
mode_t umask(mode_t mask);
函数说明
umask()会将系统umask值设成参数mask&0777后的值,然后将先前的umask值返回。在使用open()建立新文件时,该参数 mode并非真正建立文件的权限,而是(mode&~umask)的权限值。例如,在建立文件时指定文件权限为0666,通常umask值默认为 022,则该文件的真正权限则为0666&~022=0644,也就是rw-r--r--返回值此调用不会有错误值返回。返回值为原先系统的 umask值。

         下面在shell中使用文件权限屏蔽字进行测试:

  1. 打开shell]终端,使用umask检查当前权限屏蔽字

            

       2. 创建一个新文件,检查其权限是否被设置

             

       3. 再次使用umask命令改变权限屏蔽字,再察看创建后的文件权限情况

          

          可以看到此时文件的其他用户权限的可读权限被屏蔽了。

           下面在程序中使用文件权限屏蔽字进行测试,程序如下:

          

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<fcntl.h>
 4 #include<sys/stat.h>
 5 
 6 /*屏蔽所有者,组用户和其他用户的可读权限*/
 7 #define MASK S_IRUSR | S_IRGRP | S_IROTH
 8 
 9 int main()
10 {
11     int fd;
12     mode_t mask;
13     struct stat buf;
14     
15     //改变文件权限屏蔽字,并将原来的屏蔽字保存
16     mask = umask(MASK);
17    
18     printf("原始权限屏蔽字为:%x\n", mask);
19    
20     //使用新文件的所有者,组用户和其他用户的权限全部被设置
21     if( (fd = creat("tmp.txt",777)) == -1){
22         perror("创建文件失败\n");
23         exit(1);
24     }
25    
26     //获取文件的状态信息
27     if(stat("tmp.txt", &buf) == -1){
28         perror("获取文件状态信息失败\n");
29         exit(1);
30     }
31     
32     //测试文件的读属性
33     if( (buf.st_mode & S_IRUSR) != 0)
34         printf("文件tmp的所有者具有读权限\n");
35     else
36         printf("文件tmp的所有者不具有读权限\n");
37      
38     if( (buf.st_mode & S_IRGRP) != 0)
39         printf("文件tmp的所在组具有读权限\n");
40     else
41         printf("文件tmp的所在组不具有读权限\n");
42 
43     if( (buf.st_mode & S_IROTH) != 0)
44         printf("文件tmp的其他用户具有读权限\n");
45     else
46         printf("文件tmp的其他用户不具有读权限\n");
47 
48     
49     close(fd);
50 }

 运行结果如下:

      

     可以看到文件的所有可都权限都被屏蔽了。

 

      3 改变文件权限

             只有文件的所有者和根用户可以改变文件的权限。

              Linux函数使用chmod和fchmod函数来改变文件的权限。

                chmod函数

相关函数
fchmod,stat,open,chown
表头文件
#include<sys/types.h>
#include<sys/stat.h>
定义函数
int chmod(const char * path,mode_t mode);
函数说明
chmod()会依参数mode 权限来更改参数path 指定文件的权限。
参数
mode 有下列数种组合
S_ISUID 04000 文件的(set user-id on execution)位
S_ISGID 02000 文件的(set group-id on execution)位
S_ISVTX 01000 文件的sticky位
S_IRUSR(S_IREAD) 00400 文件所有者具可读取权限
S_IWUSR(S_IWRITE)00200 文件所有者具可写入权限
S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限
S_IRGRP 00040 用户组具可读取权限
S_IWGRP 00020 用户组具可写入权限
S_IXGRP 00010 用户组具可执行权限
S_IROTH 00004 其他用户具可读取权限
S_IWOTH 00002 其他用户具可写入权限
S_IXOTH 00001 其他用户具可执行权限
只有该文件的所有者或有效用户识别码为0,才可以修改该文件权限。基于系统安全,如果欲将数据写入一执行文件,而该执行文件具有S_ISUID 或S_ISGID 权限,则这两个位会被清除。如果一目录具有S_ISUID 位权限,表示在此目录下只有该文件的所有者或root可以删除该文件。
返回值
权限改变成功返回0,失败返回-1,错误原因存于errno。

             

                fchmod函数

相关函数
chmod,stat,open,chown
表头文件
#include<sys/types.h>
#include<sys/stat.h>
定义函数
int fchmod(int fildes,mode_t mode);
函数说明
fchmod()会依参数mode权限来更改参数fildes所指文件的权限。参数fildes为已打开文件的文件描述词。参数mode请参考chmod()。
返回值
权限改变成功则返回0,失败返回-1,错误原因存于errno。

          3.1 在shell中改变文件权限

               改变文件权限主要有两种方法:

  •  直接使用一个确定好的权限字改变权限。如使用权限字0777添加文件所有者的用户权限。
  • 使用相对权限,就是在原有的文件权限基础上添加若干权限,如新权限字 = 旧权限字 | 0004。

       在shell中调用chmod改变文件权限,有两种使用方法:文字设定法数字设定法 

              文字设定法,如下图

           

            数字设定法,如下图

             

          3.2 在程序中改变文件权限

                代码如下:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<fcntl.h>
 4 #include<sys/types.h>
 5 #include<sys/stat.h>
 6 
 7 
 8 #define RD_MODE S_IRUSR | S_IRGRP | S_IROTH   //读文件权限
 9 #define WR_MODE S_IWUSR | S_IWGRP | S_IWOTH   //写文件权限
10 #define EX_MODE S_IXUSR | S_IXGRP | S_IXOTH   //文件执行权限
11 
12 int main()
13 {
14     int fd;
15     struct stat statbuf;
16     mode_t mode;
17 
18     printf("程序开始\n");
19     sleep(5);
20 
21     //使用绝对权限字改变test.txt的权限
22     if(chmod("test.txt", RD_MODE) == -1){
23         perror("改变文件权限失败\n");
24         exit(1);
25     }else
26         printf("使用绝对权限字改变文件权限成功\n");
27 
28     //获取文件的状态信息
29     if(stat("test.txt", &statbuf) == -1){
30         perror("获取文件状态失败\n");
31         exit(1);
32     }
33     
34     sleep(10);
35 
36     //使用相对权限字改变文件权限
37     mode = statbuf.st_mode;   //取得文件权限字
38     mode &= (~S_IRWXU & ~S_IRWXG & ~S_IRWXO);   //关闭文件所有的权限
39     mode |= (WR_MODE);
40 
41     if(chmod("test.txt", mode) == -1){
42         perror("使用相对权限字改变文件权限失败\n");
43         exit(1);
44      }else
45          printf("使用相对权限字改变文件权限成功\n");
46 
47      sleep(10);
48 
49      //使用fchmod改变文件权限
50      fd = open("./test.txt", O_WRONLY);
51      if(fchmod(fd, EX_MODE) == -1){
52         perror("改变文件权限失败\n");
53         exit(1);
54      }else
55          printf("使用fchmod函数改变文件权限成功\n");
56 
57      printf("完成\n");
58      
59 
60     return 0;
61 }

     程序在执行之前test.txt的权限如下:

        

      使用chmod改变文件权限为RD_MODE后的权限为:

               

     使用chmod改变文件权限为WR_MODE后的权限为:

        

     使用fchmod改变文件权限为EX_MODE后的权限为:

       

      

posted @ 2013-05-03 15:25  数据世界  阅读(235)  评论(0编辑  收藏  举报