HOME | Links | About | Read

《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系统,已经没有这个问题了。