实验二Linux文件系统

本文章转载处

实验2 linux文件系统

一、实验目的
1.理解文件系统的基本概念;
2.掌握文件系统的基本操作的实现;
3.能够利用利用文件系统的操作对实际问题进行分析建模,利用计算机求解。
二、实验预备知识
1.复习C/C++语言相关知识(如:数组的和结构体定义和使用),格式化输出等;
三、实验内容
实验一
1.创建文件file1,写入字符串“abcdefghijklmn”;
2.创建文件file2,写入字符串“ABCDEFGHIJKLMN”;
3.读取file1中的内容,写入file2,使file2中的字符串内容为“ ABCDEFGHIJKLMNabcdefghijklmn”

利用Linux进行C程序开发,首先需要了解程序要求,理清思路。

按照要求,我们需要用open创建两个文件file1和file2.利用write将字符串“abcdefghijklmn”写入file1中,同理创建file2,将“ABCDEFGHIJKLMN”写入file2;最后结合lseek函数,将file中的字符串读出,写入file2;

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int main()
{
	int fd1,fd2;
	char str[14];
	fd1 = open("file1",O_RDWR|O_CREAT,S_IRWXU);
	
	if(fd1 < 0)
	  perror("open");
	
	write(fd1,"abcdefghijklmn",14);
	lseek(fd1,0,SEEK_SET);
 
	fd2 = open("file2",O_RDWR|O_CREAT,S_IRWXU);
	
	if(fd2 < 0)
	  perror("open");
	lseek(fd2,14,SEEK_END);
	write(fd2,"ABCDEFGHIJKLMN",14);
 
	read(fd1,str,14);
	lseek(fd2,0,SEEK_SET);
	write(fd2,str,14);
 
	close(fd1);
	close(fd2);
 
	system("cat file2");
        printf("\n");
	system("rm -f file1 file2");
 
	return 0;
}

通过阅读代码我们可以发现,在创建file2之后,我用了lseek函数,并且将偏移量设为14,这样做的目的是增大file2的文件大小,否则会产生文件覆盖,写入的小写字符串将大写字符串覆盖,导致实验失败。

利用lseek函数”扩充“文件时,应格外注意一点:lseek函数”扩充“文件后,并不能直接使得文件大小改变,需要在下一个写操作之后才能使文件变大。即第23句和第24句的位置不能互换,否则文件内容会发生覆盖。

system函数内的语句会被终端执行。

实验二
 编写代码,完成以下功能:
 1.创建新文件,该文件具有用户读写权限。
 2.采用dup/dup2/fcntl复制一个新的文件描述符,通过新文件描述符向文件写入“class_name”字符串;
 3.通过原有的文件描述符读取文件中的内容,并且打印显示;

由题目可知,我们需要创建一个文件file,然后用dup/dup2/fcntl中的任意一种方式,复制file的文件描述符,通过新的文件描述符将自己的班级名写入file中,最后通过原来的文件描述符读取文件信息。

通过对文件描述符的相关知识的了解,我们知道一个文件描述符只能对应一个文件,而多个文件描述符可以指向同一个文件。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
	int fd,fd1;
	char *str = "yidongyiban";
 
	fd = open("file",O_CREAT|O_RDWR);
	if(fd < 0)
	  perror("open");
 
	fd1 = dup(fd);
	if(fd1 < 0)
	  perror("dup");
 
	write(fd1,str,strlen(str));
	lseek(fd,0,SEEK_SET);
 
	char buf[12];
	read(fd,buf,12);
	printf("The buf is:%s\n",buf);
 
	close(fd);
	close(fd1);
 
	system("rm -f file");
	return 0;
}

实验三
 编写程序实现以下功能:
 1.输入文件名称,能够判断文件类型,判断实际用户对该文件具有哪些存取权限;
 2.要求打印出文件类型信息,inode节点编号,链接数目,用户id,组id,文件大小信息;
 3.修改文件的权限为当前用户读写,组内用户读写,组外用户无权限。

首先,在编写程序之前,我们需要了解如何给程序输入文件名称。利用scanf函数当然能够实现,但是在C语言中,还有一个更加方便的方法能够为程序传递所需参数。

在以前的学习中,我们可能认为main函数是没有参数的,因为main的写法是int main(),但是main函数是有且只有两个参数的。

C语言规定main函数的参数为argc和argv。其中,argc代表参数的个数,必须为int型;argv[]储存了函数的参数,必须为字符串类型的指针数组。因此,main函数的函数头可以写为:main(int argc,char *argv[])或main(int argc,char **argv)。

其中,argv[0]中储存的是程序的全名,argv[1]为第一个参数,argv[2]为第二个参数…
接下来,一个简单的程序能帮助理解:

