第四次学习笔记

20211119陈俊积

一、知识点归纳和苏格拉底挑战

第七章

文件操作级别

文件操作分为五个级别,按照从低到高的顺序排列如下:

(1)硬件级别

硬件级别的文件操作包括:
fdisk:将硬盘、U盘或SDC盘分区。
mkfs:格式化磁盘分区,为系统做好准备。
fsck:检查和维修系统。
碎片整理:压缩文件系统中的文件。

(2)操作系统内核中的文件系统函数

每个操作系统内核均可为基本文件操作提供支持,例如

kmount(),kumount() (mount/umount file systems)
kmkdir(),krmdir() (make/remove directory) 
kchdir(), kgetcwd () (change directory, get CWD pathname) klink(),kunlink() (hard link/unlink files) 
kchmod(),kchown(),kutime() (change r|w|x permissions, owner,time) 
kcreat (), kopen() (create/open file for R,W,RW,APPEND) kread(),kwrite() (read/write opened files) 
klseek(),kclose() (lseak/close file descriptors) ksymlink(), kreadlink () (create/read symbolic link files) kstat(), kfstat(),klstat() (get file status/information) kopendir(), kreaddiz() (open/read airectories)
(3)系统调用

用户模式程序使用系统调用来访问内核函数,如open(),read(),lseek()和close()都是c语言库函数。每个库函数都会发出一个系统调用,使进程进入内核模式来执行相应的内核函数。当进程结束执行内核函数时,会返回到用户模式,并得到所需的结果。在用户模式和内核模式之间切换需要大量的操作(和时间)。因此,内核和用户空间之间的数据传输成本昂贵。对于读/写文件,最好的方法是匹配内核的功能。内核会按数据块大小(从1KB到8KB)来读取/写入文件。例如,在Linux 中,硬盘的默认数据块大小是4KB,软盘的是1KB。因此,每个读/写系统调用还要尝试一次传输一个数据块。

(4)I/O库函数

用户通常需要读/写单独的字符、行或数据结构记录等。如果只有系统调用,用户模式程序则必须自己从缓冲区执行这些操作。由于大多数用户会认为这非常不方便,因此C语言库提供了一系列标准的I/O函数,同时也提高了运行效率。I/O库函数包括:

FILE mode I/0: fopen(),fread(); fwrite(),fseek(),fclose(),fflush()
char mode I/0: getc(), getchar(),ugetc(); putc(),putchar()
line mode I/0: gets(), fgets(); puts(), fputs()
formatted I/0: acanf(),fscanf(),sscanf(); printf(),fprintf(),sprintf()
(5)用户命令

用户可以使用Unix/Linux命令来执行文件操作,而不是编写程序。
用户命令的示例如下:
mkdir, rmdir, cd, pwd, ls, link, unlink, rm, cat, cp, mv, chmod, etc.
每个用户命令实际上是一个可执行程序(cd除外),通常会调用I/O库函数,而I/O库函数再发出调用相应的内核函数。
用户命令的处理顺序为:
Command => Library I/O function => System call => Kernel Function

Command =========================> System call => Kernel Function

(6)sh脚本

sh语言包含所有的有效Unix/Linux命令,它还支持变量和控制语句,如if、do、for、while、case等。除sh之外,Perl和Tcl等其他许多脚本语言也使用广泛。

文件I/O操作

在这里插入图片描述

低级别文件操作

(1)分区

一个区块存储设备可以分为几个逻辑单元,成为分区。分区表位于第一个扇区的字节偏移446(ox1BE)处,改扇区称为设备的主引导记录。如果某分区是扩展类型(类型编号=5),那么它可以划分为更多分区。

(2)格式化分区

fdisk只是将一个存储设备划分为多个分区。每个分区都有特定的文件系统类型,但是分区还不能使用。为了存储文件,必须先为特定的文件系统准备好分区。该操作习惯上称为格式化磁盘或磁盘分区。在Linux中,命令

mkfs -t TYPE [-b bsize] device nblocks

在一个nblocks设备上创建一个TYPE文件系统,每个块都是bsize字节。如果bsize未指定,则默认大小为1KB.
在Linux中,还不能访问新的文件系统。它必须挂在到跟文件系统中的现有目录。由于细腻文件系统不是真正的设备i,他们必须作为循环设备挂载,如:

sudo mount -o loop vdisk /mnt

第八章

系统调用

操作系统中,进程以内核模式(Kmode)和用户模式(Umode)两种不同的模式运行。在用户模式下,进程的权限非常有限,不能执行任何需要特殊权限的操作。特殊权限的操作必须在Kmode下执行。系统调用(简称syscall)是一种允许进程进入Kmode以执行Umode不允许操作的机制。

使用系统调用进行文件操作

简单的系统调用:
access:检查对某个文件的权限

int access(char *pathname, int mode);

chdir:更改目录

int chdir(const char *path);

chmod:更改某个文件的权限

