第4章——《文件和目录》(2)

实验环境介绍

  • gcc:4.8.5
  • glibc:glibc-2.17-222.el7.x86_64
  • os:Centos7.4
  • kernel:3.10.0-693.21.1.el7.x86_64

函数chown、fchown、fchownat和lchown

chown
* 这几个函数都是用于修改文件的用户ID和组ID,如果owner或者group中的任意一个是-1,则对应的ID值不变
* 测试代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf(", errno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)

#define FILE_PATH "/home/manjingliu/apue/part_4/chown.tmp"
#define APCHE_ID 48
#define ME 1000

static void pr_pathconf(char *mesg,char *path, int name);


int
main(int argc, char *argv[])
{
    if(argc !=2) {
        printf("usage: a.out <dirname>\n");
        exit(EXIT_FAILURE);
    }

#ifdef _POSIX_CHOWN_RESTRICTED
    printf("_POSIX_CHOWN_RESTRICTED is defined (val is %ld)\n",(long)(_POSIX_CHOWN_RESTRICTED+0));
#else
    printf("_POSIX_CHOWN_RESTRICTED is undefined\n");
#endif

#ifdef _PC_CHOWN_RESTRICTED
    pr_pathconf("pathconf says _PC_CHOWN_RESTRICTED =", argv[1], _PC_CHOWN_RESTRICTED);
#else
    printf("no symbol for _PC_CHOWN_RESTRICTED\n");
#endif

    // 打印用户ID和组ID
    printf("uid = %d, gid = %d\n", getuid(), getgid());
    if(-1 == chown(argv[1], -1, ME)) {
        perror("chown error:");
    }
    exit(EXIT_SUCCESS);
}

static void
pr_pathconf(char*mesg, char *path, int name)
{
    fputs(mesg, stdout);
    errno = 0;
    long val =0;
    if((val = pathconf(path, name)) < 0) {
        if(errno !=0) {
            if(EINVAL == errno) {
                fputs(" (not supported)\n", stdout);
            } else {
                char*err = strerror(errno);
                printf("pathconf error, path = %s : %s\n", path, err);
            }
        } else {
            fputs(" (no limit)\n", stdout);
        }
    } else {
        printf(" %ld\n", val);
    }
}

result:
[manjingliu@localhost part_4]$ ls -l
total 16
-rwxrwxr-x 1 manjingliu manjingliu 9080 Jul 30 15:07 4_5
-rw-r--r-- 1 manjingliu manjingliu 1795 Jul 30 15:07 4_5.c
-rw-rw-r-- 1 alex alex 0 Jul 30 14:25 chown.tmp
[manjingliu@localhost part_4]$ sudo chown manjingliu chown.tmp 
[manjingliu@localhost part_4]$ ls -l
total 16
-rwxrwxr-x 1 manjingliu manjingliu 9080 Jul 30 15:07 4_5
-rw-r--r-- 1 manjingliu manjingliu 1795 Jul 30 15:07 4_5.c
-rw-rw-r-- 1 manjingliu alex 0 Jul 30 14:25 chown.tmp
[manjingliu@localhost part_4]$ 
[manjingliu@localhost part_4]$ 
[manjingliu@localhost part_4]$ ./4_5 chown.tmp 
_POSIX_CHOWN_RESTRICTED is defined (val is 0)
pathconf says _PC_CHOWN_RESTRICTED = 1
uid = 1000, gid = 1000
[manjingliu@localhost part_4]$ 

[manjingliu@localhost part_4]$ ls -l
total 16
-rwxrwxr-x 1 manjingliu manjingliu 9080 Jul 30 15:07 4_5
-rw-r--r-- 1 manjingliu manjingliu 1795 Jul 30 15:07 4_5.c
-rw-rw-r-- 1 manjingliu alex 0 Jul 30 14:25 chown.tmp
[manjingliu@localhost part_4]$ sudo ./4_5 chown.tmp 
_POSIX_CHOWN_RESTRICTED is defined (val is 0)
pathconf says _PC_CHOWN_RESTRICTED = 1
uid = 0, gid = 0
[manjingliu@localhost part_4]$
  • 基于BSD的系统功能移植规定只有超级用户才能更改一个文件的所有者。这样做是为了防止用户改变文件的所有者从而摆脱磁盘空间限额对他们的限制。而system v则允许任一用户更改他们所拥有的文件的所有者。
  • 如果_POSIX_CHOWN_RESTRICTED生效(即不管这个变量有没有在头文件中定义)
    • 那么超级用户可以更改这个文件的用户id
    • 如果进程拥有此文件(进程的有效用户id等于该文件的用户id),参数owner等于-1或者文件的用户id,并且group参数等于进程的有效组ID或进程的附属组ID之一,那么非超级用户也能修改
      这意味着,当_POSIX_CHOWN_RESTRICTED起作用时,不能更改其他用户文件的用户ID。你可以更改你所拥有的文件的组ID,但只能改到你所属的组。如果这些函数由非超级用户进程调用,则在成功返回时,该文件的设置用户ID位和设置组ID位会被清除。

文件长度

  • stat结构成员st_size表示以字节为单位的文件长度,这个字段只对普通文件、目录文件和符号链接有意义
  • UNIX系统提供字段st_blksize和st_blocks,第一个是对文件I/O较合适的块长度,第二个是所分配的实际st_blksize字节快块数。当st_blksize用于读操作时,读一个文件所需的时间量最少。为了提高效率,标准I/O库(第5章说明)也试图一次性读写st_blksize个字节。
文件中的空洞
  • 测试代码如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


/* struct stat info */
// 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 */
// };


int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    struct stat sb;
    if (stat(argv[1], &sb) == -1) {
        err_sys("stat");
        exit(EXIT_FAILURE);
    }

    printf("File type: ");

    switch (sb.st_mode & S_IFMT) {
    case S_IFBLK: printf("block device\n"); break;
    case S_IFCHR: printf("character device\n"); break;
    case S_IFDIR: printf("directory\n"); break;
    case S_IFIFO: printf("FIFO/pipe\n"); break;
    case S_IFLNK: printf("symlink\n"); break;
    case S_IFREG: printf("regular file\n"); break;
    case S_IFSOCK: printf("socket\n"); break;
    default: printf("unknown?\n"); break;
    }

    printf("I-node number: %ld\n", (long) sb.st_ino);

    printf("Mode: %lo (octal)\n",
           (unsigned long) sb.st_mode);

    printf("Link count: %ld\n", (long) sb.st_nlink);
    printf("Ownership: UID=%ld GID=%ld\n",
           (long) sb.st_uid, (long) sb.st_gid);

    printf("Preferred I/O block size: %ld bytes\n",
           (long) sb.st_blksize);
    printf("File size: %lld bytes\n",
           (long long) sb.st_size);
    printf("Blocks allocated: %lld\n",
           (long long) sb.st_blocks);

    printf("Last status change: %s", ctime(&sb.st_ctime));
    printf("Last file access: %s", ctime(&sb.st_atime));
    printf("Last file modification: %s", ctime(&sb.st_mtime));

    exit(EXIT_SUCCESS);
}

