从零开始UNIX环境高级编程(4):文件和目录

1. 函数stat、fstat、fstata和lstat

1.1 函数描述

函数原型 描述
int stat(const char *restrict path, struct stat *restrict buf); 获得与path有关的文件信息到buf
int fstat(int fd, struct stat *buf); 获得与文件描述符fd有关的文件信息到buf
int fstatat(int fd, const char *path, struct stat *buf, int flag); 返回fd有关的文件信息到buf,当flag设置为AT_SYMLINK_NOFOLLOW,功能和lstat一样;当path为绝对路径时,功能和stat一样
int lstat(const char *restrict path, struct stat *restrict buf); 和stat作用类似,只是当文件是一个符号链接时,会返回符号链接的有关信息

1.2 stat结构体

stat结构体在不同的版本上实现会有所不同,在Mac OSX 10.12.2上根据宏_DARWIN_FEATURE_64_BIT_INODE是否定义,stat对应有两种实现方式。

  • _DARWIN_FEATURE_64_BIT_INODE未定义
 struct stat { /* when _DARWIN_FEATURE_64_BIT_INODE is NOT defined */
     dev_t    st_dev;    /* device inode resides on */
     ino_t    st_ino;    /* inode's number */
     mode_t   st_mode;   /* inode protection mode */
     nlink_t  st_nlink;  /* number of hard links to the file */
     uid_t    st_uid;    /* user-id of owner */
     gid_t    st_gid;    /* group-id of owner */
     dev_t    st_rdev;   /* device type, for special file inode */
     struct timespec st_atimespec;  /* time of last access */
     struct timespec st_mtimespec;  /* time of last data modification */
     struct timespec st_ctimespec;  /* time of last file status change */
     off_t    st_size;   /* file size, in bytes */
     quad_t   st_blocks; /* blocks allocated for file */
     u_long   st_blksize;/* optimal file sys I/O ops blocksize */
     u_long   st_flags;  /* user defined flags for file */
     u_long   st_gen;    /* file generation number */
 };
  • _DARWIN_FEATURE_64_BIT_INODE已定义
 struct stat { /* when _DARWIN_FEATURE_64_BIT_INODE is defined */
     dev_t           st_dev;           /* ID of device containing file */
     mode_t          st_mode;          /* Mode of file (see below) */
     nlink_t         st_nlink;         /* Number of hard links */
     ino_t           st_ino;           /* File serial number */
     uid_t           st_uid;           /* User ID of the file */
     gid_t           st_gid;           /* Group ID of the file */
     dev_t           st_rdev;          /* Device ID */
     struct timespec st_atimespec;     /* time of last access */
     struct timespec st_mtimespec;     /* time of last data modification */
     struct timespec st_ctimespec;     /* time of last status change */
     struct timespec st_birthtimespec; /* time of file creation(birth) */
     off_t           st_size;          /* file size, in bytes */
     blkcnt_t        st_blocks;        /* blocks allocated for file */
     blksize_t       st_blksize;       /* optimal blocksize for I/O */
     uint32_t        st_flags;         /* user defined flags for file */
     uint32_t        st_gen;           /* file generation number */
     int32_t         st_lspare;        /* RESERVED: DO NOT USE! */
     int64_t         st_qspare[2];     /* RESERVED: DO NOT USE! */
 };
  • 通过一段代码来验证_DARWIN_FEATURE_64_BIT_INODE是否定义
#include "../inc/apue.h"

int main(int argc, char const *argv[])
{
#if defined(_DARWIN_FEATURE_64_BIT_INODE)
    printf("_DARWIN_FEATURE_64_BIT_INODE is defined\n");
#else
    printf("_DARWIN_FEATURE_64_BIT_INODE is not defined \n");
#endif
    return 0;
}

运行结果

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ./stat_test 
_DARWIN_FEATURE_64_BIT_INODE is defined

2. 文件类型

2.1 分类

文件分类如下:


从零开始UNIX环境高级编程(4):文件和目录_第1张图片
文件类型

