Linux/UNIX之文件和目录(1)

文件和目录(1)

stat、fstat和lstat函数

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

int stat(const char *path, struct stat*buf);

int fstat(int fd, struct stat *buf);

int lstat(const char *path, struct stat*buf);

一旦给出path,stat函数返回与词文件相关的信息结构。fstat获取已在描述符fd上打开的有关信息。lstat类似于stat,但当命名的文件是一个符号连接时,lstat返回该符号链接的有关信息,而不是该符号链接引用文件的信息。

第二个参数buf是一个结构指针,该结构返回文件有关信息,其基本形式如下:

struct stat {

               dev_t     st_dev;    /* ID of device containing file */

               ino_t     st_ino;    /* inode number */

               mode_t    st_mode;   /* protection */

               nlink_t   st_nlink;  /* number of hard links */

               uid_t     st_uid;    /* user ID of owner */

               gid_t     st_gid;    /* group ID of owner */

              dev_t     st_rdev;   /* device ID (if special file) */

               off_t     st_size;   /* total size, in bytes */

               blksize_t st_blksize; /*blocksize for file system I/O */

               blkcnt_t  st_blocks; /* number of 512B blocks allocated */

               time_t    st_atime;  /* time of last access */

               time_t    st_mtime;  /* time of last modification */

               time_t    st_ctime;  /* time of last status change */

};

文件类型

文件类型包括以下几种:

普通文件、目录文件、块特殊文件、字符特殊文件、FIFO、套接字和符号链接。

文件类型信息包含在stat结构的st_mode成员中,可用下面的宏来确定文件类型:

S_ISREG():                  普通文件

S_ISDIR():                            目录文件

S_ISCHR():                 字符特殊文件

S_ISBLK():                   块特殊文件

S_ISFIFO():                 管道或FIFO

S_ISLINK():                 符号链接

S_ISSOCK():                套接字

如下程序取其命令参数,然后针对每一个命令参数打印其文件类型:

#include<unistd.h>

#include<stdio.h>

#include<sys/stat.h>

int main(int argc, char *argv[])

{

         int                       i;

         structstat        buf;

         char          *ptr;

 

         for(i = 1; i < argc; i++) {

                   printf("%s:", argv[i]);

                   if(lstat(argv[i], &buf) < 0) {

                            perror("lstaterror");

                            continue;

                   }

                   if(S_ISREG(buf.st_mode))

                            ptr= "regular";

                   elseif (S_ISDIR(buf.st_mode))

                            ptr= "directory";

                   elseif (S_ISCHR(buf.st_mode))

                            ptr= "character special";

                   elseif (S_ISBLK(buf.st_mode))

                            ptr= "block special";

                   elseif (S_ISFIFO(buf.st_mode))

                            ptr = "fifo";

                   elseif (S_ISLNK(buf.st_mode))

                            ptr= "symbolic link";

                   elseif (S_ISSOCK(buf.st_mode))

                            ptr= "socket";

                   else

                            ptr= "** unknown mode **";

                   printf("%s\n",ptr);

         }

         exit(0);

}

设置用户ID和设置组ID

每个进程相关联的ID有6个或更多,如下:

实际用户ID、实际组ID:我们实际上是谁

有效用户ID、有效组ID、附加组ID:用于文件访问权限的检查

保存的设置用户ID、保存的设置组ID:由exec函数保存

每个文件都有一个所有者和组所有者,所有者由stat结果中的st_uid成员表示,组所有者则由st_gid成员表示。

当执行一个程序文件时,进程的有效用户ID通常是实际用户ID,有效组ID通常是实际组ID。但可以在文件模式(st_mode)中可以通过设置用户ID位(S_ISUID)和设置组ID位(S_ISGID)将进程的有效用户ID设置为文件所有者的用户ID,将有效组ID设置为文件的组所有者的ID。

文件访问权限

st_mode值也包含了针对文件的访问权限位。

每个文件有9个访问权限,分为三类。chmod命令用于修改这9个权限值,改名了允许我们用u表示用户,用g表示组,用o表示其他。以下是9个访问权限位:

S_IRUSR            用户读

S_IWUSR           用户写

S_IXUSR            用户执行

S_IRGRP            用户读

S_IWGRP          用户写

S_IXGRP            用户执行

S_IROTH           用户读

S_IWOTH          用户写

S_IXOTH            用户执行

目录的读权限允许我们读目录,获得在该目录中所有文件名的列表。

当一个目录是我们要访问文件路径的一个组成部分时,对该目录的执行权限使我们可通过该目录。

当需要创建或删除有一个目录中的文件时,必须对包含该文件的目录具有写权限和执行权限。

进程每次打开、创建或删除一个文件时,内核就进行文件访问权限测试,这种测试可能涉及文件的所有者、进程的有效ID以及进程的附加组ID。两个所有者ID是文件的性质,而两个有效组ID和附加组ID则是进程的性质。内核测试如下:
1.若进程有效用户ID是0(超级用户),则允许访问

2.若进程有效用户ID等于文件所有者ID,那么可通过所有者设置适当的访问权限访问文件,否则拒绝访问。

