首页 > 系统相关 >《Unix/Linux系统编程》学习笔记4

《Unix/Linux系统编程》学习笔记4

时间:2022-09-25 21:35:53浏览次数:46  
标签:printf sp int 编程 char Unix Linux include block

第七章 文件操作

一.知识点归纳

(一)文件操作级别

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

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

image
image

image

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

image
image

  • Block#0:引导块
    • B0是引导块(Boot Block),文件系统不会使用它。它用于容纳从磁盘引导操作系统的引导程序。
  • Block#1:超级块
    • 超级块(Super Block)描述整个分区的文件系统信息,如inode/block的大小、总量、使用量、剩余量,以及文件系统的格式与相关信息。超级块在每个块组的开头都有一份拷贝(第一个块组必须有,后面的块组可以没有)。
    • 超级块记录的信息有:
      1. block 与 inode 的总量(分区内所有Block Group的block和inode总量);
      2. 未使用与已使用的 inode / block 数量;
      3. block 与 inode 的大小 (block 为 1, 2, 4K,inode 为 128 bytes);
      4. filesystem 的挂载时间、最近一次写入数据的时间、最近一次检验磁盘 (fsck) 的时间等文件系统的相关信息;
      5. 一个 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);
}

image

(二)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

相关文章

  • Linux 网卡实时流量查看脚本
    Linux网卡实时流量查看脚本#!/bin/bashPATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin;exportPATHfunctiontraffic_monitor{OS_NAME=$......
  • dapr-安装之-linux版
    1.安装包准备:下载地址:https://github.com/dapr/installer-bundle/releases2.服务器准备准备centos7一台3.前置环境docker4.下载安装包由于我们计划......
  • 《Unix&Linux系统编程》第七章学习笔记
    第7章文件操作7.1文件操作级别1.硬件级别fdisk:将硬盘、U盘或SDC盘分区mkfs:格式化磁盘分区,为系统做好准备fsck:检查和维修系统碎片整理:压缩文件系统中的文件2.操......
  • 《Unix/Linux系统编程》第七、八章学习笔记
    第七章文件操作7.1文件操作级别文件操作分为五个级别,按照从高到低的顺序排列如下:(1)硬件级别fdisk:将硬盘、U盘或SDC盘分区。mkfs:格式化磁盘分区,为系统做好准备。f......
  • Linux pssh安装与使用
    Linuxpssh安装与使用说明:我这是没有在密钥认证的情况下操作1、安装pssh[root@libinansible]#yuminstall-ypssh[root@libinansible]#rpm-qlpssh/usr/bin/pnuk......
  • 弃用 Windows,政府机构 5000 万台电脑将替换为国产 Linux!
    来源:https://www.linuxmi.com/50-million-pc-linux.html开源社区的一大胜利!继德国之后,中国现在想在5000万台PC上抛弃Windows并运行Linux!如果您一直密切关注Lin......
  • Linux错题集1
    错题1在Linux系统中,小王希望将他执行ls命令的输出结果保存在当前目录下的文件output.ls中,以供日后进行分析和使用,但要求不覆盖原文件的内容,他应该使用的命令是A.ls>outpu......
  • Python核心编程 pdf
    高清扫描版下载链接:https://pan.baidu.com/s/1Gh4hoOS2-5RDSryA_mLqng点击这里获取提取码 ......
  • 在Linux下的文件IO的使用(一)
    系统调用系统调用:操作系统提供给用户程序调用的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的服务为什么用户程序不能直接访问系......
  • UnixBench的简单测试与验证
    UnixBench的简单测试与验证目标飞腾2000+(物理机和虚拟机)IntelGolden6170物理机IntelGolden5218虚拟机[email protected]至强十年前的CPUE5-262......