int chmod(char *path, mode_t mode);

chown:更改文件所有人

int chown(char *name, int uid, int gid);

chroot:将(逻辑)根目录更改为路径名

int chroot(char *pathname);

getcwd:获取 CWD 的绝对路径名

char *getcwd(char *buf, int size);

mkdir:创建目录

int mkdir(char *pathname, mode_t mode);

rmdir:移除目录(必须为空)

int rmdir(char *pathname);

link:将新文件硬链接到旧文件

int link(char *oldPath, int *newPath);

unlink:取消某个文件的链接;如果文件的链接数为0,则删除文件

int unlink(char *pathname);

symlink:创建一个符号链接

int symlink(char *target, char *newpath);

rename:更改文件名称

int rename(char *oldPath, int *newPath);

utime:更改文件的访问和修改时间

int utime(char *pathname, struct utimebuf *time);

以下系统调用需要超级用户权限。
mount:将文件系统添加到挂载点目录上

int mount(char *specialfile, char *mountDir);

umount:分离挂载的文件系统

int umount(char *dir);

mknod:创建特殊文件

int mknod(char *path, int mode, int device);

常用的系统调用(有收获)

stat:获取文件状态信息

int stat(char *filename, struct stat *buf);
int fstat(char filedes, struct stat *buf);
int lstat(char *filename, struct stat *buf);

open:打开一个文件进行读、写、追加

int open(char *file, int flags, int mode);

close:关闭打开的文件描述符

int close(int fd);

read:读取打开的文件描述符

int read(int fd, char buf[], int count);

write:写入打开的文件描述符

int write(int fd, char buf[], int count);

lseek:重新定位文件描述符的读/写偏移量

int lseek(int fd, char offset, int whence);

dup:将文件描述符复制到可用的最小描述符编号中

int dup(int oldfd);

dup2:将 oldfd 复制到 newfd 中,如果 newfd 已打开,先将其关闭

int dup2(int oldfd, int newfd);

link:将新文件硬链接到旧文件

int link(char *oldPath, int *newPath);

unlink:取消某个文件的链接;如果文件的链接数为0,则删除文件

int unlink(char *pathname);

symlink:创建一个符号链接

int symlink(char *target, char *newpath);

readlink::读取符号链接文件的内容

int readlink(char *path, char *buf, int bufsize);

umask:设置文件创建掩码;文件权限为(mask & ~umask)

int umask(int umask);

链接文件

(1)硬链接文件

硬链接:命令

ln oldpath newpath

创建从newpath到oldpath的硬链接。对应的系统调用为:

link(char *oldpath,char *newpath)

硬链接文件会共享文件系统中相同的文件表示数据结构。文件链接会记录链接到同一索引结点的硬连接数量。相反,系统调用:

unlink(char *pathname)

会减少文件的链接数。如果链接变为0,文件就被完全删除。这就是rm命令的作用。为防止重要文件被意外删除,最好创建多个链接到这个文件的硬链接。

(2)软链接文件

软连接命令:

ln -s oldpath newpath   #in command with the -s flag

创建从newpath到oldpath的软链接或符号链接。对应的系统调用是:

symlink(char *oldpath,chat *newpath)

newpath是LNK类型的普通文件,包含oldpath字符串。它可作为一个绕行标志,使访问指向链接好的目标文件。与硬链接不同,软链接适用于任何文件,包括目录。

Stat系统调用

stat/lstat/fstat系统调用可将一个文件的信息返回。
所有的stat系统调用都以stat结构体形式返回信息,其中包含以下片段:

struct stat{

dev_t    st_dev;

ino_t st_ino;

mode_t st_mode;

st_nlink; nlink_t

uid_t st_uid;

gia_t st_gid;

dev_t st_rdev;

off_t st_size;

u32     st_blksize;

u32     st_block8;

time_t  st_atime;time_E

st_mtime time_t st_ctime;

};

Open-close-lseek系统调用(有收获)

open:打开一个文件进行读、写、追加.它会返回一个进程可用的最小文件描述符,用于后续的read( ),write( ),lseek( )和close( )系统调用。

#include<sys/type.h>
#include<sys/stat.h>
#include<fcntl.h>
int open (char *pathname,int flags,mode_t mode);

close:关闭打开的文件描述符

#include <unistd.h>
int close(int fd);

lseek:将文件描述符的字节偏移量重新定位成偏移量

#include<sys/type.h>
#include <unistd.h>
off_t seek(int fd,off_t offset,int whence);

umask:设置文件创建掩码;文件权限(mask&~umask)

Read()系统调用

read:读取打开的文件描述符。read( )将n个字节从打开的文件描述符读入用户空间中的buf[ ].返回值是实际读取的字节数,如果失败,会返回-1。

#include <unistd.h>
int read(int fd,void *buf,int nbytes)

Write()系统调用

