实验环境介绍
- 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
* 这几个函数都是用于修改文件的用户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
文件截断
* 忽略
文件系统
文件系统基本结构
- 我们可以把一个硬盘分成一个或多个分区,每个分区包含一个文件系统
以下图片理解一下
创建新的目录(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节点中的时间
- 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/0和4/1