AUPE学习第四章------文件和目录

如果我们希望知道文件的各种信息和特征,stat结构可以包含文件的所有属性。

我们可以通过下面三个函数来得到文件的所有属性和信息:

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。

其中buf参数结构式我们必须提供来存储文件信息的。

structstat.c:

struct stat
{
mode_t     st_mode;
ino_t      st_ino;
dev_t      st_dev;
dev_t      st_rdev;
nlink_t    st_nlink;
uid_t      st_uid;
gid_t      st_git;
off_t      st_size;
time_t     st_atime;
time_t     st_mtime;
time_t     st_ctime;
}

4.3文件类型

普通文件,目录文件,快特殊文件,字符特殊文件,FIFO,套接字(socket),符号链接。

文件类型信息包含在stat结构的st_mode成员中。可以用下面的宏来确认文件类型,st_mode是他们的参数。

<sys/stat.h>中的文件类型宏

S_ISREG()         普通文件

S_ISDIR()           目录文件

S_ISCHR()         字符特殊文件

S_ISBLK()          块特殊文件

S_ISFIFO()         管道或者FIFO

S_ISLNK()          符号链接

S_ISSOCK()      套接字

下面的程序对每个命令行参数打印文件类型:

stattest.c:

#include "apue.h"

int main(int argc, char *argv[])
{
    int i;
    struct stat buf;
    char *ptr;
    for (i =1; i < argc; i++)
    {
        printf("%s: ", argv[i]);
        if (lstat(argv[i], &buf) < 0)
        {
            err_ret("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);
}

运行结果如下:

[root@localhost apue]# gcc -o stattest.out stattest.c 
[root@localhost apue]# ./ stattest.out  /etc/passwd /etc /dev/initctl /dev/log\
> /dev/tty /dev/scsi/host0/bus0/target0/lun0/cd /dev/cdrom
bash: ./: is a directory
[root@localhost apue]# ./stattest.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/dev/tty: lstat error: Not a directory
/dev/scsi/host0/bus0/target0/lun0/cd: lstat error: No such file or directory
/dev/cdrom: symbolic link
[root@localhost apue]# ./stattest.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: lstat error: No such file or directory
/dev/cdrom: symbolic link

4.4设置用户ID和设置组ID

与进程相关的ID共有六个或者更多。实际用户ID,实际组ID,有效用户ID,有效组ID,附加组ID,保存的设置用户ID,保存的设置组ID。

通常有效用户ID等于实际用户ID,有效组ID等于实际组ID。分别由stat结构中的st_uid和st_gid来确定。

4.5文件访问权限

stat结构中的st_mode值也包含针对文件的访问权限位。所有的文件类型都有访问权限。

有效用户ID就是执行这个进程的用户的ID,实际用户ID就是文件的所有者。组是同样的结果。

当我们用open或者creat,mkdir新建一个目录或者文件的时候,文件的所有者ID就是进程的有效用户ID,

组ID要么是有效组ID或者它所在目录的ID。

4.7 access函数

我们有时需要测试实际用户和组对文件的访问权限,access函数是按实际用户ID和组ID进行访问权限测试的。

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

返回:成功返回0,错误返回-1。

mode参数是按下面的几个值按位或。

mode          说明

R_OK          测试读权限

R_OK         测试写权限

X_OK          测试执行权限

F_OK          测试文件是否存在

access函数实例:

access.c:

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

执行结果:

[root@localhost apue]# gcc -o access.out access.c 
[root@localhost apue]# ls -l access.out 
-rwxr-xr-x 1 root root 7025 12-28 17:51 access.out
[root@localhost apue]# ./access.out  access.out
read access ok
open for reading ok
[root@localhost apue]# ./access.out  /etc/shadow
read access ok
open for reading ok
[root@localhost apue]# su - huangcd
[huangcd@localhost ~]$ cd /apue
[huangcd@localhost apue]$ ./access.out  /etc/shadow
access error for /etc/shadow: Permission denied
open error for /etc/shadow: Permission denied

4.8umask函数

umask函数用于设置创建文件的默认权限。
mode_t     umask(mode_t   cmask);
返回:返回以前的权限对应的数字。
cmask对应于下面的一个或者多个的或。

st_mode mask

Meaning

S_IRUSR

user-read

S_IWUSR

user-write

S_IXUSR

user-execute

S_IRGRP

group-read

S_IWGRP

group-write

S_IXGRP

group-execute

S_IROTH

other-read

S_IWOTH

other-write

S_IXOTH

other-execute

umask函数实例:

#include "apue.h"
#include <fcntl.h>

#define RWRWRW (S_IRUSR|S_IWUSR|S_IWGRP|S_IRGRP|S_IROTH|S_IWOTH)

int main(void)
{
    umask(0);
    if (creat("foo", RWRWRW) < 0)
        err_sys("creat error for foo");
    umask(S_IWGRP|S_IRGRP|S_IROTH|S_IWOTH);
    if (creat("bar", RWRWRW) < 0)
        err_sys("creat error for bar");
    exit(0);
}

我们可以从结果发现,umask设置的屏蔽位已经覆盖了creat函数设置的屏蔽位。

运行结果:

[huangcd@localhost apue]$ gcc -o umasktest.out umasktest.c 
[huangcd@localhost apue]$ umask
0002
[huangcd@localhost apue]$ ./umasktest.out 
[huangcd@localhost apue]$ ls -l foo bar
-rw------- 1 huangcd huangcd 0 12-28 18:20 bar
-rw-rw-rw- 1 huangcd huangcd 0 12-28 18:20 foo

4.9chmod和fchmod函数

这两个函数可用用于改变现有文件的访问权限。

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

int    fchmod(int    filedes,  mode_t  mode);

mode参数在下面中的一个或者多个或,在<sys/stat.h>中定义。

mode

Description

S_ISUID

set-user-ID on execution

S_ISGID

set-group-ID on execution

S_ISVTX

saved-text (sticky bit)

S_IRWXU

read, write, and execute by user (owner)

S_IRUSR

read by user (owner)

S_IWUSR

write by user (owner)

S_IXUSR

execute by user (owner)

S_IRWXG

read, write, and execute by group

S_IRGRP

read by group

S_IWGRP

write by group

S_IXGRP

execute by group

S_IRWXO

read, write, and execute by other (world)

S_IROTH

read by other (world)

S_IWOTH

write by other (world)

S_IXOTH

execute by other (world)

chmod函数实例:

chmodtest.c:

#include "apue.h"

int main(void)
{
    struct stat statbuf;
    if (stat("foo", &statbuf) < 0)
        err_sys("stat error for foo");
    /*turn on set-group-id and trun off group-execute*/
    if (chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)
        err_sys("chmod error for foo");
    /*set absolute mode to rw-r--r--*/
    if (chmod("bar", S_IRUSR| S_IWUSR| S_IRGRP| S_IROTH) < 0)
        err_sys("chmod error for bar");
    exit(0);
}

运行结果:

[huangcd@localhost apue]$ vim chmodtest.c
[huangcd@localhost apue]$ ls -l bar foo
-rw------- 1 huangcd huangcd 0 12-28 18:20 bar
-rw-rw-rw- 1 huangcd huangcd 0 12-28 18:20 foo
[huangcd@localhost apue]$ gcc -o chmodtest.out chmodtest.c 
[huangcd@localhost apue]$ ./chmodtest.out 
[huangcd@localhost apue]$ ls -l bar foo
-rw-r--r-- 1 huangcd huangcd 0 12-28 18:20 bar
-rw-rwSrw- 1 huangcd huangcd 0 12-28 18:20 foo

如果一个文件设置了粘住位,那么在文件第一次执行以后,保留程序正文部分的一个副本在交换区。可以通过S_ISVTX来设置粘住位。

4.11chown、fchown和lchown函数

下面几个函数可以用于更改文件的用户ID和组ID。

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

int   fchown(int   filedes,   uid_t   owner,  gid_t  group);

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

如果参数owner和group中的任何一个值是-1,那么对应的ID不变。

4.12文件长度

stat结构成员st_size表示以字节为单位的文件长度,此字段只针对普通文件,目录文件和连接文件有效。

文件空洞是由于所设置的偏移量超过文件尾端,并写入某些数据造成的。对于没有写入的空洞,read读入的字节是0。

复制有空洞的文件的时候,所有的空洞都被填满。

4.13文件截短

我们可以通过在打开文件时设置O_TRUNC标志来将一个文件清空为0。

下面的函数可以用于文件的截短:

int    truncate(const   char   *pathname,   off_t    length);

int    ftruncate(int    filedes,   off_t   length);

这两个函数把文件的长度截短为length长。

4.19utime函数

一个文件的访问和修改时间可以用utime函数来实现。

int   utime(const  char  *pahtname,  const struct  utimebuf   *times)

参数中的time的结构如下:

struct  utimebuf{

     time_t   actime;

     time_t   modtime;

}

utime函数实例:

#include "apue.h"
#include <fcntl.h>
#include <utime.h>

int main(int argc, char *argv[])
{
    int   i,fd;
    struct stat   statbuf;
    struct utimbuf timebuf;
    for (i = 1; i< argc; i++)
    {
        if (stat(argv[i] , &statbuf) < 0)
        {
            err_ret("%s: stat errir", argv[i]);
            continue;
        }
        if ((fd = open(argv[i], O_RDWR| O_TRUNC)) < 0)
        {
            err_ret("%s: open error", argv[i]);
            continue;
        }
        close(fd);
        timebuf.actime = statbuf.st_atime;
        timebuf.modtime = statbuf.st_mtime;
        if (utime(argv[i], &timebuf) < 0)
        {
            err_ret("%s: utime error", argv[1]);
            continue;
        }
    }
    exit(0);
}

运行结果:

[root@localhost apue]# ls -l printId.out 
-rwxr-xr-x 1 root root 5241 12-25 15:42 printId.out
[root@localhost apue]# ls -ul printId.out 
-rwxr-xr-x 1 root root 5241 12-30 14:00 printId.out
[root@localhost apue]# date
2013年 12月 30日 星期一 14:20:28 CST
[root@localhost apue]# ./utimetest.out  printId.out 
[root@localhost apue]# ls -l printId.out 
-rwxr-xr-x 1 root root 0 12-25 15:42 printId.out
[root@localhost apue]# ls -ul printId.out 
-rwxr-xr-x 1 root root 0 12-30 14:20 printId.out
[root@localhost apue]# ls -cl printId.out 
-rwxr-xr-x 1 root root 0 12-30 14:20 printId.out

4.20mkdir和rmdir函数

新建一个目录,pahtname是一个空目录。mode是新建目录的权限值。

int    mkdir(const   char   *pathname,   mode_t   mode)

若成功返回0,出错返回-1。

用rmdir和删除一个目录。空目录只包含.和..这两项的目录。

int   rmdir(const  char   *pathname);

4.21读目录

我们可以通过下列函数来实现对一个目录的读取等操作:

DIR   *   opendir(const  char   *pahtname)     //成功返回指针,错误返回NULL

struct   dirent  * readdir(DIR  *dp);      //成功返回指针,错误返回目录结尾或者NULL

void    rewinddir(DIR   *dp)                   //成功返回0,错误返回-1

int       closedir( DIR  *dp)                            //成功返回0,错误返回-1.

long    telldir( DIR  *dp)                  //返回dp关联的目录中的当前位置。

void     seekdir(DIR  *dp,  long   loc)   //返回dp关联的目录中的当前位置。

这些函数都是在头文件<dirent.h>中定义的啊。结构体的定义如下:

struct  dirent{

ino_t   d_no;

char   d_name[NAME_MAX + 1]

}

DIR是一个内部结构,它用来保存当前正在被读取的目录的有关信息。

由opendir函数返回DIR结构的指针由其他五个函数操作。

4.22 chdir、fchdir和getcwp函数

每个进程都有一个当前工作目录,次目录是搜索所有相对路径名的起点。当前工作目录是进程的一个属性。

进程通过调用chdir和fchdir函数可以更改当前工作目录。

int   chdir(const   char  *pahtname)

int   fchdir(int filedes)

若成功返回0,若错误则返回-1。参数是指定的新的工作目录。

chdir函数实例:

chdirtest.c:

#include "apue.h"

int main(void)
{
    if (chdir("/tmp") < 0)
        err_sys("chdir failed");
    printf("chdir to /tmp succeeded\n");
    exit(0);
}

执行结果:

[root@localhost apue]# gcc -o chdirtest.out chdirtest.c 
[root@localhost apue]# pwd
/apue
[root@localhost apue]# ./chdirtest.out 
chdir to /tmp succeeded
[root@localhost apue]# pwd
/apue
我们虽然改变了当前进程的工作目录,但是并没有改变shell的工作目录,当前进程是shell进程的一个子进程。

内核中并没有保存工作目录的详细信息,只是保存了指向该目录的v节点的指针等目录本身的信息。并不保存该目录的完整路径。

我们可以通过getcwd函数来得到当前工作目录的完整路径。

char   *getcwd(char  *buf,  size_t  size)

参数一是缓冲地址的,第二个参数缓冲绝对路径长度的。

getcwd()函数实例:

getcwdtest.c:

#include "apue.h"
char* path_alloc(int* size);
int main(void)
{
    char *ptr;
    int size;
    if (chdir("/home/huangcd") < 0)
        err_sys("chdir failed");
    ptr = path_alloc(&size);  
    if (getcwd(ptr, size) == NULL)
        err_sys("getcwd failed");
    printf("cwd = %s\n", ptr);
    exit(0);
}
char * path_alloc(int *size)
{
char *p = NULL;
if(!size)
     return NULL;
p = malloc(256);
if(p)
    *size = 256;
else
    *size = 0;
return p;
}
运行结果:

root@localhost apue]# gcc -o getcwdtest.out getcwdtest.c 
[root@localhost apue]# ./getcwdtest.out 
cwd = /home/huangcd

4.23特殊设备文件

在计算机系统中,每个设备都有主设备号和此设备号。设备号用的数据类型是dev_t类型。主设备号标识设备驱动程序,次设备号标识特定的子设备。

我们可以通过major和minor这两个宏来访问主、次设备号。

系统中的每个文件的stat成员st_dev的值是文件系统的设备号。只有字符特殊文件盒块特殊文件才有st_rdev值。次值包含设计设备的设备号。

下面实例打印st_dev和st_rdev值:

devtest.c:

#include "apue.h"
#ifdef SOLARIS
#include <sys/mkdev.h>
#endif
#include <sys/sysmacros.h>

int main(int argc, char *argv[])
{
    int  i;
    struct stat buf;
    for (i = 1;i < argc; i++)
    {
        printf("%s: ",argv[i]);
        if (stat(argv[i], &buf) < 0)
        {
            err_ret("stat error");
            continue;
        }
        printf("dev = %d/%d", major(buf.st_dev), minor(buf.st_dev));
        if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode))
        {
            printf("(%s) rdev = %d/%d", (S_ISCHR(buf.st_mode)) ? "character": "block", major(buf.st_rdev), minor(buf.st_rdev));
        }
        printf("\n");
    }
    exit(0);
}