result:
[manjingliu@localhost part_4]$ od -c file.hole 
0000000 a b c d e f g h i j \0 \0 \0 \0 \0 \0
0000020 \0 \0 \0 \0 A B C D E F G H I J
0000036

[manjingliu@localhost part_4]$ ./4_4 file.hole 
File type: regular file
I-node number: 50406400
Mode: 100664 (octal)
Link count: 1
Ownership: UID=1000 GID=1000
Preferred I/O block size: 4096 bytes
File size: 30 bytes
Blocks allocated: 8
Last status change: Mon Jul 30 21:04:16 2018
Last file access: Mon Jul 30 21:10:53 2018
Last file modification: Mon Jul 30 21:04:16 2018
  • du命令
du --apparent-size:指的是文件本身的大小
[manjingliu@localhost part_4]$ du --apparent-size --block-size=1 file.hole 
30 file.hole
[manjingliu@localhost part_4]$ du --apparent-size --block-size=2 file.hole  
15 file.hole

du -s:是指文件占用磁盘空间的大小
[manjingliu@localhost part_4]$ du -s --block-size=2 file.hole               
2048 file.hole
[manjingliu@localhost part_4]$ du -s --block-size=1 file.hole  
4096 file.hole

du -b等价于du --apparent-size --block-size=1

文件截断

文件截断
* 忽略

文件系统

文件系统基本结构
  • 我们可以把一个硬盘分成一个或多个分区,每个分区包含一个文件系统
  • 以下图片理解一下
    文件系统
    文件系统2

  • 创建新的目录(mkdir testdir)
    创建新的目录

