• 20191317王鹏宇第七,八章学习笔记


    第七章:文件操作

    知识点归纳总结

    本章讨论了多种文件系统;解释了操作系统中的各种操作级别,包括为文件存储准备存储设备、内核中的文件系统支持函数、系统调用、文件流上的I/O库函数、用户命令和各种 操作的sh脚本;系统性概述了各种操作,包括从用户空间的文件流读/写到内核空间的系统 调用,直到底层的设备I/O驱动程序级别;描述了低级别的文件操作,包括磁盘分区、显示分区表的示例程序、文件系统的格式化分区以及挂载磁盘分区;介绍了 Linux系统的EXT2 文件系统,包括EXT2文件系统的系统数据结构、显示超级块、组描述符、块和索引节点位 图以及目录内容的示例程序。编程项目将本章中讨论的EXT2/3文件系统和编程技术集中到 一个程序中,将路径名转换为索引节点并打印它们的信息。


    其中让我最有收获的几个部分如下:

    • 操作系统内核中的文件系统函数
    • 系统调用
    • 文件I/O操作
    • 低级别文件操作

    文件系统函数:
    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():(Iseek/close file descriptors)
    ksyralink(), kreadlink():(create/read symbolic link files)
    kstat (), kfstat()/ klstat():(get file status/infoirmation)
    kopendir (), kreaddir ():(open/read directories)



    sh-linux命令:

    • open:打开文件 (man 2 open 查看)

    int open(const char *pathname, int flags); //pathname文件名(路径);flags打开模式,有O_RDONLY, O_WRONLY, O_RDWR
    int open(const char *pathname, int flags, mode_t mode); //该函数一般用于创建新文件,flags添加O_CREAT,比如:O_RDWR|O_CREAT
    int creat(const char *pathname, mode_t mode); //创建新文件,mode权限说明,比如0644(八进制,取反后和umask做与运算得到真正结果)
    返回值:成功返回文件描述符fd,失败返回-1 。

    举例说明:

    int fd = open("test.txt", O_WRONLY); //只写的方式打开test.txt,返回文件描述符

    • read文件读取 (man 2 read 查看)

    ssize_t read(int fd, void *buf, size_t count); //ssize_t有符号整数;fd文件描述符;buf传出参数,读取的内容就在buf里;count表示buf的长度
    返回值:大于0表示读取的字节数,等于0表示读取完,-1表示读取失败

    • write文件写入 (man 2 write 查看)

    ssize_t write(int fd, const void *buf, size_t count); //buf需要写入的内容,count需要写入的内容的长度;ssize_t有符号整数;size_t无符号整数
    返回值:大于表示写入的字节数,0表示没有写入任何数据,-1表示写入失败

    • lseek移动文件指针 (man 2 lseek 查看)

    off_t lseek(int fd, off_t offset, int whence); //fd文件描述符,offset移动偏移量,whence移动参考点
    whence的三个取值:SEEK_SET文件开始位置,SEEK_CUR表示指针当前位置,SEEK_END文件结束位置
    返回值:大于等于0表示离文件开始处的偏移量,-1表示失败

    • stat获取一个文件的信息 (man 2 stat 查看)
      int stat(const char *path, struct stat *buf); //path文件路径;buf传出参数,获取的文件信息就在buf里面
      int fstat(int fd, struct stat *buf); //fd文件描述符
      int lstat(const char *path, struct stat *buf); //lstat和stat的区别只在于符号链接文件,lstat读取符号链接文件,stat读取符号链接对应的源文件
      返回值:成功返回0;失败返回-1 。

    • access检查文件权限 (man 2 access 查看)

    int access(const char *pathname, int mode); //pathname文件名称,mode权限
    返回值:所有权限被允许返回0;只要有一个权限不允许的就返回-1,错误也是返回-1;
    mode的值说明:要不是F_OK :表示文件是否存在,要不是R_OK | W_OK | X_OK ,可以是一个或者多个,多个之间按位与;R_OK是否可读,W_OK是否可写,X_OK是否可执行

    • chmod改变文件权限

    int chmod(const char *path, mode_t mode); //path文件路径;mode_t整数,mode权限,必须是一个八进制数,或者使用预定义宏,具体查看man手册
    int fchmod(int fd, mode_t mode); //fd文件描述符
    返回值:成功返回0;失败返回-1 。

    • rename文件重命名

    int rename(const char *oldpath, const char *newpath); //oldpath原文件,newpath新的文件
    返回值:成功返回0;失败返回-1 。


    教材实践:磁盘分区

    (I )在Linux下,例如Ubuntu,创建一个名为mydisk的虚拟磁盘映像文件。
    dd ifa/dev/zero of=mydisk bs=1024 count=1440
    dd是一个将1440( 1KB)个0字节块写入目标文件mydisk的程序。我们选择count=1440, 因为它是旧软盘的1KB字节块的数量。必要时,读者可指定更大的库编号。

    (2 )在磁盘映像文件上运行fdisk:
    fdisk mydisk

    实践内容:挂载分区

    man 8 losetup:显示用于系统管理的losetup实用工具命令:
    (1 )用dd命令创建一个虚拟磁盘映像:
    dd if=/dev/zero of=vdisk bs=1024 count=32768 #32K (1KB) blocks

    (2 )在vdisk上运行fdisk来创建一个分区Pl:
    fdisk vdisk
    输入n(new)命令,使用默认的起始和最后扇区编号来创建一个分区Pl。然后,输入 w命令将分区表写入vdisk并退出fdisko vdisk应包含一个分区Pl [start=2048, end=65535]0 该分区的大小是63488个扇区。

    (3)使用以下扇区数在vdisk的分区1上创建一个循环设备:
    losetup -o $(expr 2048 * 512) --sizelimit $(expr 65535 * 512) /dev/loopl vdisk
    losetup需要分区的开始字节(start_sector512)和结束字节(end_sector512 )。读者可手动 计算这些数值,并在losetup命令中使用它们。可用类似方法设置其他分区的循环设备。循 环设备创建完成后,读进程可以使用命令
    losetup -a
    将所有循环设备显示为/dev/loopNo
    这里第三步出现了问题,在openeuler系统上无法创建回环设备,具体报错如下:

    这时我们使用losetup -a指令可以查看在使用中的循环设备,使用losetup -f可以查看空闲的循环设备才发现是权限问题,于是在指令前加上sudo:

    可以看出,成功创建回环设备

    (4 )格式化/dev/】oopl,它是一个EXT2文件系统:
    mke2fs -b 4096 /dev/loopl 7936 (mke2fs with 7936 4KB blocks)
    该分区的大小是63488个扇区。4KB块的扇区大小是63488 / 8=7936。

    (5)挂载循环设备:
    mount /dev/loopl /mnt # mount as loop device
    (6 )访问作为文件系统一部分的挂载设备:
    (cd /mnt; mkdir bin boot dev etc user) # populate with DIRs

    可以通过fdisk命令查看挂载分区:

    (7) 设备使用完毕后,将其卸载。
    umount /mnt
    (8) 循环设备使用完毕后,通过以下命令将其断开:
    losetup -d /dev/loopl # detach a loop device.


    实践内容:教材实例编程

    代码:

    /*********** superblock.c program ************/
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/io.h>
    #include <ext2fs/ext2_fs.h>
    // Cypedef u8, ul6, u32 SUPER for convenience typedef typedef typedef
    typedef unsigned char u8;
    typedef unsigned short ul6;
    typedef unsigned int u32;
    typedef struct ext2_super_block SUPER;
    SUPER *sp;
    char buf[1024];
    int fd, blksize, inodesize;
    int print(char *s, u32 x)
    {
        printf("%-30s = %8d
    ", s, x);
    }
    int super(char *device)
    {
        fd = open(device, O_RDONLY);
        if (fd < 0) 
        {
            printf("open %s failed
    ", device); 
            exit(1);
        }
        lseek(fd, (long)1024*1, 0);	// block 1 or offset 1024
        read(fd, buf, 1024);
        sp = (SUPER *)buf;	// as a super block structure
        // check for EXT2 FS magic number锟斤拷
        printf("%-30s = %8x ", "s_magic", sp->s_magic);
        if (sp->s_magic != 0xEF53)
        {
            printf("NOT an EXT2 FS
    "); exit(2);
        }
        printf("EXT2 FS OK
    "); 
        print("s_inodes_count",  sp->s_inodes_count);
        print("s_blocks _count", sp->s_blocks_count); 
        print("s_r_blocks_count", sp->s_r_blocks_count);
        print("s_free_inodes_count", sp->s_free_inodes_count);
        print("s_free_blocks_count", sp->s_free_blocks_count);
        print("s_first_data_blcok", sp->s_first_data_block); 
        print("s_log_block_s i z e", sp->s_log_block_size);
        print("s_blocks_per_group", sp->s_blocks_per_group); 
        print("s_inodes_per_group", sp-> s_inodes_per_group); 
        print("s_mnt_count", sp->s_mnt_count);
        print("s_max_mnt_count", sp-> s_max_mnt_count);
     
        printf("%-30s = %8x
    ", "s_magic", sp->s_magic); 
        printf ("s_mtime = %s", ctime (&sp->s_mtime)); 
        printf ("s_wtime = %s", ctime (&sp->s_wtime)); 
        blksize = 1024 * (1 << sp->s_log_block_size);
        printf("block size = %d
    ", blksize);
        printf("inode size = %d
    ", sp->s_inode_size);
    }
    
    char *device = "mydisk";	// default device name
    int main(int argc, char *argv[])
    {
        if (argc>1)
            device = argv[1];
        super(device);
    }
    
    

    实践截图:

    我对openeuler系统的评价是:都不用,各种依赖没有就算了,装也装不上,教材代码更是跟openeuler系统绝配,代码各种头文件缺失,ok可以装,但是openeuler系统装不上,怎么办呢?看教材指令:sudo apt—get install ext2fs-dev。非常好,指令是废的,怎么办呢?我又通过vscode中vcpkg指令下载好,再挪到/usr/include文件夹中,这次头文件终于可以识别到了,问题又来了,这么多警告无法识别函数,怎么办呢?原来又是教材代码缺失头文件,继续添加头文件,但是警告总是消不掉,调试了一个晚上加一个早上,放弃了,我指定是不行了。


    第八章:使用系统调用进行文件操作

    知识点归纳总结

    本章论述了如何使用系统调用进行文件操作;解释了系统调用的作用和Linux的在线手 册页;展示r如何使用系统週用进行文件操作;列举并解释r文件操作中最常用的系统调用; 阐明了硬链接和符号链接文件;具体解释了 Stat系统调用;基于stat信息,开发了一个类似 于Is的程序来显示目录内容和文件信息;接着,讲解了 open-close-lseek系统调用和文件描 述符;然后,展示了如何使用读写系统调用来读写文件内容;在此基础上,说明了如何使用 系统调用来显示和复制文件;还演示了如何开发选择性文件复制程序,其行为类似于一个 简化的Linux dd实用程序。编程项目使用Linux系统调用来实现C程序,该程序将目录递 归复制到目标中。该项目的目的是让读者练习程序的分层结构设计,并利用stat()、open。、 read。、write。系统调用进行文件操作。


    其中让我最有收获的几个部分如下:

    • 操作系统内核中的文件系统函数
    • 系统调用函数
    • 链接文件
    • stat系统调用

    简单的系统调用:
    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 *patiiname);

    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, char *newpath);

    unlink:减少文件的链接数;如果链接数达到0,则删除文件

    int uniink(char *pathname);

    symlink:为文件创建一个符号链接

    int symliak(char *oldpath, char *newpath);

    rename:更改文件名称

    int rename(char *oldpath, char *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);



    实践内容:教材实例编程

    代码:

    /*****C8.1.C file ************/
    #include <stdio.h>
    #include <errno.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<unistd.h>
    #include<string.h>
    int main()
    {
        char buf[256], *s;
        int r;
        r = mkdir("newdir", 0766); // mkdir syscall
        if (r < 0)
            printf ("errno=%d : %s
    "  ,errno, strarror (errno));
        r = chdir("newdir");	//cd into newdlr
        s = getcwd(buf, 256);	// get CWD string into buf[]
        printf ("CWD = %s
    ", s);
    }
    

    实践截图:


    实践内容:教材练习8.1

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <time.h>
    #include <sys/types.h>
    #include <dirent.h>
    #include <unistd.h>
    struct stat mystat, *sp;
    char *t1 = "xwrxwrxwr------";
    char *t2 = "---------------";
    
    int ls_file(char *fname)
    {
        struct stat fstat, *sp;
        int r, i;
        char ftime[64];
        sp = &fstat;
        if ( (r = lstat(fname, &fstat)) < 0)
        { 
            printf("can* t stat %s
    ", fname); 
            exit(1);
        }
        if ((sp->st_mode & 0xF000)==0x8000) // if (S_ISREG())
            printf("%c",'-');
        if ((sp->st_mode &	0xF000)==0x4000) // if (S_ISDIR())
            printf("%c",'d');
        if ((sp->st_mode &	0xF000)==0xA000) // if (S_ISLNK())
            printf ("%c",'l');	
        for (i=8; i >= 0; i--)
        {	
            if (sp->st_mode & (1 << i))	// print r|w|x
                printf("%c",t1[i]);	
            else		
                printf("%c",t2[i]);	// or print -
        }
        printf("%4d ",sp->st_nlink);	// link count
        printf("%4d ",sp->st_gid);	// gid
        printf("%4d ",sp->st_uid);	// uid
        printf("%8d ",sp->st_size);	// file size
    // print time		
        strcpy(ftime, ctime(&sp->st_ctime)); // print time in calendar form
        ftime[strlen(ftime)	-1] = 0;	// kill 
     at end
        printf("%s	",ftime);
    // print name
        printf("%s", basename(fname)); // print file basename
    // print -> linkname if symbolic file
        if ((sp->st_mode & 0xF000)== 0xA000)
        {
                    // use readlink() to read linkname
        printf(" -> %s", linkname); // print linked name
        }
        printf("
    ");
    }
    int ls_dir(char *dname)
    {
        // use opendir(), readdir(); then call ls_file(name)
    }
    int main(int argc, char *argv[])
    {
        struct stat mystat, *sp = &mystat;
        int r;
        char *filename, path[1024], cwd[256];
        filename = "./";	// default to CWD
        if (argc > 1)
        filename = argv[1];	// if specified a filename
        if (r = Istat(filename, sp) < 0)
        {
            printf("no such file %s
    ", filename);
            exit(1);
        }
        strcpy(path, filename);
        if (path[0] != '/')
        { 
            getcwd(cwd, 256);
            strcpy(path, cwd); strcat(path, " /") ; strcat(path,filename);
        }
        if (S_ISDIR(sp->st_mode))
            ls_dir(path);
        else
            ls_file(path);
    }
    

    这里是教材代码但是暂时还未调试成功,因为缺少了两个函数,但是这里两个函数还未补充完全。

  • 相关阅读:
    [Linux]调整swap
    [Linux]mysql错误总结-ERROR 1067 (42000): Invalid default value for TIMESTAMP
    Canvas动画:地球绕着太阳转
    50个好用的前端框架,建议收藏!
    flex布局属性说明
    纯CSS绘制的图形一览
    深入理解CSS盒模型(转)
    JS的防抖与节流学习笔记
    应用八:Vue之在nginx下的部署实践
    css元素居中的几种方式
  • 原文地址:https://www.cnblogs.com/wpy-1049363419/p/15375278.html
Copyright © 2020-2023  润新知