实现一个文件系统

偶然看到sysplay(印度科学研究院的一家伙的blog,实现了一个用户态的文件系统 File Systems: The Semester Project, 做个笔记。

说已经存在了很多的文件系统,但是没有最好的。每个文件系统都是针对特定的场景。

而了解系统最好的办法不是看文档,而是看代码。

所以产生了这个 模拟文件系统(simula-ting file system file) 项目 。该项目是用户态的一个文件系统。 

Part 1:

通过文件模拟一个块设备,并格式化成定义的文件系统格式

  

首先要了解问价系统的概念,一个基本的文件系统包含两个重要的结构体:

超级块(supper block)和文件条目(file entry)

 1 #ifndef SFS_DS_H
 2 #define SFS_DS_H
 3 
 4 #define SIMULA_FS_TYPE 0x13090D15 /* Magic Number for our file system */
 5 #define SIMULA_FS_BLOCK_SIZE 512 /* in bytes */
 6 #define SIMULA_FS_ENTRY_SIZE 64 /* in bytes */
 7 #define SIMULA_FS_DATA_BLOCK_CNT ((SIMULA_FS_ENTRY_SIZE - (16 + 3 * 4)) / 4)
 8 
 9 #define SIMULA_DEFAULT_FILE ".sfsf"
10 
11 typedef unsigned int uint4_t;
12 
13 typedef struct sfs_super_block
14 {
15     uint4_t type; /* Magic number to identify the file system */
16     uint4_t block_size; /* Unit of allocation */
17     uint4_t partition_size; /* in blocks */
18     uint4_t entry_size; /* in bytes */ 
19     uint4_t entry_table_size; /* in blocks */
20     uint4_t entry_table_block_start; /* in blocks */
21     uint4_t entry_count; /* Total entries in the file system */
22     uint4_t data_block_start; /* in blocks */
23     uint4_t reserved[SIMULA_FS_BLOCK_SIZE / 4 - 8];
24 } sfs_super_block_t; /* Making it of SIMULA_FS_BLOCK_SIZE */
25 
26 typedef struct sfs_file_entry
27 {
28     char name[16];
29     uint4_t size; /* in bytes */
30     uint4_t timestamp; /* Seconds since Epoch */
31     uint4_t perms; /* Permissions for user */
32     uint4_t blocks[SIMULA_FS_DATA_BLOCK_CNT];
33 } sfs_file_entry_t;
34 
35 #endif

执行一下代码创建sfs_ds.h

cat << EOF |  sed -e "s/\\\t/\t/" | tee sfs_ds.h
#ifndef SFS_DS_H
#define SFS_DS_H

#define SIMULA_FS_TYPE 0x13090D15 /* Magic Number for our file system */
#define SIMULA_FS_BLOCK_SIZE 512 /* in bytes */
#define SIMULA_FS_ENTRY_SIZE 64 /* in bytes */
#define SIMULA_FS_DATA_BLOCK_CNT ((SIMULA_FS_ENTRY_SIZE - (16 + 3 * 4)) / 4)

#define SIMULA_DEFAULT_FILE ".sfsf"

typedef unsigned int uint4_t;

typedef struct sfs_super_block
{
\tuint4_t type; /* Magic number to identify the file system */
\tuint4_t block_size; /* Unit of allocation */
\tuint4_t partition_size; /* in blocks */
\tuint4_t entry_size; /* in bytes */ 
\tuint4_t entry_table_size; /* in blocks */
\tuint4_t entry_table_block_start; /* in blocks */
\tuint4_t entry_count; /* Total entries in the file system */
\tuint4_t data_block_start; /* in blocks */
\tuint4_t reserved[SIMULA_FS_BLOCK_SIZE / 4 - 8];
} sfs_super_block_t; /* Making it of SIMULA_FS_BLOCK_SIZE */

typedef struct sfs_file_entry
{
\tchar name[16];
\tuint4_t size; /* in bytes */
\tuint4_t timestamp; /* Seconds since Epoch */
\tuint4_t perms; /* Permissions for user */
\tuint4_t blocks[SIMULA_FS_DATA_BLOCK_CNT];
} sfs_file_entry_t;

#endif
EOF
View Code

这里面有很多冗余字段,都是可以通过其他字段可以计算得知。

 代码实现 format_sfs.c

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <sys/types.h>
 4 #include <sys/stat.h>
 5 #include <fcntl.h>
 6 #include <unistd.h>
 7 
 8 #include "sfs_ds.h"
 9 
10 #define SFS_ENTRY_RATIO 0.10 /* 10% of all blocks */
11 #define SFS_ENTRY_TABLE_BLOCK_START 1
12 
13 sfs_super_block_t sb =
14 {
15     .type = SIMULA_FS_TYPE,
16     .block_size = SIMULA_FS_BLOCK_SIZE,
17     .entry_size = SIMULA_FS_ENTRY_SIZE,
18     .entry_table_block_start = SFS_ENTRY_TABLE_BLOCK_START
19 };
20 sfs_file_entry_t fe; /* All 0's */
21 
22 void write_super_block(int sfs_handle, sfs_super_block_t *sb)
23 {
24     write(sfs_handle, sb, sizeof(sfs_super_block_t));
25 }
26 void clear_file_entries(int sfs_handle, sfs_super_block_t *sb)
27 {
28     int i;
29 
30     for (i = 0; i < sb->entry_count; i++)
31     {
32         write(sfs_handle, &fe, sizeof(fe));
33     }
34 }
35 void mark_data_blocks(int sfs_handle, sfs_super_block_t *sb)
36 {
37     char c = 0;
38 
39     lseek(sfs_handle, sb->partition_size * sb->block_size - 1, SEEK_SET);
40     write(sfs_handle, &c, 1); /* To make the file size to partition size */
41 }
42 
43 int main(int argc, char *argv[])
44 {
45     int sfs_handle;
46 
47     if (argc != 2)
48     {
49         fprintf(stderr, "Usage: %s <partition size in 512-byte blocks>\n",
50             argv[0]);
51         return 1;
52     }
53     sb.partition_size = atoi(argv[1]);
54     sb.entry_table_size = sb.partition_size * SFS_ENTRY_RATIO;
55     sb.entry_count = sb.entry_table_size * sb.block_size / sb.entry_size;
56     sb.data_block_start = SFS_ENTRY_TABLE_BLOCK_START + sb.entry_table_size;
57 
58     sfs_handle = creat(SIMULA_DEFAULT_FILE,
59         S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
60     if (sfs_handle == -1)
61     {
62         perror("No permissions to format");
63         return 2;
64     }
65     write_super_block(sfs_handle, &sb);
66     clear_file_entries(sfs_handle, &sb);
67     mark_data_blocks(sfs_handle, &sb);
68     close(sfs_handle);
69     return 0;
70 }

执行一下代码创建format_sfs.c

cat << EOF |  sed -e "s/\\\t/\t/g" | tee format_sfs.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include "sfs_ds.h"

#define SFS_ENTRY_RATIO 0.10 /* 10% of all blocks */
#define SFS_ENTRY_TABLE_BLOCK_START 1

sfs_super_block_t sb =
{
\t.type = SIMULA_FS_TYPE,
\t.block_size = SIMULA_FS_BLOCK_SIZE,
\t.entry_size = SIMULA_FS_ENTRY_SIZE,
\t.entry_table_block_start = SFS_ENTRY_TABLE_BLOCK_START
};
sfs_file_entry_t fe; /* All 0's */

void write_super_block(int sfs_handle, sfs_super_block_t *sb)
{
\twrite(sfs_handle, sb, sizeof(sfs_super_block_t));
}
void clear_file_entries(int sfs_handle, sfs_super_block_t *sb)
{
\tint i;

\tfor (i = 0; i < sb->entry_count; i++)
\t{
\t\twrite(sfs_handle, &fe, sizeof(fe));
\t}
}
void mark_data_blocks(int sfs_handle, sfs_super_block_t *sb)
{
\tchar c = 0;

\tlseek(sfs_handle, sb->partition_size * sb->block_size - 1, SEEK_SET);
\twrite(sfs_handle, &c, 1); /* To make the file size to partition size */
}

int main(int argc, char *argv[])
{
\tint sfs_handle;

\tif (argc != 2)
\t{
\t\tfprintf(stderr, "Usage: %s <partition size in 512-byte blocks>\n",
\t\t\targv[0]);
\t\treturn 1;
\t}
\tsb.partition_size = atoi(argv[1]);
\tsb.entry_table_size = sb.partition_size * SFS_ENTRY_RATIO;
\tsb.entry_count = sb.entry_table_size * sb.block_size / sb.entry_size;
\tsb.data_block_start = SFS_ENTRY_TABLE_BLOCK_START + sb.entry_table_size;

\tsfs_handle = creat(SIMULA_DEFAULT_FILE,
\t\tS_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
\tif (sfs_handle == -1)
\t{
\t\tperror("No permissions to format");
\t\treturn 2;
\t}
\twrite_super_block(sfs_handle, &sb);
\tclear_file_entries(sfs_handle, &sb);
\tmark_data_blocks(sfs_handle, &sb);
\tclose(sfs_handle);
\treturn 0;
}
EOF
View Code

采用gcc模拟mkfs,生成一个.sfsf

gcc format_sfs.c -o format_sfs
./format_sfs 1024 # Partition size in blocks of 512-bytes
ls -al # List the .sfsf created with a size of 512 KiBytes

Part 2:

工具browse_sfs.c,显示文件系统的信息

  • quit – 退出
  • list – 显示文件
  • create <filename> – 创建文件
  • remove <filename> – 删除文件
  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include <unistd.h>
  6 #include <string.h>
  7 #include <time.h>
  8 
  9 #include "sfs_ds.h"
 10 
 11 sfs_super_block_t sb;
 12 
 13 void sfs_list(int sfs_handle)
 14 {
 15     int i;
 16     sfs_file_entry_t fe;
 17 
 18     lseek(sfs_handle, sb.entry_table_block_start * sb.block_size, SEEK_SET);
 19     for (i = 0; i < sb.entry_count; i++)
 20     {
 21         read(sfs_handle, &fe, sizeof(sfs_file_entry_t));
 22         if (!fe.name[0]) continue;
 23         printf("%-15s  %10d bytes  %c%c%c  %s",
 24             fe.name, fe.size,
 25             fe.perms & 04 ? 'r' : '-',
 26             fe.perms & 02 ? 'w' : '-',
 27             fe.perms & 01 ? 'x' : '-',
 28             ctime((time_t *)&fe.timestamp)
 29             );
 30     }
 31 }
 32 void sfs_create(int sfs_handle, char *fn)
 33 {
 34     int i;
 35     sfs_file_entry_t fe;
 36 
 37     lseek(sfs_handle, sb.entry_table_block_start * sb.block_size, SEEK_SET);
 38     for (i = 0; i < sb.entry_count; i++)
 39     {
 40         read(sfs_handle, &fe, sizeof(sfs_file_entry_t));
 41         if (!fe.name[0]) break;
 42         if (strcmp(fe.name, fn) == 0)
 43         {
 44             printf("File %s already exists\n", fn);
 45             return;
 46         }
 47     }
 48     if (i == sb.entry_count)
 49     {
 50         printf("No entries left for : %s\n", fn);
 51         return;
 52     }
 53 
 54     lseek(sfs_handle, -(off_t)(sb.entry_size), SEEK_CUR);
 55 
 56     strncpy(fe.name, fn, 15);
 57     fe.name[15] = 0;
 58     fe.size = 0;
 59     fe.timestamp = time(NULL);
 60     fe.perms = 07;
 61     for (i = 0; i < SIMULA_FS_DATA_BLOCK_CNT; i++)
 62     {
 63         fe.blocks[i] = 0;
 64     }
 65 
 66     write(sfs_handle, &fe, sizeof(sfs_file_entry_t));
 67 }
 68 void sfs_remove(int sfs_handle, char *fn)
 69 {
 70     int i;
 71     sfs_file_entry_t fe;
 72 
 73     lseek(sfs_handle, sb.entry_table_block_start * sb.block_size, SEEK_SET);
 74     for (i = 0; i < sb.entry_count; i++)
 75     {
 76         read(sfs_handle, &fe, sizeof(sfs_file_entry_t));
 77         if (!fe.name[0]) continue;
 78         if (strcmp(fe.name, fn) == 0) break;
 79     }
 80     if (i == sb.entry_count)
 81     {
 82         printf("File %s doesn't exist\n", fn);
 83         return;
 84     }
 85 
 86     lseek(sfs_handle, -(off_t)(sb.entry_size), SEEK_CUR);
 87 
 88     memset(&fe, 0, sizeof(sfs_file_entry_t));
 89     write(sfs_handle, &fe, sizeof(sfs_file_entry_t));
 90 }
 91 
 92 void browse_sfs(int sfs_handle)
 93 {
 94     int done;
 95     char cmd[256], *fn;
 96     int ret;
 97 
 98     done = 0;
 99 
100     printf("Welcome to SFS Browsing Shell v1.0\n\n");
101     printf("Block size     : %d bytes\n", sb.block_size);
102     printf("Partition size : %d blocks\n", sb.partition_size);
103     printf("File entry size: %d bytes\n", sb.entry_size);
104     printf("Entry tbl size : %d blocks\n", sb.entry_table_size);
105     printf("Entry count    : %d\n", sb.entry_count);
106     printf("\n");
107     while (!done)
108     {
109         printf(" $> ");
110         ret = scanf("%[^\n]", cmd);
111         if (ret < 0)
112         {
113             done = 1;
114             printf("\n");
115             continue;
116         }
117         else
118         {
119             getchar();
120             if (ret == 0) continue;
121         }
122         if (strcmp(cmd, "?") == 0)
123         {
124             printf("Supported commands:\n");
125             printf("\t?\tquit\tlist\tcreate\tremove\n");
126             continue;
127         }
128         else if (strcmp(cmd, "quit") == 0)
129         {
130             done = 1;
131             continue;
132         }
133         else if (strcmp(cmd, "list") == 0)
134         {
135             sfs_list(sfs_handle);
136             continue;
137         }
138         else if (strncmp(cmd, "create", 6) == 0)
139         {
140             if (cmd[6] == ' ')
141             {
142                 fn = cmd + 7;
143                 while (*fn == ' ') fn++;
144                 if (*fn != '\0') // (char) 0 145                 {
146                     sfs_create(sfs_handle, fn);
147                     continue;
148                 }
149             }
150         }
151         else if (strncmp(cmd, "remove", 6) == 0)
152         {
153             if (cmd[6] == ' ')
154             {
155                 fn = cmd + 7;
156                 while (*fn == ' ') fn++;
157                 if (*fn != '\0') // (char) 0
158                 {
159                     sfs_remove(sfs_handle, fn);
160                     continue;
161                 }
162             }
163         }
164         printf("Unknown/Incorrect command: %s\n", cmd);
165         printf("Supported commands:\n");
166         printf("\t?\tquit\tlist\tcreate <file>\tremove <file>\n");
167     }
168 }
169 
170 int main(int argc, char *argv[])
171 {
172     char *sfs_file = SIMULA_DEFAULT_FILE;
173     int sfs_handle;
174 
175     if (argc > 2)
176     {
177         fprintf(stderr, "Incorrect invocation. Possibilities are:\n");
178         fprintf(stderr,
179             "\t%s /* Picks up %s as the default partition_file */\n",
180             argv[0], SIMULA_DEFAULT_FILE);
181         fprintf(stderr, "\t%s [ partition_file ]\n", argv[0]);
182         return 1;
183     }
184     if (argc == 2)
185     {
186         sfs_file = argv[1];
187     }
188     sfs_handle = open(sfs_file, O_RDWR);
189     if (sfs_handle == -1)
190     {
191         fprintf(stderr, "Unable to browse SFS over %s\n", sfs_file);
192         return 2;
193     }
194     read(sfs_handle, &sb, sizeof(sfs_super_block_t));
195     if (sb.type != SIMULA_FS_TYPE)
196     {
197         fprintf(stderr, "Invalid SFS detected. Giving up.\n");
198         close(sfs_handle);
199         return 3;
200     }
201     browse_sfs(sfs_handle);
202     close(sfs_handle);
203     return 0;
204 }

通过以下命令创建 browse_sfs.c

cat << EOF |  sed -e "s/\\\t/\t/g" | tee browse_sfs.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <time.h>

#include "sfs_ds.h"

sfs_super_block_t sb;

void sfs_list(int sfs_handle)
{
\tint i;
\tsfs_file_entry_t fe;

\tlseek(sfs_handle, sb.entry_table_block_start * sb.block_size, SEEK_SET);
\tfor (i = 0; i < sb.entry_count; i++)
\t{
\t\tread(sfs_handle, &fe, sizeof(sfs_file_entry_t));
\t\tif (!fe.name[0]) continue;
\t\tprintf("%-15s  %10d bytes  %c%c%c  %s",
\t\t\tfe.name, fe.size,
\t\t\tfe.perms & 04 ? 'r' : '-',
\t\t\tfe.perms & 02 ? 'w' : '-',
\t\t\tfe.perms & 01 ? 'x' : '-',
\t\t\tctime((time_t *)&fe.timestamp)
\t\t\t);
\t}
}
void sfs_create(int sfs_handle, char *fn)
{
\tint i;
\tsfs_file_entry_t fe;

\tlseek(sfs_handle, sb.entry_table_block_start * sb.block_size, SEEK_SET);
\tfor (i = 0; i < sb.entry_count; i++)
\t{
\t\tread(sfs_handle, &fe, sizeof(sfs_file_entry_t));
\t\tif (!fe.name[0]) break;
\t\tif (strcmp(fe.name, fn) == 0)
\t\t{
\t\t\tprintf("File %s already exists\n", fn);
\t\t\treturn;
\t\t}
\t}
\tif (i == sb.entry_count)
\t{
\t\tprintf("No entries left for : %s\n", fn);
\t\treturn;
\t}

\tlseek(sfs_handle, -(off_t)(sb.entry_size), SEEK_CUR);

\tstrncpy(fe.name, fn, 15);
\tfe.name[15] = 0;
\tfe.size = 0;
\tfe.timestamp = time(NULL);
\tfe.perms = 07;
\tfor (i = 0; i < SIMULA_FS_DATA_BLOCK_CNT; i++)
\t{
\t\tfe.blocks[i] = 0;
\t}

\twrite(sfs_handle, &fe, sizeof(sfs_file_entry_t));
}
void sfs_remove(int sfs_handle, char *fn)
{
\tint i;
\tsfs_file_entry_t fe;

\tlseek(sfs_handle, sb.entry_table_block_start * sb.block_size, SEEK_SET);
\tfor (i = 0; i < sb.entry_count; i++)
\t{
\t\tread(sfs_handle, &fe, sizeof(sfs_file_entry_t));
\t\tif (!fe.name[0]) continue;
\t\tif (strcmp(fe.name, fn) == 0) break;
\t}
\tif (i == sb.entry_count)
\t{
\t\tprintf("File %s doesn't exist\n", fn);
\t\treturn;
\t}

\tlseek(sfs_handle, -(off_t)(sb.entry_size), SEEK_CUR);

\tmemset(&fe, 0, sizeof(sfs_file_entry_t));
\twrite(sfs_handle, &fe, sizeof(sfs_file_entry_t));
}

void browse_sfs(int sfs_handle)
{
\tint done;
\tchar cmd[256], *fn;
\tint ret;

\tdone = 0;

\tprintf("Welcome to SFS Browsing Shell v1.0\n\n");
\tprintf("Block size\t : %d bytes\n", sb.block_size);
\tprintf("Partition size : %d blocks\n", sb.partition_size);
\tprintf("File entry size: %d bytes\n", sb.entry_size);
\tprintf("Entry tbl size : %d blocks\n", sb.entry_table_size);
\tprintf("Entry count\t: %d\n", sb.entry_count);
\tprintf("\n");
\twhile (!done)
\t{
\t\tprintf(" $> ");
\t\tret = scanf("%[^\n]", cmd);
\t\tif (ret < 0)
\t\t{
\t\t\tdone = 1;
\t\t\tprintf("\n");
\t\t\tcontinue;
\t\t}
\t\telse
\t\t{
\t\t\tgetchar();
\t\t\tif (ret == 0) continue;
\t\t}
\t\tif (strcmp(cmd, "?") == 0)
\t\t{
\t\t\tprintf("Supported commands:\n");
\t\t\tprintf("\t?\tquit\tlist\tcreate\tremove\n");
\t\t\tcontinue;
\t\t}
\t\telse if (strcmp(cmd, "quit") == 0)
\t\t{
\t\t\tdone = 1;
\t\t\tcontinue;
\t\t}
\t\telse if (strcmp(cmd, "list") == 0)
\t\t{
\t\t\tsfs_list(sfs_handle);
\t\t\tcontinue;
\t\t}
\t\telse if (strncmp(cmd, "create", 6) == 0)
\t\t{
\t\t\tif (cmd[6] == ' ')
\t\t\t{
\t\t\t\tfn = cmd + 7;
\t\t\t\twhile (*fn == ' ') fn++;
\t\t\t\tif (*fn != '\0') // (char) 0 
\t\t\t\t{
\t\t\t\t\tsfs_create(sfs_handle, fn);
\t\t\t\t\tcontinue;
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse if (strncmp(cmd, "remove", 6) == 0)
\t\t{
\t\t\tif (cmd[6] == ' ')
\t\t\t{
\t\t\t\tfn = cmd + 7;
\t\t\t\twhile (*fn == ' ') fn++;
\t\t\t\tif (*fn != '\0') // (char) 0 
\t\t\t\t{
\t\t\t\t\tsfs_remove(sfs_handle, fn);
\t\t\t\t\tcontinue;
\t\t\t\t}
\t\t\t}
\t\t}
\t\tprintf("Unknown/Incorrect command: %s\n", cmd);
\t\tprintf("Supported commands:\n");
\t\tprintf("\t?\tquit\tlist\tcreate <file>\tremove <file>\n");
\t}
}

int main(int argc, char *argv[])
{
\tchar *sfs_file = SIMULA_DEFAULT_FILE;
\tint sfs_handle;

\tif (argc > 2)
\t{
\t\tfprintf(stderr, "Incorrect invocation. Possibilities are:\n");
\t\tfprintf(stderr,
\t\t\t"\t%s /* Picks up %s as the default partition_file */\n",
\t\t\targv[0], SIMULA_DEFAULT_FILE);
\t\tfprintf(stderr, "\t%s [ partition_file ]\n", argv[0]);
\t\treturn 1;
\t}
\tif (argc == 2)
\t{
\t\tsfs_file = argv[1];
\t}
\tsfs_handle = open(sfs_file, O_RDWR);
\tif (sfs_handle == -1)
\t{
\t\tfprintf(stderr, "Unable to browse SFS over %s\n", sfs_file);
\t\treturn 2;
\t}
\tread(sfs_handle, &sb, sizeof(sfs_super_block_t));
\tif (sb.type != SIMULA_FS_TYPE)
\t{
\t\tfprintf(stderr, "Invalid SFS detected. Giving up.\n");
\t\tclose(sfs_handle);
\t\treturn 3;
\t}
\tbrowse_sfs(sfs_handle);
\tclose(sfs_handle);
\treturn 0;
}
EOF
View Code

执行

gcc browse_sfs.c -o browse_sfs
sudo apt install rlwrap  -y
rlwrap ./browse_sfs      

will get the result

$ rlwrap ./browse_sfs
Welcome to SFS Browsing Shell v1.0

Block size       : 512 bytes
Partition size : 1024 blocks
File entry size: 64 bytes
Entry tbl size : 102 blocks
Entry count     : 816

 $> list
 $> create aaaa
 $> create bbbb
 $> list
aaaa                      0 bytes  rwx  Thu Jun 24 14:48:20 2973
bbbb                      0 bytes  rwx  Thu Jun 24 14:48:26 2973
 $> ?
Supported commands:
        ?       quit    list    create  remove

 

posted @ 2020-10-07 00:18  lvmxh  阅读(286)  评论(0编辑  收藏  举报