#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
	for(int i = 0; i < argc; i++)
	{
		printf("The argv[%d] is:%s\n ",i,argv[i]);		
	}
	return 0;
}

程序运行结果:

通过这个简单的程序,能够很清楚的看出argc和argv[]的含义

我们可以通过argv[]文件名传递到程序

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(int argc,char *argv[])
{
	if(argc < 2)
	{
		printf("Please input the filename!\n");
		return 0;
	}
 
	struct stat statbuf;
	int i;
	for(i = 1;i < argc;i++)
	{
		if(lstat(argv[i],&statbuf) < 0)
			perror("lstat");
 
		char *buf;
	
		if(S_ISREG(statbuf.st_mode))
			buf = "Regular file!";
		else if(S_ISDIR(statbuf.st_mode))
			buf = "Directory file!";
		else if(S_ISCHR(statbuf.st_mode))
			buf = "Char file!";
		else
			buf = "Other file!";
		printf("The %s is:%s\n",argv[i],buf);
 
		printf("The %s mode is:%d\n",argv[i],statbuf.st_mode);
		printf("The %s inode is:%d\n",argv[i],statbuf.st_ino);
		printf("The %s uid is:%d\n",argv[i],statbuf.st_uid);
		printf("The %s gid is:%d\n",argv[i],statbuf.st_gid);
		printf("The %s size is:%d\n",argv[i],statbuf.st_size);
		printf("The %s link num is:%d\n",argv[i],statbuf.st_nlink);
	}
 
	for(i = 1;i < argc;i++)
	{
		if(access(argv[i],R_OK))
		  printf("The user can read the %s\n",argv[1]);
		else if(access(argv[i],W_OK))
		  printf("The user can write the %s\n",argv[1]);
		else if(access(argv[i],X_OK))
		  printf("The user can read and write the %s\n",argv[1]);
 
	}
 
	for(i = 1;i < argc;i++)
	{
		if(chmod(argv[i],0660) < 0)
			perror("chmod");
		else
			printf("The file.mode chmod successful!\n");
	}
 
	return 0;
}

可能有人注意到了我在修改文件权限时用到了0660这样的一串数字,那么它的含义是什么呢?

0xxxx是文件权限的另一种表示方法,一般Linux文件或目录权限分为三个,当前用户,组内用户和组外用户。每个都有三个权限rwx,即读,写,执行权限。
权限的表示方法有两种,一是直观法,即直接用rwx表示,另外一种是二进制数值法,如:644,755等。读是4,写是2,执行是1,三个相加得7,以此类推,如果是6,则表示读,写,没有执行权限。

当运行程序但并没有传入参数时,程序退出并提示输入文件名

实验四
 编写程序实现以下功能:
 1.新建文件,设置文件权限屏蔽字为0;
 2.建立该文件的硬链接文件,打印硬链接文件的inode节点号和文件大小;
 3.建立该文件的软链接文件,打印软链接文件的inode节点号和文件大小;打印软链接文件中的内容;
 4.打印源文件的inode节点号,文件大小和链接数目;
 5.调用unlink对源文件进行操作,打印源文件链接数目;

在进行程序编写之前,我们应当了解文件的软链接和硬链接的含义及两者的区别。

1.软链接,以路径的形式存在。类似于Windows操作系统中的快捷方式
2.软链接可以 跨文件系统 ,硬链接不可以
3.软链接可以对一个不存在的文件名进行链接
4.软链接可以对目录进行链接

软链接文件存放的内容是原文件的路径名。

硬链接:硬链接文件是对原文件的文件名

Linux下的每个文件都具有各自的权限位,用户要想对文件进行某种操作,就必须具有相应权限。Linux下的文件权限位如下表所示:
st_mode 含义
S_IRUSR 当前用户读(0400)
S_IWUSR 当前用户写(0200)
S_IXUSR 当前用户执行(0100)
S_IRWXU 当前用户读、写、执行(0700)
S_IRGRP 组内用户读(0040)
S_IWGRP 组内用户写(0020)
S_IXGRP 组内用户执行(0010)
S_IRWXG 组内用户读、写、执行(0070)
S_IROTH 组外用户读(0004)
S_IWOTH 组外用户写(0002)
S_IXOTH 组外用户执行(0001)
S_IRWXO 组外用户读、写、执行(0007)

当用户创建一个文件时,需要为新的文件指定一个权限字,在实际应用中,系统有时不希望用户设置所有的权限。因此可以通过umask函数设置权限屏蔽字,直接将不需要用户干预的文件权限进行屏蔽,这样即使用户设置了相关文件权限位,系统也会将其忽略,仍然将其设为0;