文件类型可以通过结构体stat中的成员st_mode获取,不同类型对应的值都定义在头文件 /usr/include/sys/stat.h中:

 #define S_IFMT 0170000           /* type of file */
 #define        S_IFIFO  0010000  /* named pipe (fifo) */
 #define        S_IFCHR  0020000  /* character special */
 #define        S_IFDIR  0040000  /* directory */
 #define        S_IFBLK  0060000  /* block special */
 #define        S_IFREG  0100000  /* regular */
 #define        S_IFLNK  0120000  /* symbolic link */
 #define        S_IFSOCK 0140000  /* socket */
 #define        S_IFWHT  0160000  /* whiteout */
 #define S_ISUID 0004000  /* set user id on execution */
 #define S_ISGID 0002000  /* set group id on execution */
 #define S_ISVTX 0001000  /* save swapped text even after use */
 #define S_IRUSR 0000400  /* read permission, owner */
 #define S_IWUSR 0000200  /* write permission, owner */
 #define S_IXUSR 0000100  /* execute/search permission, owner */

2.2 获取文件类型 - 示例

  • code
#include "../inc/apue.h"

int main(int argc, char const *argv[])
{
    struct stat buf;
    char *ptr;

    if (argc != 2)
    {
        printf("please input a filename\n");
        return 0;
    }

    if (lstat(argv[1], &buf) < 0 )
        err_ret("lstat error");

    if (S_ISREG(buf.st_mode))
        ptr = "regular";
    else if (S_ISDIR(buf.st_mode))
        ptr = "directory";
    else if (S_ISLNK(buf.st_mode))
        ptr = "symbolic link";
    else
        ptr = "unknown mode";

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

    return 0;
}

早期的unix版本不提供S_ISxxx宏,需要先将st_mode与屏蔽字S_IFMT进行与运算,然后在和S_IFxxx常量进行比较才能得出对应的文件类型。S_ISxxx宏定义如下:

#define S_ISBLK(m)  (((m) & S_IFMT) == S_IFBLK) /* block special */
#define S_ISCHR(m)  (((m) & S_IFMT) == S_IFCHR) /* char special */
#define S_ISDIR(m)  (((m) & S_IFMT) == S_IFDIR) /* directory */
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) /* fifo or socket */
#define S_ISREG(m)  (((m) & S_IFMT) == S_IFREG) /* regular file */
#define S_ISLNK(m)  (((m) & S_IFMT) == S_IFLNK) /* symbolic link */
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)    /* socket */
  • 运行结果
zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ cc get_file_type.c -o get_file_type
zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ./get_file_type /dev/zero 
unknown mode
zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ./get_file_type get_file_type.c 
regular
zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ./get_file_type .
directory
zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ./get_file_type /dev/stdin 
symbolic link

使用ls命令查看文件属性,和程序运行结果一致

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ls -dl get_file_type.c /dev/zero . /dev/stdin 
drwxr-xr-x  6 zhanghuamao  staff       204  2 11 09:58 .
lr-xr-xr-x  1 root         wheel         0  2 11 09:39 /dev/stdin -> fd/0
crw-rw-rw-  1 root         wheel    3,   3  2 11 09:39 /dev/zero
-rw-r--r--@ 1 zhanghuamao  staff       453  2 11 10:01 get_file_type.c

3. 访问权限

3.1 文件权限

  • 可读权限

使用chmod命令去掉文件的r权限,执行cp复制文件时,会报错"cp: file.txt: Permission denied
"
,说明复制文件需要r权限

zhanghuamaodeMacBook-Pro:test zhanghuamao$ sudo chmod a-r file.txt 

zhanghuamaodeMacBook-Pro:test zhanghuamao$ cp file.txt file.txt.bk
cp: file.txt: Permission denied

给文件用户添加可读权限,复制成功

zhanghuamaodeMacBook-Pro:test zhanghuamao$ sudo chmod u+r file.txt 

zhanghuamaodeMacBook-Pro:test zhanghuamao$ ls -l file.txt
-rw-------  1 zhanghuamao  staff  0  2 11 14:15 file.txt