函数link、linkat、unlink、unlinkat和remove

  • 如何确保程序崩溃时,也能对一个临时文件进行删除
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (open(argv[1], O_RDWR) < 0)
        err_sys("open");

    if (unlink(argv[1]) < 0)
        err_sys("unlink");

    printf("file unlinked\n");

    sleep(60);
    printf("done\n");
    exit(EXIT_SUCCESS);
}

result:
[manjingliu@localhost part_4]$ ./unlink tmp
tmp tmp.iso  
[manjingliu@localhost part_4]$ ./unlink tmp.iso &
[1] 13568
[manjingliu@localhost part_4]$ file unlinked
dd if=/dev/zero of=tmp.iso bs=1df -h ./            
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 17G 5.2G 12G 31% /
[manjingliu@localhost part_4]$ df -h ./
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 17G 5.2G 12G 31% /
[manjingliu@localhost part_4]$ df -h ./
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 17G 5.2G 12G 31% /
[manjingliu@localhost part_4]$ ps -ef | grep unlink
manjing+ 13568 12731 0 23:19 pts/1 00:00:00 ./unlink tmp.iso
manjing+ 13573 12731 0 23:19 pts/1 00:00:00 grep --color=auto unlink
[manjingliu@localhost part_4]$ kill 13568
[manjingliu@localhost part_4]$ df -h ./            
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 17G 5.1G 12G 30% /
[1]+ Terminated ./unlink tmp.iso

使用remove测试
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (open(argv[1], O_RDWR) < 0)
        err_sys("open");

    if (remove(argv[1]) < 0)
        err_sys("unlink");

    printf("file unlinked\n");

    sleep(60);
    printf("done\n");
    exit(EXIT_SUCCESS);
}
[manjingliu@localhost part_4]$ !dd
dd if=/dev/zero of=oo.org bs=516581760 count=1
1+0 records in
1+0 records out
516581760 bytes (517 MB) copied, 6.97637 s, 74.0 MB/s
[manjingliu@localhost part_4]$ df -h ./            
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 17G 5.6G 12G 33% /
[manjingliu@localhost part_4]$ ./remove oo.org &
[1] 13965
[manjingliu@localhost part_4]$ file unlinked
此时由于文件还是被打开的,所以没有被真正的删除,单文件关闭后就会被真正删除
df -h ./         
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 17G 5.6G 12G 33% /
[manjingliu@localhost part_4]$ ps -ef | grep remove
manjing+ 13965 13860 0 20:35 pts/3 00:00:00 ./remove oo.org
manjing+ 13968 13860 0 20:35 pts/3 00:00:00 grep --color=auto remove
[manjingliu@localhost part_4]$ kill 13965
[manjingliu@localhost part_4]$ df -h ./            
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 17G 5.1G 12G 30% /
[1]+ Terminated ./remove oo.org
[manjingliu@localhost part_4]$

进程用open或者creat打开一个文件,然后立即调用unlink,他所创建的临时文件不会遗留下来

函数rename和renameat

#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


int
main(int argc, char *argv[])
{
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <pathname> <pathname2>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    int fd = rename(argv[1], argv[2]);
    if (fd < 0)
        err_sys("remove");
    exit(EXIT_SUCCESS);
}

[manjingliu@localhost part_4]$ ls tmp* -l
-rw-rw-r-- 1 manjingliu manjingliu 0 Jul 31 21:03 tmp
-rw-rw-r-- 1 manjingliu manjingliu 0 Jul 31 21:03 tmp2
-rw-rw-r-- 1 manjingliu manjingliu 0 Jul 31 21:03 tmp.exsit
lrwxrwxrwx 1 manjingliu manjingliu 4 Jul 31 21:04 tmp.link -> link

tmp.exsit.dir:
total 0
[manjingliu@localhost part_4]$ ./renamt tmp tmp.exsit
[manjingliu@localhost part_4]$ ./renamt tmp2 tmp.exsit.dir
remove
errno:21 Is a directory
[manjingliu@localhost part_4]$ ./renamt tmp.link tmp.link.new
[manjingliu@localhost part_4]$ ls -l tmp*
-rw-rw-r-- 1 manjingliu manjingliu 0 Jul 31 21:03 tmp2
-rw-rw-r-- 1 manjingliu manjingliu 0 Jul 31 21:03 tmp.exsit
lrwxrwxrwx 1 manjingliu manjingliu 4 Jul 31 21:04 tmp.link.new -> link