#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
	umask(0);
	struct stat statbuf;
	int fd = open("file",O_CREAT|O_RDWR);
	if(fd < 0)
	  perror("open");
 
	char *str = "hello world";
	if(write(fd,str,strlen(str)) < 0)
	  perror("write");
	
	link("./file","./hard_link");
 
	
	if(lstat("hard_link",&statbuf) < 0)
	  perror("lstat");
 
	printf("The hard_link's inode is: %d\n",statbuf.st_ino);
	printf("The hard_link's size is: %d\n",statbuf.st_size);
 
	symlink("file","sort_link");
 
	if(lstat("sort_link",&statbuf) < 0)
        perror("lstat");
 
	printf("The sort_link's inode is: %d\n",statbuf.st_ino);
        printf("The sort_link's size is: %d\n",statbuf.st_size);
	
	char buf[4];
	readlink("sort_link",buf,4);
	printf("The sort_link is: %s\n",buf);
 
	if(lstat("file",&statbuf) < 0)
	  perror("lstat");
 
	printf("The file's inode is: %d\n",statbuf.st_ino);
	printf("The file's size is: %d\n",statbuf.st_size);
	printf("The frist linknum is: %d\n",statbuf.st_nlink);
 
	unlink("file");
 
	if(lstat("file",&statbuf) < 0)
	  perror("lstat");
	printf("The second linknum is: %d\n",statbuf.st_nlink);
 
	close(fd);
	return 0;
}

程序运行结果:

我们可以看到,在第二次利用lstat获取file的信息时,提示没有file,这正是进行ulink的结果。

ulink函数的作用:删除目录相并减少一个连接数,如果链接数为0并且没有任何进程打开该文件,该文件内容才能被真正删除,但是若又进程打开了该文件,则文件暂时不删除直到所有打开该文件的进程都结束时文件才能被删除。

因此,运行结果中显示的第二个linknum仍然是第一个的值。
实验五
 1.新建/home/user目录;
 2.把当前工作路径移至/home/user目录;
 3.打印当前工作路径;

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
	char str[128];
 
	if(getcwd(str,128) < 0)
	  perror("getwcd");
	else
	  printf("The workdir is:%s\n",str);
 
	if(mkdir("/home/user",0666) < 0)
	  perror("mkdir");
	else
	  printf("The dir create successfully!\n");
	
	if(chdir("/home/user") < 0)
	  perror("chdir");
	else
	{
		getcwd(str,128);
		printf("The workdir is:%s\n",str);
	}
 
	rmdir("/home/user");
	return 0;
}

虽然程序已经编写完毕,但是我们在运行程序时却会遇到问题:

权限不够
我们可以先切换到root用执行该程序,就能成功创建。

实验六
 编写程序完成以下功能:
 1.递归遍历/home目录,打印出所有文件和子目录名称及节点号。
 2.判断文件类型,如果是子目录,继续进行递归遍历,直到遍历完所有子目录为止。
所谓递归,就函数自己调用自己,直到完成函数终止条件,跳出递归函数。

要想递归遍历/home目录,就必须确定合适的迭代条件。既然要遍历/home目录,那就要将所有的文件夹都访问到。因此,只要是/home目录下的文件夹,都要被访问,因此,我们以打开文件的结果作为迭代条件,只要打开的是目录文件,就能够进入递归函数。不仅如此,要想打开正确的目录,就必须获得目录的路径,因此,我们会用到spritnf函数来储存文件路径。

spritf函数的作用和printf的作用相似,只不过printf是将字符串输出到屏幕,而sprintf函数是将字符串输出到字符串中。

函数示例如下

#include <stdio.h>
#include <stdlib.h>
int main()
{
	char *str = "hello";
	char *buf = "world";
	char s[128];
 
	sprintf(s,"%s%s",str,buf);
 
	printf("The s is: %s\n",s);
	
	return 0;
}

程序运行结果为:

利用sprintf函数,我们就能将文件的绝对路径写入字符串中,通过字符串打开文件

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
 
void show(char *path)
{
	DIR *dir;
	char str[128];
	struct dirent *dirp;
	struct stat statbuf;
 
	dir = opendir(path);
 
	if(dir)
	{
		while((dirp = readdir(dir)) != NULL)
		{	
			sprintf(str,"%s/%s",path,dirp->d_name);
			if(lstat(str,&statbuf) < 0)
			  perror("lstat");
	
			if(dirp->d_name[0] == '.')
			  continue;
 
			if(S_ISDIR(statbuf.st_mode))
			{
				show(str);
 
				printf("The dirent's name is: %s\n",dirp->d_name);
				printf("The dirent's inode is: %d\n",dirp->d_ino);
			}
			else
			{
				printf("The file's name is: %s\n",dirp->d_name);
				printf("The file's inode is: %d\n",dirp->d_ino);
			}
		}
	}
	else
		perror("opendir");
 
	closedir(dir);
}
 