zhanghuamaodeMacBook-Pro:test zhanghuamao$ cp file.txt file.txt.bk

zhanghuamaodeMacBook-Pro:test zhanghuamao$ ls -l
total 0
-rw-------  1 zhanghuamao  staff    0  2 11 14:15 file.txt
-rw-------  1 zhanghuamao  staff    0  2 11 14:18 file.txt.bk

3.2 目录权限

  • 可读权限

目录要具有可读权限,才能使用ls命令

zhanghuamaodeMacBook-Pro:code zhanghuamao$ sudo chmod a-r test/ ; ls -dl test/;ls -al test/
d-wx--x--x  4 zhanghuamao  staff  136  2 11 14:22 test/
ls: : Permission denied
  • 可执行权限

目录要具有可执行权限,才能进入

zhanghuamaodeMacBook-Pro:code zhanghuamao$ sudo chmod a-x test/

zhanghuamaodeMacBook-Pro:code zhanghuamao$ ls -dl test/ ; cd test/
drw-r--r--  2 zhanghuamao  staff  68  2 11 11:21 test/
-bash: cd: test/: Permission denied

3.3 用户ID和组ID

  • 实际用户ID、实际组ID和有效用户ID、有效组ID

通常,有效用户ID = 实际用户ID,每个文件的所有者有stat中的st_uid指定;
当执行一个程序文件时,进程的有效用户ID通常就是实际用户ID。但是,当设置了特殊标志时,当执行此文件时,进程的有效用户ID = 文件所有者的用户ID

  • code
#include "apue.h"
#include 

int main(int argc, char const *argv[])
{
    struct stat buf;
    char *ptr;

    if (argc != 2)
    {
        printf("please input a filename\n");
        return 0;
    }

    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");

    return 0;
}
  • output
ckt@ubuntu:~/work/unix/code/chapter4$ cc access_test.c -o access_test
ckt@ubuntu:~/work/unix/code/chapter4$ ls -l access_test
-rwxrwxr-x 1 ckt ckt 13419 Feb 12 18:46 access_test

ckt@ubuntu:~/work/unix/code/chapter4$ ls -l /etc/shadow
-rw-r----- 1 root shadow 1129 Sep 19 23:17 /etc/shadow

ckt@ubuntu:~/work/unix/code/chapter4$ ./access_test /etc/shadow
access error for /etc/shadow: Permission denied
open error for /etc/shadow: Permission denied

ckt@ubuntu:~/work/unix/code/chapter4$ sudo chown root access_test
ckt@ubuntu:~/work/unix/code/chapter4$ sudo chmod u+s access_test

ckt@ubuntu:~/work/unix/code/chapter4$ ls -l access_test
-rwsrwxr-x 1 root ckt 13419 Feb 12 18:46 access_test
ckt@ubuntu:~/work/unix/code/chapter4$ ./access_test /etc/shadow
access error for /etc/shadow: Permission denied
open for reading OK

3.4 默认权限:umask

  • 查看默认权限

zhanghuamaodeMacBook-Pro:test zhanghuamao$ umask; umask -S
0022
u=rwx,g=rx,o=rx

umask的分数0022指的是“该默认值需要减掉的权限”,umask一共4组数字,第一组是特殊权限用的,后面3组为user、group、other的默认分值

  • 文件和目录的默认权限

用户建文件时,默认没有可执行权限,即只有r、w这两个选项,默认权限为-rw-rw-rw
新建文件时默认权限计算方式:(-rwxrw-rw-) - (------w--w) = -rw-r--r--

zhanghuamaodeMacBook-Pro:test zhanghuamao$ touch test ; ls -l
total 0
-rw-r--r--  1 zhanghuamao  staff  0  2 11 15:03 test

用户创建目录时,由于x与是否进入目录有关,因此默认3个权限都开放:-rwxrwxrwx
新建目录时默认权限计算方式:(-rwxrwxrwx) - (------w--w) = -rwxr-xr-x

