文件系统
# ext2文件系统
Boot Block | Block Group 0 | Block Group 1 | ... | Block Group n
_____________/ \___________________________________________
Super Block | GDT | Block Bitmap | Inode Bitmap | Inode Table | Data Blocks
文件系统中存储的最小单位是块
- 启动块(Boot Block) 1KB,由PC标准规定,用来存储磁盘分区信息和启动信息,任何文件系统都不能使用该块
- 超级块(Supper Block) 描述整个分区的文件系统信息,例如块大小、文件系统版本号、上次mount时间等等,超级块在每个块组的开头都有一份拷贝
- 块组描述符表(GDT, Group Descripter Table) 由很多块组描述符组成,整个分区分成多少个块组就对应有多少个块组描述符,包括inode表哪里开始,数据块从哪里开始,空闲的inode和数据块还有多少个等。块组描述符在每个块组的开头也都有一份拷贝
- 块位图(Block Bitmap) 用来描述整个块组中哪些块已经使用,哪些空闲
- inode位图 标识一个inode是否空闲可用
- inode表 文件类型(常规、目录、符号链接等),权限,文件大小,创建、修改、访问时间等信息,每个文件都有一个inode
- 数据块
- 常规文件 文件的数据存储在数据块中
- 目录 该目录下所有文件名和目录名存储在数据块中(注意,文件名保存在它所在的目录的数据块中,其他信息都保存在该文件的inode中)
- 符号链接 如果目标路径名比较短则直接保存在inode中,否则分配一个数据块保存
- 设备文件、FIFO和socket等特殊文件 没有数据块,设备文件的主设备号和次设备号保存在inode中
stat/opendir/readdir/closedir
# 文件系统详解
#拷贝文件
dd if=/dev/zero of=fs count=256 bs=4K
#把/dev/zero文件开头的1M字节拷贝成文件名为fs的文件。256次,4K大小
#格式化文件
mke2fs fs
#现在fs的大小仍然是1MB,但不再是全0了,其中已经有了块组和描述信息。
#查看这个分区的信息
dumpe2fs fs
#挂载文件系统
mount -o loop fs /mnt
#-o loop告诉mount这是一个常规文件而不是一个块设备文件,mount会把它的数据块中的数据当作分区格式来解释
#文件系统格式化之后在根目录下自动生成三个子目录:. , ..和lost+found
umount /mnt
#用二进制查看工具查看这个文件系统的所有字节
od -tx1 -Ax fs
# 文件操作
# 获取文件属性
//参数1:文件名
//参数2:inode结构体指针 (传出参数)
int stat(const char *path, struct stat *buf); //成返回0;失败返回-1 设置errno为恰当值。
//当命名的文件是一个符号链接,lstat返回该符号链接的有关信息,而不是该符号链接引用的文件的信息
int lstat(const char *path, struct stat *buf); //成返回0;失败返回-1 设置errno为恰当值。
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection 文件类型,文件访问权限 */
// S_ISREG(m) is it a regular file?
// S_ISDIR(m) directory?
// S_ISCHR(m) character device?
// S_ISBLK(m) block device?
// S_ISFIFO(m) FIFO (named pipe)?
// S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
// S_ISSOCK(m) socket?
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last modification */
struct timespec st_ctim; /* time of last status change */
};
穿透符号链接:stat:会;lstat:不会
# 测试指定文件是否存在/拥有某种权限。
//参数2:R_OK、W_OK、X_OK,通常使用access函数来测试某个文件是否存在。F_OK
int access(const char *pathname, int mode); //成功/具备该权限:0;失败/不具备 -1 设置errno为相应值。
# 修改文件的访问权限
int chmod(const char *path, mode_t mode); ///成功:0;失败:-1设置errno为相应值
int fchmod(int fd, mode_t mode);
# 文件屏蔽字
int umask(mode_t cmask);
umask -S //打印符号格式
# 截断文件长度成指定长度
int truncate(const char *path, off_t length); //成功:0;失败:-1设置errno为相应值
int ftruncate(int fd, off_t length);
# 重定向
int dup(int oldfd); //成功:返回一个新文件描述符;失败:-1设置errno为相应值
int dup2(int oldfd, int newfd);
wc -c file 计算文件中的字符数
# 函数stat、fstat、fstatat和lstat
文件相关的信息结构
//参数1:文件名
//参数2:inode结构体指针 (传出参数)
int stat(const char *path, struct stat *buf); //成返回0;失败返回-1 设置errno为恰当值。
int fstat(int fd, struct stat* buf);
//当命名的文件是一个符号链接,lstat返回该符号链接的有关信息,而不是该符号链接引用的文件的信息
int lstat(const char *path, struct stat *buf); //成返回0;失败返回-1 设置errno为恰当值。
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection 文件类型,文件访问权限 */
// S_ISREG(m) is it a regular file?
// S_ISDIR(m) directory?
// S_ISCHR(m) character device?
// S_ISBLK(m) block device?
// S_ISFIFO(m) FIFO (named pipe)?
// S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
// S_ISSOCK(m) socket?
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last modification */
struct timespec st_ctim; /* time of last status change */
};
// 用上面3种即可,该方法一般不用
int fstatat(int fd, const char* pathname, struct stat* buf, int flag);
穿透符号链接:stat:会;lstat:不会
#include <unistd.h>
#include <sys/stat.h>
int main(int argc, char * argv[])
{
struct stat sbuf;
int ret = stat(argv[1], &sbuf); //穿透符号链接
if (ret < 0) {
perror("stat");
exit(1);
}
printf("st_ino = %ld\n", buf.st_ino);
printf("st_size = %ld\n", buf.st_size);
printf("st_nlink = %d\n", buf.st_nlink);
printf("st_uid = %d\n", buf.st_uid);
printf("st_gid = %d\n", buf.st_gid);
printf("st_mode = %x\n", buf.st_mode);
if (S_ISREG(sbuf.st_mode)) {
printf("It's a regular file\n");
} else if (S_ISDIR(sbuf.st_mode)) {
printf("It's a directory\n");
} else if (S_ISFIFO(sbuf.st_mode)) {
printf("It's a fifo\n");
} else if (S_ISLNK(sbuf.st_mode)) {
printf("It's a symbolic link\n");
}
return 0;
}