int main()
{
	show("/home");
	return 0;
}

实验完成

  • 7
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在任一OS下,建立一个大文件,把它假象成一张盘,在其中实现一个简单的模拟Linux文件系统。 1. 在现有机器硬盘上开辟100M的硬盘空间,作为设定的硬盘空间。 2. 编写一管理程序simdisk对此空间进行管理,以模拟Linux文件系统,要求: (1) 盘块大小1k (2) 空闲盘块的管理:Linux位图法 (3) 结构:超级块, i结点区, 根目录区 3. 该simdisk管理程序的功能要求如下: (1) info: 显示整个系统信息(参考Linux文件系统的系统信息),文件可以根据用户进行读写保护。目录名和文件名支持全路径名和相对路径名,路径名各分量间用“/”隔开。 (2) cd …: 改变目录:改变当前工作目录,目录不存在时给出出错信息。 (3) dir …: 显示目录:显示指定目录下或当前目录下的信息,包括文件名、物理地址、保护码、文件长度、子目录等(带/s参数的dir命令,显示所有子目录)。 (4) md …: 创建目录:在指定路径或当前路径下创建指定目录。重名时给出错信息。 (5) rd …: 删除目录:删除指定目录下所有文件和子目录。要删目录不空时,要给出提示是否要删除。 (6) newfile …: 建立文件。 (7) cat …: 打开文件。 (8) copy …: 拷贝文件,除支持模拟Linux文件系统内部的文件拷贝外,还支持host文件系统与模拟Linux文件系统间的文件拷贝,host文件系统的文件命名为…,如:将windows下D:盘的文件\data\sample\test.txt文件拷贝到模拟Linux文件系统中的/test/data目录,windows下D:盘的当前目录为D:\data,则使用命令: simdisk copy D:\data\sample\test.txt /test/data 或者:simdisk copy D:sample\test.txt /test/data (9) del …: 删除文件:删除指定文件,不存在时给出出错信息。 (10) check: 检测并恢复文件系统:对文件系统中的数据一致性进行检测,并自动根据文件系统的结构和信息进行数据再整理。 4. 程序的总体流程为: (1) 初始化文件目录; (2) 输出提示符,等待接受命令,分析键入的命令; (3) 对合法的命令,执行相应的处理程序,否则输出错误信息,继续等待新命令,直到键入EXIT退出为止。
模拟Linux文件系统。在任一OS下,建立一个大文件,把它假象成一张盘,在其中实现一个简单的 模拟Linux文件系统 在现有机器硬盘上开辟20M的硬盘空间,作为设定的硬盘空间。 2. 编写一管理程序对此空间进行管理,以模拟Linux文件系统,具体要求如下: (1) 要求盘块大小1k 正规文件 (2) i 结点文件类型 目录文件 (共1byte) 块设备 管道文件 物理地址(索引表) 共有13个表项,每表项2byte 文件长度 4byte 。联结计数 1byte (3)0号块 超级块 栈长度50 空闲盘块的管理:成组链接 ( UNIX) 位示图法 (Linux) (4)每建一个目录,分配4个物理块 文件名 14byte (5)目录项信息 i 结点号 2byte (6)结构: 0#: 超级块 1#-20#号为 i 结点区 20#-30#号为根目录区 3. 该管理程序的功能要求如下: (1) 能够显示整个系统信息,源文件可以进行读写保护。目录名和文件名支持全路径名和相对路径名,路径名各分量间用“/”隔开。 (2) 改变目录:改变当前工作目录,目录不存在时给出出错信息。 (3) 显示目录:显示指定目录下或当前目录下的信息,包括文件名、物理地址、保护码、文件长度、子目录等(带/s参数的dir命令,显示所有子目录)。 (4) 创建目录:在指定路径或当前路径下创建指定目录。重名时给出错信息。 (5) 删除目录:删除指定目录下所有文件和子目录。要删目录不空时,要给出提示是否要删除。 (6) 建立文件(需给出文件名,文件长度)。 (7) 打开文件(显示文件所占的盘块)。 (8) 删除文件:删除指定文件,不存在时给出出错信息。 4. 程序的总体流程为: (1) 初始化文件目录; (2) 输出提示符,等待接受命令,分析键入的命令; (3) 对合法的命令,执行相应的处理程序,否则输出错误信息,继续等待新命令,直到键入EXIT退出为止。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值