zhanghuamaodeMacBook-Pro:test zhanghuamao$ mkdir dir; ls -l
total 0
drwxr-xr-x  2 zhanghuamao  staff  68  2 11 15:06 dir
-rw-r--r--  1 zhanghuamao  staff   0  2 11 15:03 test

3.5 umask函数

  • 函数原型
    mode_t umask(mode_t mask); , 其中的参数mask的值定义在/usr/include/sys/stat.h中:
#define S_IRUSR __S_IREAD   /* Read by owner.  */
#define S_IWUSR __S_IWRITE  /* Write by owner.  */
#define S_IXUSR __S_IEXEC   /* Execute by owner.  */
/* Read, write, and execute by owner.  */
#define S_IRWXU (__S_IREAD|__S_IWRITE|__S_IEXEC)

#define S_IRGRP (S_IRUSR >> 3)  /* Read by group.  */
#define S_IWGRP (S_IWUSR >> 3)  /* Write by group.  */
#define S_IXGRP (S_IXUSR >> 3)  /* Execute by group.  */
/* Read, write, and execute by group.  */
#define S_IRWXG (S_IRWXU >> 3)

#define S_IROTH (S_IRGRP >> 3)  /* Read by others.  */
#define S_IWOTH (S_IWGRP >> 3)  /* Write by others.  */
#define S_IXOTH (S_IXGRP >> 3)  /* Execute by others.  */
/* Read, write, and execute by others.  */
#define S_IRWXO (S_IRWXG >> 3)
  • code
#include "apue.h"
#include 

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

int main(int argc, char const *argv[])
{
    umask(0);
    if (creat("test", RWRWRW) < 0 )
        err_sys("create error for test");
    umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
    if (creat("test2", RWRWRW) < 0 )
        err_sys("create error for test2");
    return 0;
}
  • output
ckt@ubuntu:~/work/unix/code/chapter4$ cc umask_test.c -o umask_test

ckt@ubuntu:~/work/unix/code/chapter4$ umask 
0002

ckt@ubuntu:~/work/unix/code/chapter4$ ./umask_test
ckt@ubuntu:~/work/unix/code/chapter4$ ls -l test*
-rw-rw-rw- 1 ckt ckt 0 Feb 12 21:53 test
-rw------- 1 ckt ckt 0 Feb 12 21:53 test2

ckt@ubuntu:~/work/unix/code/chapter4$ umask
0002

3.6 chmod函数

  • code
#include "apue.h"