3.若进程有效组ID或附加组ID等于文件组ID,那么可通过文件组设置的适当访问权限访问文件,否则拒绝访问。

4.若其他用户适当的访问权限被设置,则允许访问;否则拒绝访问。

 

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

1)      新文件的组ID可以是进程的有效组ID

2)      新文件的组ID可以是它所在目录的组ID

access函数

#include <unistd.h>

int access(const char *pathname, int mode);

该函数按实际用户ID和实际组ID进行文件访问权限测试。成功返回0,出错返回-1。

其中第一个参数为测试文件名,第二个参数是以下所列常量的按位或

R_OK                  测试读权限

W_OK                测试写权限

X_OK                  测试执行权限

F_OK                  测试文件是否存在

以下显示了access函数的使用方法:

#include "apue.h"

#include <fcntl.h>

 

int

main(int argc, char *argv[])

{

   if (argc != 2)

       err_quit("usage: a.out <pathname>");

   if (access(argv[1], R_OK) < 0)

       err_ret("access error for %s", argv[1]);

   else

       printf("read access OK\n");

   if (open(argv[1], O_RDONLY) < 0)

       err_ret("open error for %s", argv[1]);

   else

       printf("open for reading OK\n");

   exit(0);

}

下面是该程序的示例会话:

chen123@ubuntu:~/user/apue.2e$ ls -l a.out

-rwxrwxr-x 1 chen123 chen123 78392014-04-18 19:59 a.out

chen123@ubuntu:~/user/apue.2e$ ./a.out a.out

read access OK

open for reading OK

chen123@ubuntu:~/user/apue.2e$ ls -l /etc/shadow

-rw-r----- 1 root shadow 1047 2014-04-1506:03 /etc/shadow

chen123@ubuntu:~/user/apue.2e$ ./a.out /etc/shadow

access error for /etc/shadow: Permissiondenied

open error for /etc/shadow: Permissiondenied

chen123@ubuntu:~/user/apue.2e$ su

Password:

root@ubuntu:/home/chen123/user/apue.2e# chown root a.out

root@ubuntu:/home/chen123/user/apue.2e# chmod u+s a.out

root@ubuntu:/home/chen123/user/apue.2e# ls -l a.out

-rwsrwxr-x 1 root chen123 7839 2014-04-1819:59 a.out

root@ubuntu:/home/chen123/user/apue.2e# exit

exit

chen123@ubuntu:~/user/apue.2e$ ./a.out /etc/shadow

access error for /etc/shadow: Permissiondenied

open for reading OK

这里的测试首先显示a.out的文件信息和/etc/shadow的文件信息。当执行./a.out /etc/shadow命令时,access不能通过,因为/etc/shadow的文件用户为root,而进程实际用户是chen123,所以没有读权限。open也不能通过,因为测试的是用户也是实际用户。但将a.out的用户ID改变为root,并打开设置用户ID位后,当执行a.out程序时,可以认为执行这个程序的进程有效用户ID变成了a.out文件用户ID root。但access函数测试的实际用户ID仍然是chen123。所以access不能通过,而open可以通过。但若没有打开设置用户ID位,open也不能通过。

umask函数

#include <sys/types.h>

#include <sys/stat.h>

mode_t umask(mode_t mask);

umask函数为进程设置文件模式创建屏蔽字,并返回以前的值。

参数mask是由文件访问权限中的9个常量中的若干个按位或构成的。在进程创建文件或新目录时,一定会使用文件模式创建屏蔽字。对于任何在文件模式创建屏蔽字中为1的为,在文件mode中的相应位一定被关闭。

chmod和fchmod函数

#include <sys/stat.h>

int chmod(const char *path, mode_t mode);

int fchmod(int fd, mode_t mode);

这两个函数可以更改现有的文件访问权限。

chown、fchown和lchown函数

#include <unistd.h>

int chown(const char *path, uid_t owner,gid_t group);

int fchown(int fd, uid_t owner, gid_tgroup);

int lchown(const char *path, uid_t owner,gid_t group);

以上函数可用于更改文件的用户ID和组ID。

在符号链接的情况下,lchown更改符号链接本身的所有者,而不是符号链接所指向的文件。

如若两个参数owner和group中的任意一个是-1,则个的ID不变。

文件长度

stat结构成员st_size表示一字节为单位的文件长度。此字段只对普通文件、目录文件和符号链接有意义。

对普通文件,其文件长度可以是0,在读这种文件时,将得到文件结束指示。

对于目录,文件长度通常是一个数(例如16或512)的倍数。

对于链接,文件长度是文件名(包括路径)中的实际字节数。

UNIX提供st_blksize字段,当我们将该字段用于读操作时,读一个文件的时间量最少。

文件截短

#include <unistd.h>

#include <sys/types.h>

int truncate(const char *path, off_tlength);

int ftruncate(int fd, off_t length);

这两个函数可以把现有的文件长度截短为length字节。如果该文件以前的长度大于length,则超过length以外的数据就不在能访问。如果以前的长度短语length,则扩张该文件,在旧文件尾端与新文件尾端填充0(也就是创建了空洞)。

讲一个文件清空为0可以在打开文件时使用O——TRUNC标志。

Linux/UNIX之文件和目录(1),古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。