tmp.exsit.dir:
total 0
[manjingliu@localhost part_4]$
  • 如果源文件是目录
    • 如果目标文件是个目录且为空,则可以重命名
    • 如果目标文件是个目录且不为空,则提示目录已经存在
    • 如果目标文件不是目录,则提示目标文件不是目录
  • 如果源文件不是目录
    • 如果目标文件是目录,则无法重命名
    • 如果目标文件不是目录,则删除目标文件后,再重命名

符号链接

  • 不同系统中的函数对于符号链接的跟随可能不一样
    符号链接
  • 对于creat函数O_EXCL的注意
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)


int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    int fd = open(argv[1], O_CREAT | O_EXCL, 0666);
    if (fd < 0)
        err_sys("open");
    close(fd);
    exit(EXIT_SUCCESS);
}

result:
[manjingliu@localhost part_4]$ ./open_excl manjingliu
[manjingliu@localhost part_4]$ ./open_excl manjingliu
open
errno:17 File exists

这种处理方式是为了具有特权的进程被诱骗写了错误的文件

  • ftw()函数
#include <sys/stat.h>
#include <unistd.h>
#include <ftw.h>
#include <stdlib.h>
#include <stdio.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)

int fn(const char *file, const struct stat *sb, int flag)
{
 if(flag == FTW_D)  
  printf("%s --- directory\n", file);
 else if (flag == FTW_F)
  printf("%s --- common files\n", file);
 else if (flag == FTW_DNR)
  printf("%s --- can not reachable\n", file);
 else if (flag == FTW_SL)
  printf("%s --- symbol", file);
 else if (flag == FTW_NS)
  printf("%s --- can not get stat", file);
    return 0;
}

int main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

 ftw(argv[1], fn, 500);
 exit(EXIT_SUCCESS);
}

result:
[manjingliu@localhost part_4]$ ./ftw ./tmp.dir1/
./tmp.dir1 --- directory
./tmp.dir1/file --- common files

创建和读取符号链接