int main(int argc, char const *argv[])
{
    struct stat statbuf;
    if (stat("test", &statbuf) < 0 )
        err_sys("stat error for test");
    
    if (chmod("test", (statbuf.st_mode & ~S_IWGRP) |  S_IXGRP) < 0 )
        err_sys("chmod error for test");

    if (chmod("test2", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0 )
        err_sys("chmod error for test2");

    return 0;
}
  • output
ckt@ubuntu:~/work/unix/code/chapter4$ ls -l test*
-rw-rw-rw- 1 ckt ckt 0 Feb 13 00:17 test
-rw------- 1 ckt ckt 0 Feb 13 00:17 test2

ckt@ubuntu:~/work/unix/code/chapter4$ cc chmod_test.c -o chmod_test
ckt@ubuntu:~/work/unix/code/chapter4$ ./chmod_test
ckt@ubuntu:~/work/unix/code/chapter4$ ls -l test*
-rw-r-xrw- 1 ckt ckt 0 Feb 13 00:17 test
-rw-rw---- 1 ckt ckt 0 Feb 13 00:17 test2

3.7 chown函数

  • code
#include "apue.h"

int main(int argc, char const *argv[])
{
    if (chown("test", getuid(), getgid()) < 0 )
        err_sys("chmod error for test");

    return 0;
}
  • output
ckt@ubuntu:~/work/unix/code/chapter4$ cc chown_test.c -o chown_test
ckt@ubuntu:~/work/unix/code/chapter4$ ls -l test
-rw------- 1 ckt ckt 0 Feb 13 00:17 test

ckt@ubuntu:~/work/unix/code/chapter4$ sudo ./chown_test
ckt@ubuntu:~/work/unix/code/chapter4$ ls -l test
-rw------- 1 root root 0 Feb 13 00:17 test

4. 文件系统

4.1 硬链接和软链接对比

在link目录下,使用link命令给test目录下的file文件创建一个硬链接hard_link,file和hard_link的inode相同,都为1000760

zhanghuamaodeMacBook-Pro:link zhanghuamao$ link ../test/file hard_link
zhanghuamaodeMacBook-Pro:link zhanghuamao$ ls -li hard_link ../test/file 
1000760 -rw-r--r--  2 zhanghuamao  staff  0  2 12 11:36 ../test/file
1000760 -rw-r--r--  2 zhanghuamao  staff  0  2 12 11:36 hard_link

使用ls -li查看link和test目录的inode号,分别为1000766、100068

zhanghuamaodeMacBook-Pro:code zhanghuamao$ ls -li
1000766 drwxr-xr-x   2 zhanghuamao  staff   68  2 12 11:37 link
1000688 drwxr-xr-x   3 zhanghuamao  staff  102  2 12 11:36 test

再使用ln -s命令给file文件创建一个软链接soft_link,查看soft_link的inode号为1000805,和file的inode号不一样。

zhanghuamaodeMacBook-Pro:link zhanghuamao$ ln -s ../test/file soft_link
zhanghuamaodeMacBook-Pro:link zhanghuamao$ ls -il ../test/file soft_link
1000760 -rw-r--r--  2 zhanghuamao  staff   0  2 12 11:36 ../test/file
1000805 lrwxr-xr-x  1 zhanghuamao  staff  12  2 12 11:40 soft_link -> ../test/

往hard_link文件中添加内容"add by hard link",使用cat命令查看soft_link和file文件,内容都同步更新了。

zhanghuamaodeMacBook-Pro:link zhanghuamao$ cat soft_link ../test/file 
add by hard link
add by hard link

删除file文件,再次使用cat命令查看soft_link和hard_link文件,soft_link提示"No such file or directory",而hard_link文件仍然存在。

zhanghuamaodeMacBook-Pro:link zhanghuamao$ rm ../test/file 
zhanghuamaodeMacBook-Pro:link zhanghuamao$ cat soft_link hard_link 
cat: soft_link: No such file or directory
add by hard link

创建硬链接后,inode和bloack data示意图


从零开始UNIX环境高级编程(4):文件和目录_第2张图片
硬链接

当删除file文件时,hard_link仍然可以通过编号为1000760的inode访问文件内容

从零开始UNIX环境高级编程(4):文件和目录_第3张图片
硬链接 - 删除file文件后

创建软链接后,inode和bloack data示意图

从零开始UNIX环境高级编程(4):文件和目录_第4张图片
软链接

当删除file文件后,soft_link无法再通过test目录的inode号访问file文件

从零开始UNIX环境高级编程(4):文件和目录_第5张图片
软链接 - 删除file文件

4.2 获取文件的硬链接

  • code
#include "../inc/apue.h"

int main(int argc, char const *argv[])
{
    struct stat buf;
    char *ptr;

    if (argc != 2)
    {
        printf("please input a filename\n");
        return 0;
    }

    if (lstat(argv[1], &buf) < 0 )
        err_ret("lstat error");

    printf("The hard link count of %s : %d\n", argv[1], buf.st_nlink);

    return 0;
}
  • output

先ls -il查看hard_link文件的链接数为3

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ls -il ../link/hard_link*
1005313 -rw-r--r--  3 zhanghuamao  staff  0  2 12 16:20 ../link/hard_link
1005313 -rw-r--r--  3 zhanghuamao  staff  0  2 12 16:20 ../link/hard_link1
1005313 -rw-r--r--  3 zhanghuamao  staff  0  2 12 16:20 ../link/hard_link2

运行link_text程序查看hard_link文件的链接数,和ls -il得到的结果一致,都为3

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ cc link_text.c -o link_text
zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ./link_text ../link/hard_link
The hard link count of ../link/hard_link : 3

4.3 link函数

  • code
#include "../inc/apue.h"

int main(int argc, char const *argv[])
{
    struct stat buf;
    char *ptr;

    if (argc != 3)
    {
        printf("please input a filename\n");
        return 0;
    }

    link(argv[1], argv[2]);

    return 0;
}
  • output

运行程序my_link创建my_link.c的硬链接文件my_link_hard_link.txt

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ cc my_link.c -o my_link

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ls
get_file_type   link_text   my_link     stat_test
get_file_type.c link_text.c my_link.c   stat_test.c

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ./my_link my_link.c my_link_hard_link.txt

运行完成后使用ls -il查看,my_link.c和my_link_hard_link.txt的inode号一样都为1006798

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ls -il my*
1006809 -rwxr-xr-x  1 zhanghuamao  staff  13596  2 12 16:56 my_link
1006798 -rw-r--r--@ 2 zhanghuamao  staff    275  2 12 16:55 my_link.c
1006798 -rw-r--r--@ 2 zhanghuamao  staff    275  2 12 16:55 my_link_hard_link.txt

4.4 unlink函数

  • code
#include "../inc/apue.h"

int main(int argc, char const *argv[])
{
    struct stat buf;
    char *ptr;

    if (argc != 2)
    {
        printf("please input a filename\n");
        return 0;
    }

    unlink(argv[1]);

    return 0;
}
  • output

运行程序my_unlink取消掉之前创建的my_link_hard_link.txt

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ cc my_unlink.c -o my_unlink

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ./my_unlink my_link_hard_link.txt 

已经没有my_link_hard_link.txt 这支文件了

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ls -il my*
1006809 -rwxr-xr-x  1 zhanghuamao  staff  13596  2 12 16:56 my_link
1006798 -rw-r--r--@ 1 zhanghuamao  staff    210  2 12 17:05 my_link.c
1006904 -rwxr-xr-x  1 zhanghuamao  staff  13596  2 12 17:06 my_unlink
1006865 -rw-r--r--@ 1 zhanghuamao  staff    203  2 12 17:06 my_unlink.c

4.5 rename函数

  • code
#include "../inc/apue.h"

int main(int argc, char const *argv[])
{
    struct stat buf;
    char *ptr;

    if (argc != 3)
    {
        printf("please input a filename\n");
        return 0;
    }

    rename(argv[1], argv[2]);

    return 0;
}
  • output

运行程序my_mv创建硬链接前,先查看当前已使用inode个数为793518

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ cc my_mv.c -o my_mv

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ df .
Filesystem 512-blocks     Used Available Capacity iused      ifree %iused  Mounted on
/dev/disk1  487686144 65661544 421512600    14%  793518 4294173761    0%   /

运行程序my_mv创建my_mv.c的硬链接my_mv_rename.txt,查看它们的inode号都为1007929,并且已使用inode个数和创建硬链接前一样。

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ./my_mv my_mv.c my_mv_rename.txt

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ df .
Filesystem 512-blocks     Used Available Capacity iused      ifree %iused  Mounted on
/dev/disk1  487686144 65663336 421510808    14%  793518 4294173761    0%   /

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ls -il my_m*
1007936 -rwxr-xr-x  1 zhanghuamao  staff  13596  2 12 17:37 my_mv
    1007929 -rwxr-xr-x  1 zhanghuamao  staff    212  2 12 17:37 my_mv.c
1007929 -rwxr-xr-x  1 zhanghuamao  staff    212  2 12 17:37 my_mv_rename.txt

4.6 symlink函数

  • code
#include "../inc/apue.h"

int main(int argc, char const *argv[])
{
    struct stat buf;
    char *ptr;

    if (argc != 3)
    {
        printf("please input a filename\n");
        return 0;
    }

    symlink(argv[1], argv[2]);

    return 0;
}
  • output

在运行程序my_ln创建软链接前,先使用df命令查看当前已用inode个数为793532

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ cc my_ln.c -o my_ln 

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ df .
Filesystem 512-blocks     Used Available Capacity iused      ifree %iused  Mounted on
/dev/disk1  487686144 65664040 421510104    14%  793532 4294173747    0%   /

运行程序my_ln创建my_ln.c的软链接my_ln_soft_link.txt,查看它们的inode号分别是1008145和1008163

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ./my_ln my_ln.c my_ln_soft_link.txt

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ls -il my_ln*
1008156 -rwxr-xr-x  1 zhanghuamao  staff  13604  2 12 17:50 my_ln
1008145 -rw-r--r--@ 1 zhanghuamao  staff    213  2 12 17:49 my_ln.c
1008163 lrwxr-xr-x  1 zhanghuamao  staff      7  2 12 17:51 my_ln_soft_link.txt -> my_ln.c

再次使用df命令查看当前已用inode个数为793533,比运行程序my_ln前,少了一个inode号

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ df .
Filesystem 512-blocks     Used Available Capacity iused      ifree %iused  Mounted on
/dev/disk1  487686144 65663920 421510224    14%  793533 4294173746    0%   /

将my_ln.c删除,再去cat my_ln_soft_link.txt,提示错误"cat: my_ln_soft_link.txt: No such file or directory"

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ rm my_ln.c ; cat my_ln_soft_link.txt
cat: my_ln_soft_link.txt: No such file or directory

4.7 时间参数

Unix中一共有3个时间参数,这3个值被记录在stat成员变量中:

 struct timespec st_atimespec;  /* time of last access */
 struct timespec st_mtimespec;  /* time of last data modification */
 struct timespec st_ctimespec;  /* time of last file status change */
  • modification time(mtime)
    当修改文件内容时,mtime会更新,使用ls -l命令查看的时间就是mtime
ckt@ubuntu:~/work/unix/code/chapter4$ ls -l ../chapter2/limits_test.c 
-rwxr--r-- 1 ckt ckt 179 Jan 15 22:10 ../chapter2/limits_test.c
  • acess time(atime)
    当文件内容被取用时,就会更新atime。例如,使用cat去读取文件时。
    使用命令ls -l --time=atime可以查看atime
ckt@ubuntu:~/work/unix/code/chapter4$ cat ../chapter2/limits_test.c 
cat内容省略
ckt@ubuntu:~/work/unix/code/chapter4$ls -l ../chapter2/limits_test.c
-rwxr--r-- 1 ckt ckt 179 Jan 15 22:10 ../chapter2/limits_test.c

ckt@ubuntu:~/work/unix/code/chapter4$ ls -l --time=atime ../chapter2/limits_test.c 
-rwxr--r-- 1 ckt ckt 179 Feb 13 01:00 ../chapter2/limits_test.c

ckt@ubuntu:~/work/unix/code/chapter4$ date
Mon Feb 13 01:01:12 PST 2017
  • status time(ctime)
    当文件的状态改变时,就会更新这个时间,例如:权限与属性被更改了
    使用命令ls -l --time=ctime可以查看ctime
ckt@ubuntu:~/work/unix/code/chapter4$ chmod 644 ../chapter2/limits_test.c 
ckt@ubuntu:~/work/unix/code/chapter4$ ls -l --time=ctime ../chapter2/limits_test.c 
-rw-r--r-- 1 ckt ckt 179 Feb 13 01:03 ../chapter2/limits_test.c

4.8 打印设备ID

  • code
#include "apue.h"
#include 

int main(int argc, char const *argv[])
{
    struct stat buf;

    if (argc != 2)
    {
        printf("please input a filename\n");
        return 0;
    }

    if (lstat(argv[1], &buf) < 0 )
        err_ret("lstat error");

    printf("dev = %d / %d ", major(buf.st_dev), minor(buf.st_dev));
    
    if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode))
    {
        printf(", rdev = %d / %d ", major(buf.st_rdev), minor(buf.st_rdev));
    }

    printf("\n");
    return 0;
}
  • output
