《Unix/Linux编程实践教程》笔记(3)
Table of Contents
内容
本节主要讲了unix操作系统如何将文件和目录组织起来。文件依靠inode来区分,目录是一个包含文件名和inode的集合,每个目录都有2个特殊的目录 . 和 .. ,它们分别表示当前目录和上一层目录,只有根目录的 . 和 .. 指向同一个目录。
inode中有数据块的编号,数据块储存文件的内容,数据块还有二级,三级之分(不同操作系统的实现不同)。也就是说,当我们打开一个文件,内核会在目录中找到文件相应的inode号,通过inode号找到储存文件的数据块,从数据块中读取文件内容。
与目录相关的系统调用有
- mkdir(pathname, mode) 创建目录
- readir(path) 删除非空目录
- unlink(path) 删除一个链接
- link(orig, new) 创建一个文件的新链接
- rename(from, to) 重命名或删除一个链接
习题
4.15 使mkdir支持递归创建目录
递归创建,即一层层的创建不存在的目录,用系统函数access来探测是否存在目录。具体代码如下:
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main (int ac, char *av[])
{
char pathname[128];
int i, len;
memset(pathname, '\0', 128);
if (ac == 1)
{
printf("useage: ./mkdir dirname\n");
exit(-1);
}
if (ac == 3 && (strcmp(av[1],"-p") == 0) )
{
//printf("av[1]is %s\n", av[1]);
strcpy(pathname, av[2]);
//printf ("pathname is %s", pathname);
//if (pathname[0] == '/')
// printf ("pathname[0] is %c", pathname[0]);
i = 1;
len = strlen(pathname);
while (i < len -1)
{
if (pathname[i] == '/') // / 是linux下的目录分割符
{
pathname[i] = '\0';
if (access(pathname, F_OK) != 0) //如果目录不存在,则创建
{
if (mkdir(pathname, 0755) != 0)
{
perror ("cannot mkdir");
exit(-1);
}
printf ("mkdir %s\n", pathname);
}
pathname[i] = '/';
}
i++;
}
if(mkdir(pathname, 0755) != 0)
{
perror("cannot mkdir");
exit(-1);
}
printf ("mkdir %s\n", pathname);
}
return 0;
}
4.16 使rename支持两个参数
使rename支持两个参数,第一个参数必须是文件,第二个可为文件或目录,不会覆盖。代码如下
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <libgen.h>
int main (int ac, char *av[])
{
struct stat info;
char *pathtofile;
if (ac != 3)
{
perror("ac");
exit(-1);
}
//如果第一个文件不存在,则退出
if (stat(av[1], &info) == -1)
{
perror("stat");
exit(-1);
}
if (!S_ISREG(info.st_mode))
{
printf ("av[1] must be regular file\n");
exit(-1);
}
//如果第二个参数不存在于系统
if (stat(av[2], &info) == -1)
{
//如果dirname存在,则把第二个参数当成文件路径
char *tmpchar = strdup(av[2]);
if (stat(dirname(tmpchar), &info) == -1)
{
perror("stat dirname av[2]");
exit(-1);
}
if (S_ISDIR(info.st_mode))
{
//printf("av[2] is %s", av[2]);
rename(av[1], av[2]);
}
return 0;
}
//如果第二个参数存在于系统且是目录,类似于cp的处理
if (S_ISDIR(info.st_mode))
{
int len = strlen(av[2]);
char *filename = basename(av[1]);
pathtofile = (char *)malloc(strlen(av[1])+len+2);
memset(pathtofile, 0, strlen(filename)+len+2);
strcat(pathtofile, av[2]);
if (pathtofile[len-1] != '/')
strcat(pathtofile, "/");
strcat(pathtofile, filename);
rename(av[1], pathtofile);
return 0;
}
else{
//如果第二个参数存在于系统且是文件, 不做操作,退出
if (S_ISREG(info.st_mode))
{
printf("%s is existed\n",av[2]);
exit(-1);
}
}
return 0;
}
项目
结束
本章简单讲了文件系统的内部结构。4.5.2的pwd遇到一个问题,一个文件系统的根的当前目录inode和父目录inode是相同的,然而它并不是/目录。我查看了我当前的linux系统,已经没有这个问题了。