write:写入打开的文件描述符。read( )将n个字节从用户空间中的buf[ ]写入文件描述符,必须打开该文件描述符进行写、读写或追加。返回值是实际读取的字节数,通常等于n个字节。如果失败,会返回-1。

#include <unistd.h>
int write(int fd,void *buf,int nbytes)

苏格拉底挑战

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、问题与解决思路

用课本上给的复制程序生成的文件不能正常打开

在这里插入图片描述
解决方法:在运行程序时用sudo命令

在这里插入图片描述

三、实践内容与截图

第七章

分区:

虚拟磁盘映像创建:
在这里插入图片描述
在磁盘映像文件上运行fdisk:
在这里插入图片描述
在这里插入图片描述
帮助文档
在这里插入图片描述

格式化分区:

使用1440个块把vdisk格式化为ext2文件系统:
在这里插入图片描述
把vdisk挂载到/mnt目录里边。df -h查看挂载点,然后卸载设备:
在这里插入图片描述

第八章

mkdir、chdir、getcwd 系统调用:

1.c

#include<stdio.h>
#include<errno.h>
int main()
{
  char buf[256],*s;
  int r;
  r=mkdir("newdir",0766);//mkdir syscall
  if(r<0)
    printf("errno=%d : %s\n",errno,strerror(errno));
  r=chdir("newdir");//cd into newdir
  s=getcwd(buf,256);//get CWD string into buf[]
  printf("CWD = %s\n",s);
}

新建一个文件夹newdir
在这里插入图片描述

ls程序(ls -l file命令):

2.c

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>

int main(int argc,char * argv[]){
    if(argc<2){
        printf("%s need filename\n",argv[0]);
        return -1;
    }
    struct stat st;
    int ret=stat(argv[1],&st);
    if(ret==-1){
        perror("stat");
        return -1;
    }
    char perms[11]={0}; 

    switch (st.st_mode & S_IFMT){
        case S_IFLNK:
            perms[0]='l';
            break;
        case S_IFDIR:
            perms[0]='d';
            break;
        case S_IFREG:
            perms[0]='-';
            break;
        case S_IFBLK:
            perms[0]='b';
            break;
        case S_IFCHR:
            perms[0]='c';
            break;
        case S_IFSOCK:
            perms[0]='s';
            break;
        case S_IFIFO:
            perms[0]='p';
            break;
        default:
            perms[0]='?';
            break;
    }
    
    perms[1]=(st.st_mode & S_IRUSR) ? 'r':'-';
    perms[2]=(st.st_mode & S_IWUSR) ? 'w':'-';
    perms[3]=(st.st_mode & S_IXUSR) ? 'x':'-';
    perms[4]=(st.st_mode & S_IRGRP) ? 'r':'-';
    perms[5]=(st.st_mode & S_IWGRP) ? 'w':'-';
    perms[6]=(st.st_mode & S_IXGRP) ? 'x':'-';
    perms[7]=(st.st_mode & S_IROTH) ? 'r':'-';
    perms[8]=(st.st_mode & S_IWOTH) ? 'w':'-';
    perms[9]=(st.st_mode & S_IXOTH) ? 'x':'-';

    int linkNum=st.st_nlink;

    char * fileUser = getpwuid(st.st_uid)->pw_name;
    char * fileGrp = getgrgid(st.st_gid)->gr_name;
    long int fileSize = st.st_size;
    char * time = ctime(&st.st_mtime);

    char mtime[512]={0};
    strncpy(mtime,time,strlen(time)-1);

    char buf[1024];
    sprintf(buf,"%s %d %s %s %ld %s %s",perms,linkNum,fileUser,fileGrp,fileSize,mtime,argv[1]);
    printf("%s\n",buf);
    return 0;
}


相当于ls -l file 命令:
在这里插入图片描述

显示文件内容(cat 命令):

3.c

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

#define BLKSIZE 4096
int main(int argc, char *argv[])
{
	int fd, i, m, n;
	char buf[BLKSIZE], dummy;
	if(argc>1)
	{
		fd = open(argv[1], O_RDONLY);
		if(fd < 0)
			exit(1);
	}
	while(n = read(fd, buf, BLKSIZE))
	{
		m = write(1, buf, n);
	}
}

将1.c(即mkdir、chdir、getcwd 系统调用)打印出来
在这里插入图片描述

复制文件:

4.c

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

#define BLKSIZE 4096
int main(int argc, char *argv[])
{
	int fd, gd, n, total=0;
	char buf[BLKSIZE];
	if(argc<3)
		exit(1);
	if((fd = (open(argv[1], O_RDONLY)) < 0))
		exit(2);
	if((gd = open(argv[2], O_WRONLY|O_CREAT)) < 0)
		exit(3); 
	while(n = read(fd, buf, BLKSIZE))
	{
		write(gd, buf, n);
		total += n;
	}
	printf("total bytes copied=%d\n", total);
	close(fd);
	close(gd);
}

将1.c的内容复制到5.c中并用3.c打印出来:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值