ckt@ubuntu:~/work/unix/code/chapter4$ cc dev_test.c -o dev_test
ckt@ubuntu:~/work/unix/code/chapter4$ ./dev_test /dev/tty1
dev = 0 / 5 , rdev = 4 / 1 
ckt@ubuntu:~/work/unix/code/chapter4$ ./dev_test dev_test
dev = 8 / 17 

5. 目录操作

5.1 mkdir函数

  • code
#include "apue.h"

#define RWXRXRX (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)

int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("please input a filename\n");
        return 0;
    }

    if (mkdir(argv[1], RWXRXRX) < 0 )
        err_ret("mkdir error");
    return 0;
}
  • output
ckt@ubuntu:~/work/unix/code/chapter4$ cc mkdir_test.c -o mkdir_test
ckt@ubuntu:~/work/unix/code/chapter4$ ./mkdir_test 222
ckt@ubuntu:~/work/unix/code/chapter4$ ls -dl 222
drwxr-xr-x 2 ckt ckt 4096 Feb 15 01:14 222

5.2 rmdir函数

  • code
#include "apue.h"

int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("please input a filename\n");
        return 0;
    }

    if (rmdir(argv[1]) < 0 )
        err_ret("rmdir error");
    return 0;
}
  • output
ckt@ubuntu:~/work/unix/code/chapter4$ cc rmdir_test.c -o rmdir_test
ckt@ubuntu:~/work/unix/code/chapter4$ ./rmdir_test 222/
ckt@ubuntu:~/work/unix/code/chapter4$ ls -dl 222
ls: cannot access 222: No such file or directory

