第七章 文件操作
一.知识点归纳
(一)文件操作级别
文件操作分为五个级别,按照从低到高的顺序排列如下:
1.硬件级别:
硬件级别的文件操作包括:
- fdisk:将硬盘、U盘或SDC盘分区。
- mkfs:格式化磁盘分区,为系统做好准备。
- fsck:检查和维修系统。
- 碎片整理:压缩文件系统中的文件。
2.操作系统内核中的文件系统函数
每个操作系统内核均可为基本文件操作提供支持。下文列出了类Unix系统内核中的一些函数,其中前缀 k 表示内核函数。
kmount(), kumount() (mount)
kmkdir(), krmdir() ()
kchdir(), kgetcwd() ()
klink(), kunlink() ()
kchmod(), kchown(), kutime() ()
kcreat(), kopen() ()
kread(), kwrite() ()
klseek(), kclose() ()
ksymlink(), kreadlink() ()
kstat(), kfstat(), klstat() ()
kopendir(), kreaddir() ()
3.系统调用
用户模式程序使用系统调用来访问内核函数。例如,下面的程序可读取文件的第二个1024字节。
#include<fcntl.h>
int main(int argc, char *agrv[])
{
int fd, n;
char buf[1024];
if((fd = open(argv[1], O_RDONLY))<0)
exit(1);
lseek(fd, 1024, SEEK_SET);
n = read(fd, buf, 1024);
close(fd);
}
4.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脚本
(二)文件I/O操作
(三)低级别文件操作
1.分区
(1)在 Linux 下,创建一个名为 mydisk 的虚拟磁盘映像文件。
dd if=/dev/zero of=mydisk bs=1024 count=1440
dd 是将一个1440(1KB)个0字节块写入目标文件 mydisk 的程序。我们选择 count=1440,因为它是旧软盘的 1KB 字节块的数量。必要时,可指定更大的库编号。
(2)在磁盘映像文件上运行 fidisk:
fdisk mydisk
2.格式化分区
格式:
mkfs -t TYPE [-b bsize] device nblocks
假设是 EXT2/3 文件系统,它是 Linux 的默认文件系统。因此,
mkfs -t ext2 vdisk 1440 或 mke2fs vdisk 1440
sudo mount -o loop vdisk /mnt
sudo umount /mnt 或 sudo umount vdisk
3.挂载分区
#(1)用dd命令创建一个虚拟磁盘映像
dd if=/dev/zero of=mydisk bs=1024 count=32768
#(2)在vdisk上运行fdisk来创建一个分区P1
fdisk vdisk
#(3)使用以下扇区数在vdisk的分区1上创建一个循环设备
losetup -o $(expr 2048 \* 512) --sizelimit $(expr 65535 \* 512) /dev/loop1
vdisk
losetup -a
#(4)格式化/dev/loop1,它是一个EXT2文件系统
mke2fs -b 4096 /dev/loop1 7936
#(5)挂载循环设备
mount /dev/loop1 /mnt
#(6)访问作为文件系统一部分的挂载系统
(cd /mnt; mkdir bin boot dev etc user)
#(7)设备使用完毕后,将其卸载
umount /mnt
#(8)循环设备使用完毕后,通过以下命令将其断开
losetup -d /dev/loop1
(四)EXT2文件系统简介
在 Linux 下,我们可以创建一个包含简单 EXT2 文件系统的虚拟磁盘,如下文所示:
dd if=/dev/zero of=mydisk bs=1024 count=1440
mke2fs -b 1024 mydisk 1440
- Block#0:引导块
- B0是引导块(Boot Block),文件系统不会使用它。它用于容纳从磁盘引导操作系统的引导程序。
- Block#1:超级块
- 超级块(Super Block)描述整个分区的文件系统信息,如inode/block的大小、总量、使用量、剩余量,以及文件系统的格式与相关信息。超级块在每个块组的开头都有一份拷贝(第一个块组必须有,后面的块组可以没有)。
- 超级块记录的信息有:
- block 与 inode 的总量(分区内所有Block Group的block和inode总量);
- 未使用与已使用的 inode / block 数量;
- block 与 inode 的大小 (block 为 1, 2, 4K,inode 为 128 bytes);
- filesystem 的挂载时间、最近一次写入数据的时间、最近一次检验磁盘 (fsck) 的时间等文件系统的相关信息;
- 一个 valid bit 数值,若此文件系统已被挂载,则 valid bit 为 0 ,若未被挂载,则 valid bit 为 1 。
- Block#2:块组描述符块
- 块组描述符块(GD)由很多块组描述符组成,整个分区分成多个块组就对应有多少个块组描述符。
- 每个块组描述符存储一个块组的描述信息,如在这个块组中从哪里开始是inode Table,从哪里开始是Data Blocks,空闲的inode和数据块还有多少个等等。块组描述符在每个块组的开头都有一份拷贝。
- Block#8:块位图
- 块位图(Block Bitmap)用来描述整个块组中哪些块已用哪些块空闲。块位图本身占一个块,其中的每个bit代表本块组的一个block,这个bit为1代表该块已用,为0表示空闲可用。假设格式化时block大小为1KB,这样大小的一个块位图就可以表示1024*8个块的占用情况,因此一个块组最多可以有10248个块。
- Block#9:索引节点位图
- inode位图(inode Bitmap)和块位图类似,本身占一个块,其中每个bit表示一个inode是否空闲可用。 Inode bitmap的作用是记录block group中Inode区域的使用情况,Ext文件系统中一个block group中可以有16384个Inode,代表着这个Ext文件系统中一个block group最多可以描述16384个文件。
- Block#10:索引(开始)节点块
- inode表(inode Table)由一个块组中的所有inode组成。一个文件除了数据需要存储之外,一些描述信息也需要存储,如文件类型,权限,文件大小,创建、修改、访问时间等,这些信息存在inode中而不是数据块中。inode表占多少个块在格式化时就要写入块组描述符中。 在Ext2/Ext3文件系统中,每个文件在磁盘上的位置都由文件系统block group中的一个Inode指针进行索引,Inode将会把具体的位置指向一些真正记录文件数据的block块,需要注意的是这些block可能和Inode同属于一个block group也可能分属于不同的block group。我们把文件系统上这些真实记录文件数据的block称为Data blocks。
二.问题与解决思路
三.实践内容与截图
为了编译和运行程序,系统必须安装 ext2fs.h 头文件
sudo apt-get install ext2fs-dev
(一)显示超级块
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<ext2fs/ext2_fs.h>
//typedef u8, u16, u32, SUPER for convenience
typedef unsigned char u8;
typedef unsigned short u16;
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\n",s,x);
}
int super(char *device)
{
fd=open(device,O_RDONLY);
if (fd <0)
{
printf("open %sfailed\n", device);
exit(1);
)
1seek(fd, (1ong)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("8-30s = %8x ", "s_magic", sp->s_magic);
if (sp->s_magic != 0xEF53)
{
printf("NOT an EXT2 FS\n*);
exit(2);
}
printf("EXT2 FS OK\n");
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_size",sp->s_1og_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\n", "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\n", blksize);
printf("inode size = %d\n", sp->s_inode_size);
}
char *device = "mydisk"; // default device name
int main(int argc, char *argv[])
{
if(argc>1)
device = argv[1];
super(sevice);
}
(二)显示位图
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<ext2fs/ext2_fs.h>
typedef struct ext2_super_block SUPER;
typedef struct ext2_group_desc GD;
#define BLKSIZE 1024
SUPER *sp;
GD *gp;
char buf[BLKSIZE];
int fd;
int get_block(int fd, int blk, char *buf)
{
lseek(fd, (1ong)blk*BLKSIZE, 0);
read(fd, buf, BLKSIZE);
}
int imap(char *device)
{
int i, ninodes, blksize, imapblk;
fd = open(dev, O_RDONLY);
if (fd < 0)
{
printf("open %s failed\n", device);
exit(1);
}
get_block(fd,1, buf); // get superblock
sp=(SUPER *)buf;
ninodes = sp->s_inodes_count; // get inodes_count
printf("ninodes = %d\n", ninodes):
get_block(fd, 2, buf); // get group descriptor
gp=(GD*)buf;
imapblk = gp->bg_inode_bitmap: // got imap block number
printf("imapblk = &d\n", imapblk);
get_block(fd, imapblk, buf): // get imap block into buf[]
for (i=0) i<=nidoes/8;i++)
{ // print each byte in HEX
printf("%02x ", (unsigned char)buf[i]);
}
printf("\n");
}
char *dev = "mydisk"; // default device name
int main(int argc, char *argv[])
{
if(argc>1)
dev = argv[1];
imap(dev);
}
(三)显示根索引节点
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<ext2fs/ext2_fs.h>
#define BLKSIZE 1024
typedef struct ext2_super_block SUPER;
typedef struct ext2_group_desc GD;
typedef struct ext2_inode INODE;
typedef struct ext2_dir_entry_2 DIR;
SUPER *sp;
GD *gp;
INODE *ip;
DIR *dp;
char buf[BLKSIZE];
int fd, firstdate, inodesize, blksize, iblock;
char *dev = "mydisk"; // default device name
int get_block(int fd, int blk, char *buf)
{
lseek(fd, blk*BLKSIZE, SEEK_SET);
return read(fd, buf, BLKSIZE);
{
int inode(char *dev)
{
int i;
fd = open(dev, O_RDONLY) < 0):
if (fd<0){
printf("open failed\n"); exit(1);
)
get_block(fd, 1, buf); // get superblock
sp=(SUPER *)buf;
firstdata = sp->s_first_data_block;
inodesize = sp->s_inode_size;
blksize = 1024*(1<<sp->s_log_block_size);
printf("first_data_block=%d block_size=%d inodesize=%d\n",firstdata, blksize, inodesize);
get_block(fd, (firstdata+1), buf); // get group descriptor
gp=(GD *)buf;
printf("bmap_block=%d imap_block=%d inodes_table=%d ",gp->bg_block_bitmap,gp->bg_inode_bitmap,gp->bg_inode_table,gp->bg_free_blocks_count);
printf("free_blocks=%d free_inodes=&d\n",gp->bg_free_inodes_count,gp->bg_used_dirs_count);
iblock = gp->bg_inode_table;
printf("root inode information:\n", iblock);
printf("----------------------\n");
get_block(fd, iblock, buf);
ip=(INODE *)buf +1; // ip point at #2 INODE
printf("mode=%4x ",ip->i_mode);
printf("uid=%d gid=%d\n", ip->i_uid, ip->i_gid);
printf("size=%d\n",ip->i_size);
printf("ctime=%s", ctime(&ip->i_ctime));
printf("links=%d\n", ip->i_links_count);
for (i=0; i<15;i++) // print disk block numbers
{
if (ip->i_block[i]) // print non-zero blocks only
printf("i_block[%d]=&d\n",i,ip->i_block[i]);
}
}
int main(int argc, char *argv[])
{
if(argc>1)
dev = argv[1];
inode(dev);
}
(四)显示目录条目
第八章 使用系统调用进行文件操作
一.知识点归纳
(一)系统调用
在操作系统中,进程以两种不同的模式运行,即内核模式和用户模式,简称 Kmode 和 Umode。在 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 read(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, int *newPath)
2.符号链接文件
软连接:命令
ln -s oldpath newpath # ln command with the -s flag
创建从 newpath 到 oldpath 的软链接或符号链接,对应的系统调用为:
symlink(char *target, char *newpath)
二.问题与解决思路
三.实践内容与截图
(一)mkdir、chdir、getcwd 系统调用
#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);
}
(二)ls程序
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h>
#include<time.h>
#include<sys/types.h>
#include<dirent.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\n", 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",'1');
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 timo in calandar form
ftime[strlen(ftime)-1]= 0;// kill \n 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)
{
// uso readlink() to read linkname
printf(" -> %s", linkname); // print linked name
}
printf("\n");
}
int ls_dir(char *dname)
{
// use opendir(), readdir(); then ca1l 1s_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 = lstat(filename, sp) <0){
printf("no such file %s\n", filename);
exit(1);
{
strcpy(path, filename);
if (path[0] !='/') // filename is relative : get CWD path
(
getcwd(cwd,256);
strcpy(path, cwd);
strcat(path, "/");
strcat(path,filename);
}
if (S_ISDIR(sp->st_mode))
ls_dir(path);
else
ls_file(path);
}
(三)显示文件内容(cat 命令)
#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);
}
}
(四)复制文件(cp sec dest 命令)
#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);
}
标签:printf,sp,int,编程,char,Unix,Linux,include,block
From: https://www.cnblogs.com/20201212ycy/p/16727423.html