创建和读取符号链接
* 忽略
* readlink和readlinkat函数,测试如下

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define err_sys(fmt, arg...) \
do { \
    printf(fmt, ##arg);\
    printf("\nerrno:%d %s\n", errno, strerror(errno));\
    exit(EXIT_FAILURE);\
} while (0)

#define BUF_SIZE 1024

int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    char buf[BUF_SIZE] = {0};
    ssize_t size = readlink(argv[1], buf, BUF_SIZE);
    printf("size = %d, buf = %s\n", size, buf);
 exit(EXIT_SUCCESS);

result:
[manjingliu@localhost part_4]$ ./readlink tmp.link.new 
size = 4, buf = link
[manjingliu@localhost part_4]$ ls -l tmp.link.new 
lrwxrwxrwx 1 manjingliu manjingliu 4 Jul 31 21:04 tmp.link.new -> link

文件的时间

  • 不同文件系统对文件属性stat结构所保存的精度是不一样的
  • 每个文件系统维护三个时间字段,意义如下:
    文件的时间
# ls -lc filename 列出文件的 ctime,按照ctime先后排序显示
# ls -lu filename 列出文件的 atime,按照atime先后排序显示
# ls -l filename 列出文件的 mtime,按照mtime先后排序显示

[manjingliu@localhost part_4]$ ls -lc time.file 
-rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 15:58 time.file
[manjingliu@localhost part_4]$ ls -lu time.file 
-rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 15:58 time.file
[manjingliu@localhost part_4]$ ls -l time.file  
-rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 15:58 time.file
[manjingliu@localhost part_4]$ cat time.file 
[manjingliu@localhost part_4]$ ls -l time.file 
-rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 15:58 time.file
[manjingliu@localhost part_4]$ ls -lu time.file   
-rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 15:59 time.file
[manjingliu@localhost part_4]$ ls -lc time.file    
-rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 15:58 time.file
[manjingliu@localhost part_4]$ echo lll > time.file 
[manjingliu@localhost part_4]$ ls -lc time.file     
-rw-rw-r-- 1 manjingliu manjingliu 4 Aug 1 15:59 time.file
[manjingliu@localhost part_4]$ ls -lu time.file     
-rw-rw-r-- 1 manjingliu manjingliu 4 Aug 1 15:59 time.file
[manjingliu@localhost part_4]$ ls -l time.file      
-rw-rw-r-- 1 manjingliu manjingliu 4 Aug 1 15:59 time.file


  • 几个时间的区别:
    • st_mtim(修改时间)和st_ctim(状态更改时间)的区别:修改时间是文件最后一次被修改的时间,状态更改时间是该文件的i节点最后一次呗修改的时间(更改文件的访问权限、更改用户ID、更改连接数等都会修改状态更改时间)。但是他们并没有更改文件的时机内容,因为i节点中的所有信息与文件的时机内容分开存放的。所以除了要记录数修改的时间外,还要记录状态更改的时间,也就是i节点中的时间

系统不维护对i节点的最后一次访问时间,所以access和stat函数并不更改这3个时间中的任一个

  • 与目标文件和父目录的三个时间相关的函数如下:

  • 影响时间的函数

    函数futimens、utimensat和utimes

    • 修改文件的访问时间和修改时间的函数
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    
    #define err_sys(fmt, arg...) \
    do { \
        printf(fmt, ##arg);\
        printf("\nerrno:%d %s\n", errno, strerror(errno));\
        exit(EXIT_FAILURE);\
    } while (0)
    
    #define err_ret(fmt, arg...) \
    do { \
        printf(fmt, ##arg);\
        printf("\nerrno:%d %s\n", errno, strerror(errno));\
    } while (0)
    
    
    int
    main(int argc, char *argv[])
    {
        if (argc == 1) {
            fprintf(stderr, "Usage: %s <pathname> [pathname] [pathname]\n", argv[0]);
            exit(EXIT_FAILURE);
        }
    
        int fd;
        struct stat statbuf;
        struct timespec times[2];
    
        for (int i = 1; i < argc; i++) {
            if (stat(argv[i], &statbuf) < 0) {
                err_ret("stat");
                continue;
            }
    
            if ((fd = open(argv[i], O_RDWR | O_TRUNC)) < 0) {
                err_ret("open error");
                continue;
            }
    
            times[0] = statbuf.st_atim;
            times[1] = statbuf.st_mtim;
            if (futimens(fd, times) < 0) {
                err_ret("%s: futimens error");
                continue;
            }
            close(fd);
        }
        exit(EXIT_FAILURE);
    }
    [manjingliu@localhost part_4]$ ls -lt time.file 
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 16:39 time.file
    [manjingliu@localhost part_4]$ ls -l time.file  
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 16:39 time.file
    [manjingliu@localhost part_4]$ ls -lc time.file  
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 16:39 time.file
    [manjingliu@localhost part_4]$ ./futimens_1 time.file         
    [manjingliu@localhost part_4]$ ls -lc time.file       
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 17:13 time.file
    [manjingliu@localhost part_4]$ ls -l time.file        
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 16:39 time.file
    [manjingliu@localhost part_4]$ ls -lt time.file        
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 16:39 time.file
    
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <utime.h>
    
    #define err_sys(fmt, arg...) \
    do { \
        printf(fmt, ##arg);\
        printf("\nerrno:%d %s\n", errno, strerror(errno));\
        exit(EXIT_FAILURE);\
    } while (0)
    
    #define err_ret(fmt, arg...) \
    do { \
        printf(fmt, ##arg);\
        printf("\nerrno:%d %s\n", errno, strerror(errno));\
    } while (0)
    
    
    int
    main(int argc, char *argv[])
    {
        if (argc == 1) {
            fprintf(stderr, "Usage: %s <pathname> [pathname] [pathname]\n", argv[0]);
            exit(EXIT_FAILURE);
        }
    
        int fd;
        struct stat statbuf;
        struct timespec times[2];
        struct utimbuf timebuf;
    
        for (int i = 1; i < argc; i++) {
            if (stat(argv[i], &statbuf) < 0) {
                err_ret("stat");
                continue;
            }
    
            if ((fd = open(argv[i], O_RDWR | O_TRUNC)) < 0) {
                err_ret("open error");
                continue;
            }
            close(fd);
    
            timebuf.actime = statbuf.st_atime;
            timebuf.modtime = statbuf.st_mtime;
            if (utime(argv[1], &timebuf) < 0) {
                err_ret("futimens error");
                continue;
            }
    
        }
        exit(EXIT_FAILURE);
    }
    [manjingliu@localhost part_4]$ ls -l time.file 
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 17:23 time.file
    [manjingliu@localhost part_4]$ ls -lc time.file 
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 17:23 time.file
    [manjingliu@localhost part_4]$ ls -lt time.file  
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 17:23 time.file
    [manjingliu@localhost part_4]$ ./utimes time.file 
    [manjingliu@localhost part_4]$ ls -lt time.file   
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 17:23 time.file
    [manjingliu@localhost part_4]$ ls -lc time.file   
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 17:30 time.file
    [manjingliu@localhost part_4]$ ls -l time.file    
    -rw-rw-r-- 1 manjingliu manjingliu 0 Aug 1 17:23 time.file
    
    注意代码中stat的成员
    #if defined __USE_MISC || defined __USE_XOPEN2K8
        /* Nanosecond resolution timestamps are stored in a format
           equivalent to 'struct timespec'. This is the type used
           whenever possible but the Unix namespace rules do not allow the
           identifier 'timespec' to appear in the <sys/stat.h> header.
           Therefore we have to handle the use of this header in strictly
           standard-compliant sources special. */
        struct timespec st_atim; /* Time of last access. */
        struct timespec st_mtim; /* Time of last modification. */
        struct timespec st_ctim; /* Time of last status change. */
    # define st_atime st_atim.tv_sec /* Backward compatibility. */
    # define st_mtime st_mtim.tv_sec
    # define st_ctime st_ctim.tv_sec
    #else
        __time_t st_atime; /* Time of last access. */
        unsigned long int st_atimensec; /* Nscecs of last access. */
        __time_t st_mtime; /* Time of last modification. */
        unsigned long int st_mtimensec; /* Nsecs of last modification. */
        __time_t st_ctime; /* Time of last status change. */
        unsigned long int st_ctimensec; /* Nsecs of last status change. */
    #endif

    创建、删除目录、读目录

    • 略过
      创建目录
      删除目录
    • 测试代码
    #include <sys/types.h>
    #include <dirent.h>
    #include <unistd.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    #define err_sys(fmt, arg...) \
    do { \
        printf(fmt, ##arg);\
        printf("\nerrno:%d %s\n", errno, strerror(errno));\
        exit(EXIT_FAILURE);\
    } while (0)
    
    int
    main(int argc, char *argv[])
    {
        if (argc != 2) {
            fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
            exit(EXIT_FAILURE);
        }
    
        DIR * dir;
        struct dirent * ptr;
        dir = opendir(argv[1]);
        while((ptr = readdir(dir)) != NULL) {
            printf("d_name : %s\n", ptr->d_name);
        }
        closedir(dir);
    }
    
    [manjingliu@localhost part_4]$ ./readdir ./
    d_name : .
    d_name : ..
    d_name : 4_5.c
    d_name : chown.tmp
    d_name : 4_5
    d_name : time.file
    d_name : futimens_1.c
    d_name : utimes.c
    d_name : futimens_1
    d_name : utimes
    d_name : readdir

    函数chdir、fchdir、getcwd

    路径
    * 省略

    设备特殊文件

    • stat结构中有两个结构(18章再来研究):文件系统所在的存储设备都由主、次设备号表示。主设备号,标识设备驱动程序, 次设备号表示特定的子设备,同一个磁盘驱动器上的个文件系统通常具有相同的主设备号,但次设备号不同
      • st_dev
      • st_rdev
    • 一般用major和minor来访问主、次设备号
    • 测试代码
    #include <sys/types.h>
    #include <dirent.h>
    #include <unistd.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/stat.h>
    
    #ifdef SOLARIS
    #include <sys/mkdev.h>
    #endif
    
    #define err_sys(fmt, arg...) \
    do { \
        printf(fmt, ##arg);\
        printf("\nerrno:%d %s\n", errno, strerror(errno));\
    } while (0)
    
    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_sys("stat");
                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(EXIT_SUCCESS);
    }
    result:
    [manjingliu@localhost part_4]$ ./dev /home/manjingliu/ /dev/tty[01]
    /home/manjingliu/: dev = 253/0
    /dev/tty0: dev = 0/5 (character) rdev = 4/0
    /dev/tty1: dev = 0/5 (character) rdev = 4/1
    
    两个终端设备(st_dev)的文件名和i节点在设备0/5上(devtmpfs伪文件系统,他实现了/dev文件系统),但实际设备号是4/04/1

    文件权限权限位

    权限位

    猜你喜欢

    转载自blog.csdn.net/u012570105/article/details/81322459
    今日推荐