UNIX环境高级编程学习之路(二)----文件和目录

对于UNIX环境编程,工作中经常会用到相关知识,作为学习UNIX环境编程的经典书籍--UNIX环境高级编程,是每个UNIX编程人员必看的经典书籍之一,为了将相关知识重新进行学习,以系统的整合所学知识,遂以博文形式作为总结。

一、概述

本章将描述文件系统的其他特征和文件的性质。将从stat函数开始,诸葛说明stat结构的每一个成员以了解文件的所有属性。在此过程中我们将说明修改这些属性的各个函数(更改所有者、更改权限等),还将更详细的查看UNIX文件系统的结构以及符号链接。


二、stat、fstat和lstat函数

#include<sys/stat.h>
int stat(const char *restrict pathname,struct stat *restrict buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *restrict pathname,struct stat *restrict buf);
三个函数的返回值:若成功则返回0,若出错则返回-1

    一旦给出pathname,stat函数就返回与此命名文件相关的信息结构。fstat函数获取已在filedes上打开的有关信息。lstat函数类似于stat,但是当命名的文件是一个符号链接时,lstat返回该符号链接的有关信息,而不是由符号链接引用文件的信息。
    第二个参数是buf指针,它指向一个我们必须提供的结构。这些函数填写由buf指向的结构。该结构的实际定义可能随实现有所不同,但其基本形式是:
struct stat {
    mode_t st_mode;     /* file type & mode (permissions) */
    ino_t      st_ino;        /* i-node number (serial number) */
    dev_t     st_dev;       /* device number (file system) */
    dev_t     st_rdev;      /* device number for special files */
    nlink_t    st_nlink;     /* number of links */
    uid_t      st_uid;        /* user ID of owner */
    gid_t      st_gid;        /* group ID of group */
    off_t       st_size;      /* size in bytes, for regular files */
    time_t    st_atime;    /* time of access */
    time_t    st_mtime;   /* time of last modification */
    time_t    st_ctmie;    /* time of last file status change */
    blksize_t st_blksize; /* best I/O block size */
    blkcnt    st_blocks;   /*number of disk blocks allocated */
};
使用stat函数最多的是ls -l命令,用其可以获得有关一个文件的所有信息。

三、文件类型
至今已经介绍了两种不同的文件类型---普通文件和目录。UNIX系统的大多数文件是普通文件或目录,但是也有另外一些文件类型。文件类型包括如下:
(1)普通文件(regular file)这种文件包含了某种形式的数据。至于这种数据是文本还是二进制数据对于UNIX内核而言并无区别。对普通文件内容的解释由处理该文件的应用程序进行。
(2)目录文件(directory file)这种文件包含了其他文件的名字以及指向与这些文件有关信息的指针。对一个目录文件具有读权限的任一进程都可以读该目录的内容,但只有内核可以直接写目录文件。
(3)块特殊文件(block special file)这种文件类型提供对设备(例如磁盘)带缓冲的访问,每次访问以固定长度为单位来进行。
(4)字符特殊文件(character special file)这种文件类型提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件。
(5)FIFO,这种类型文件用于进程间通信,有时也将其称为命名管道(named pipe)
(6)套接字(socket)这种文件类型用于进程间的网络通信。套接字也可以用于在一台宿主机上进程间的非网络通信。
(7)符号链接(symbolic link)这种文件类型指向另一个文件。
    文件类型信息包含在st_mode成员,可以用下表的宏确定文件类型。

POSIX.1允许实现将进程间通信(IPC)对象(例如,消息队列和信号量等)表示为文件。

以下代码为:对每一个命令行参数打印文件类型
#include <stdio.h> //for printf
#include <stdlib.h> //for exit
#include <sys/stat.h> //for S_ISREG()/S_ISDIR() and so on
int main(int argc,char *argv[])
{
    char *ptr;
    struct stat buf;
    int i;
    
    for(i=1; i<argc; i++)
    {
        printf("argv[%d]:%s: ",i,argv[i]);    
        if(lstat(argv[i],&buf) < 0)
        {
            perror("lstat error");
            continue;    
        }
        if(S_ISREG(buf.st_mode))
         ptr = "regular";
        else if(S_ISDIR(buf.st_mode))
         ptr = "directory";
        else if(S_ISCHR(buf.st_mode))
         ptr = "character special";
        else if(S_ISBLK(buf.st_mode))
         ptr = "block special";
        else if(S_ISFIFO(buf.st_mode))
         ptr = "fifo";
        else if(S_ISLNK(buf.st_mode))
         ptr = "symbolic link";
        else if(S_ISSOCK(buf.st_mode))
         ptr = "socket";
        else
            ptr = "***unknown mode***";
        
        printf("%s\n",ptr);
    }
    exit(0);
}
程序事例输出:./a.out /etc/passwd /etc /dev/initctl /dev/log /dev/tty /dev/scsi/host0/bus0/target0/lun0/cd /dev/cdrom
/etc/passwd:regular
/etc:directory
/dev/initctl:fifo
/dev/log:socket
/dev/tty:character special
/dev/scsi/host0/bus0/target0/lun0/cd:block special
/dev/cdrom:symbolic link