5.3 chdir函数

  • code
#include "apue.h"

int main(int argc, char const *argv[])
{
    if (chdir("/home") < 0 )
        err_ret("chdir error");

    printf("chdir to /home succeeded\n");

    printf("current path = %s\n", get_current_dir_name());
    return 0;
}
  • output
    运行程序chdir_test后,shell显示的当前目录并没有改变,这是因为每个程序运行在独立的进程中,shell的当前工作目录并不会随着程序调用chdir而改变。但是,chdir_test程序通过调用get_current_dir_name函数,可以将当前目录名称打印出来,由此可以证明chdir已经生效
ckt@ubuntu:~/work/unix/code/chapter4$ cc chdir_test.c -o chdir_test

ckt@ubuntu:~/work/unix/code/chapter4$ ./chdir_test
chdir to /home succeeded
current path = /home

5.4 读目录

  • code
#include "../inc/apue.h"
#include 

int main(int argc, char const *argv[])
{
    DIR *dirp;
    struct dirent *dp;

    dirp = opendir("../");

    if (dirp == NULL)
        return 0;

    while ((dp = readdir(dirp)) != NULL)
    {
        printf("%s\n", dp->d_name);
    }

    return 0;
}
  • output
zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ cc readdir_test.c -o readdir_test
zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ./readdir_test 
.
..
chapter3
chapter4
file1
file2
inc
link
test

zhanghuamaodeMacBook-Pro:chapter4 zhanghuamao$ ls -l ../
total 0
drwxr-xr-x  17 zhanghuamao  staff  578  1 22 21:55 chapter3
drwxr-xr-x  21 zhanghuamao  staff  714  2 15 23:18 chapter4
-rw-r--r--   1 zhanghuamao  staff    0  2 15 23:01 file1
-rw-r--r--   1 zhanghuamao  staff    0  2 15 23:01 file2
drwxr-xr-x   4 zhanghuamao  staff  136  1 21 10:06 inc
drwxr-xr-x   8 zhanghuamao  staff  272  2 12 16:25 link
drwxr-xr-x   2 zhanghuamao  staff   68  2 12 11:43 test

参考

  • UNIX 环境高级编程 第3版
  • undefined reference to `major'

你可能感兴趣的:(从零开始UNIX环境高级编程(4):文件和目录)