运行结果:

[root@localhost apue]# gcc -o devtest.out devtest.c 
[root@localhost apue]# ./devtest.out  / /home/huangcd /dev/tty[01]
/: dev = 8/2
/home/huangcd: dev = 8/3
/dev/tty0: dev = 0/17(character) rdev = 4/0
/dev/tty1: dev = 0/17(character) rdev = 4/1

4.24文件访问权限位小结

Constant

Description

Effect on regular file

Effect on directory

S_ISUID

set-user-ID

set effective user ID on execution

(not used)

S_ISGID

set-group-ID

if group-execute set then set effective group ID on execution; otherwise enable mandatory record locking (if supported)

set group ID of new files created in directory to group ID of directory

S_ISVTX

sticky bit

control caching of file contents (if supported)

restrict removal and renaming of files in directory

S_IRUSR

user-read

user permission to read file

user permission to read directory entries

S_IWUSR

user-write

user permission to write file

user permission to remove and create files in directory

S_IXUSR

user-execute

user permission to execute file

user permission to search for given pathname in directory

S_IRGRP

group-read

group permission to read file

group permission to read directory entries

S_IWGRP

group-write

group permission to write file

group permission to remove and create files in directory

S_IXGRP

group-execute

group permission to execute file

group permission to search for given pathname in directory

S_IROTH

other-read

other permission to read file

other permission to read directory entries

S_IWOTH

other-write

other permission to write file

other permission to remove and create files in directory

S_IXOTH

other-execute

other permission to execute file

other permission to search for given pathname in directory

最后九个常量分为三组:

S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR
S_IRWXG = S_IRGRP | S_IWGRP | S_IXGRP
S_IRWXO = S_IROTH | S_IWOTH | S_IXOTH

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值