四、 设置用户ID和设置组ID
与一个进程相关的ID有6个或者更多,如下表:


* 实际用户ID和实际组ID标识我们究竟是谁。这两个字段在登录时取自口令文件中的登陆项。通常,在一个登录会话间这些值并不改变,但是超级用户进程有方法改变它们;
* 有效用户ID,有效阻ID以及附加组ID决定了我们的文件访问权限;
* 保存的设置用户ID和保存的设置组ID在执行一个程序时包含了有效用户ID和有效阻ID的副本。
    通常,有效用户ID等于实际用户ID,有效组ID等于实际组ID。
每个文件都有一个所有者和组所有者,所有者和组所有者分别用st_uid成员和st_gid成员来表示。
      当执行一个程序文件时,进程的有效用户ID通常就是实际用户ID,有效组ID通常就是实际组ID。但是可以在文件模式字(st_mode)中设置一个特殊标志,其含义是“当执行此文件时,将进程的有效用户ID设置为文件所有者的用户ID(st_uid)”。与此相类似,在文件模式字中可以设置另外一位,它使得将执行此文件的进程的有效组ID设置为文件的组所有者ID(st_gid)。在文件模式字中的这两位被称为设置用户ID(set-user-ID)位和设置组ID(set-group-ID)位。
    例如,若文件所有者是超级用户,并且设置了该文件的设置用户ID位,然后当该程序由一个进程执行时,则改进程就有超级用户特权。不管执行此文件的进程的实际用户ID是什么,都进行这种处理。
关于实际用户ID,有效用户ID,文件所有者,有如下通俗的解释:
实际用户ID: 有的文章中将其称为真实用户ID, 这个ID就是我们登陆unix系统时的身份ID。
有效用户ID: 定义了操作者的权限。有效用户ID是进程的属性,决定了该进程对文件的访问权限。
文件的访问权限包括读写和执行 。判断某个进程对文件有何权限时,内核会将非超级用户进程的有效ID与文件的所有者ID进行比较 ,当然,也可能需要比较有效组ID,这关系到具体的权限测试方法,先不在这里说明。 而超级用户创建的进程是允许访问整个文件系统的。它的有效ID等于0。不过,这里还有一点需要说明的是,仅仅有合适的有效ID,还不一定就能获得所有或者部分权限。你需要得到被访问文件的允许,这就是文件访问权限位(用户读、用户写、组读等)的责任了。
文件的所有者ID创建文件是由某用户的进程实现的吧? 所以在创建新文件的时候,就将该进程的有效ID作为该文件的所有者ID了。 APUE里面有时又将文件的所有者ID称为“文件的用户ID”。也就是该文件是由哪个用户创建的,可用通过ls -l来查看到。

五、文件访问权限
st_mode值也包括了针对文件的访问权限位,当提及文件时,指的是前面提到的任何类型的文件。所有文件类型(目录、字符特别文件等)都有访问权限。

* 我们用名字打开任一类型的文件时,对该名字中包含的每一个目录,包括它可能隐藏的当前工作目录都应具有执行权限。所以,对应目录的执行权位常被称为搜索位。
    例如,打开文件/usr/include/stdio.h,需要对/、/usr和/usr/include具有执行权限。然后,需要具有对该文件本身的适当权限,这取决于以何种模式打开它(只读、读写等)。
    如果当前目录是/usr/include,那么为了打开文件stdio.h,需要对该工作目录的执行权限。这是隐含当前工作目录的一个实例,打开stdio.h文件与打开./stdio.h作用相同。
    注意,对于目录的读权限和执行权限是不同的。读权限允许我们读目录,获得在该目录中所有文件的列表。当一个目录是我们要访问的路径名的衣蛾组成部分时,对该目录的执行权限使我们可以通过该目录。
* 为了在open函数中对一个文件制定O_TRUNC标志,必须对该文件有写权限。
* 为了在一个目录中创建一个新文件,必须对该目录具有写权限和执行权限。
* 为了删除一个现有文件,必须对包含该文件的目录具有写权限和执行权限。对该文件本身则不需要有读、写权限。
如果用6个exec函数中的任何一个执行某个文件,都必须对该文件具有执行权限。该文件还必须是一个普通文件。

六、新文件和目录的所有权
新文件的用户ID设置为进程的有效用户ID。关于组ID,POSIX.1允许实现选择下列之一作为新文件的组ID。
(1)新文件的组ID可以是进程的有效组ID。
(2)新文件的组ID可以是他所在的目录的组ID。
    使用POSIX.1所允许的第二个选项(继承目录的组ID)使得在某个目录下创建的文件和目录都具有该目录的组ID。于是文件和目录的组所有权从该点向下传递

七、access函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值