CS350 COS
COS
Loading...
Searching...
No Matches
newfs_o2fs.c
Go to the documentation of this file.
1
2#include <assert.h>
3#include <stdbool.h>
4#include <stdint.h>
5#include <string.h>
6#include <stdio.h>
7#include <stdlib.h>
8
9#include <unistd.h>
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <fcntl.h>
13#include <time.h>
14#include <getopt.h>
15
16#include <o2fs.h>
17
18#define ROUND_UP(_a, _b) (((_a) + (_b) - 1)/(_b))
19
20#define MAXBLOCKSIZE (64*1024*1024)
21
24
25bool verbose = false;
26bool hasManifest = false;
33
34#define TOKEN_EOF 0
35#define TOKEN_DIR 1
36#define TOKEN_END 2
37#define TOKEN_FILE 3
38#define TOKEN_STRING 4
39
42char tokenString[512];
43
44void LoadManifest(const char *manifest)
45{
46 int fd = open(manifest, O_RDONLY);
47 struct stat manifeststat;
48
49 if (fd < 0) {
50 perror("Cannot open manifest");
51 exit(1);
52 }
53
54 fstat(fd, &manifeststat);
55 tokenBuf = malloc(manifeststat.st_size + 1);
56 read(fd, tokenBuf, manifeststat.st_size);
57 tokenBuf[manifeststat.st_size] = '\0';
58
60 tokenString[0] = '\0';
61}
62
64{
65 int i;
66
67 while (*tokenCur == ' ' || *tokenCur == '\t' ||
68 *tokenCur == '\n' || *tokenCur == '\r')
69 tokenCur++;
70
71 for (i = 0; i < 512; i++)
72 {
73 tokenString[i] = tokenCur[i];
74 if (tokenCur[i] == ' ' || tokenCur[i] == '\t' ||
75 tokenCur[i] == '\n' || tokenCur[i] == '\r' ||
76 tokenCur[i] == '\0')
77 {
78 tokenString[i] = '\0';
79 tokenCur += i;
80 break;
81 }
82 }
83
84 if (strcmp(tokenString, "") == 0)
85 return TOKEN_EOF;
86 if (strcmp(tokenString, "DIR") == 0)
87 return TOKEN_DIR;
88 if (strcmp(tokenString, "END") == 0)
89 return TOKEN_END;
90 if (strcmp(tokenString, "FILE") == 0)
91 return TOKEN_FILE;
92 return TOKEN_STRING;
93}
94
95void
96FlushBlock(uint64_t offset, const void *buf, size_t len)
97{
98 assert(offset % blockSize == 0);
100
101 pwrite(diskfd, buf, len, offset);
102 if (len != blockSize) {
103 pwrite(diskfd, zerobuf, blockSize - len, offset + len);
104 }
105}
106
107
109AppendBlock(const void *buf, size_t len)
110{
111 uint64_t offset = lseek(diskfd, 0, SEEK_CUR);
112
113 FlushBlock(offset, buf, len);
114 lseek(diskfd, blockSize, SEEK_CUR);
115
116 return offset;
117}
118
121{
122 return AppendBlock(NULL, 0);
123}
124
125ObjID *AddFile(const char *file)
126{
127 int i = 0;
128 int fd;
129 ObjID *id = malloc(sizeof(ObjID));
130 BNode node;
131
132 memset(id, 0, sizeof(*id));
133 memset(&node, 0, sizeof(node));
134 memcpy(node.magic, BNODE_MAGIC, 8);
137
138 // Copy file
139 fd = open(file, O_RDONLY);
140 if (fd < 0) {
141 perror("Cannot open file");
142 exit(1);
143 }
144 while (1) {
145 int len = read(fd, tempbuf, blockSize);
146 if (len < 0) {
147 perror("File read error");
148 exit(1);
149 }
150 if (len == 0) {
151 break;
152 }
153
154 node.direct[i].device = 0;
155 node.direct[i].offset = AppendBlock(tempbuf, len);
156 node.size += (uint64_t)len;
157 i += 1;
158 }
159 close(fd);
160
161 // Construct BNode
162 uint64_t offset = AppendBlock(&node, sizeof(node));
163
164 // Construct ObjID
165 id->device = 0;
166 id->offset = offset;
167
168 return id;
169}
170
172{
173 int tok;
174 BDirEntry *entries = malloc(128 * sizeof(BDirEntry));
175 int entry = 0;
176 ObjID *id = malloc(sizeof(ObjID));
177 BNode node;
178
179 while (1)
180 {
181 memset(&entries[entry], 0, sizeof(BDirEntry));
182 tok = GetToken();
183 if (tok == TOKEN_FILE) {
184 tok = GetToken();
185 printf("FILE %s\n", tokenString);
186 strncpy((char *)entries[entry].name, tokenString, MAXNAMELEN);
187
188 tok = GetToken();
189 ObjID *fobj = AddFile(tokenString);
190 memcpy(&entries[entry].objId, fobj, sizeof(ObjID));
191 free(fobj);
192 } else if (tok == TOKEN_DIR) {
193 tok = GetToken();
194 printf("DIR %s\n", tokenString);
195 strncpy((char *)entries[entry].name, tokenString, MAXNAMELEN);
196 ObjID *dobj = AddDirectory();
197 memcpy(&entries[entry].objId, dobj, sizeof(ObjID));
198 free(dobj);
199 } else if (tok == TOKEN_END) {
200 printf("END\n");
201 break;
202 } else if (tok == TOKEN_EOF) {
203 printf("Unexpected end of file\n");
204 exit(1);
205 } else {
206 printf("Unknown token '%s'\n", tokenString);
207 exit(1);
208 }
209
210 memcpy(entries[entry].magic, BDIR_MAGIC, 8);
211 // entries[entry].size ...
212 entries[entry].flags = 0;
213 entries[entry].ctime = (uint64_t)time(NULL);
214 entries[entry].mtime = (uint64_t)time(NULL);
215 strncpy((char *)entries[entry].user, "root", MAXUSERNAMELEN);
216 strncpy((char *)entries[entry].group, "root", MAXUSERNAMELEN);
217
218 entry++;
219 }
220
221 // Write Directory
222
223 // Make sure we fit into a single indirect
224 // block to simplify the logic below.
225 uint64_t size = entry * sizeof(BDirEntry);
227 uint64_t offset = AppendBlock(entries, size);
228
229 // Write Inode
230 memset(&node, 0, sizeof(node));
231 memcpy(node.magic, BNODE_MAGIC, 8);
234 node.size = size;
235 node.direct[0].device = 0;
236 node.direct[0].offset = offset;
237 uint64_t nodeoff = AppendBlock(&node, sizeof(node));
238
239 memset(id, 0, sizeof(*id));
240 id->device = 0;
241 id->offset = nodeoff;
242
243 return id;
244}
245
247{
248 off_t off = lseek(diskfd, 0, SEEK_CUR) / blockSize;
249
250 /* Code below only supports using the first 16K blocks */
251 assert(off < blockSize);
252
254
255 /* Mark the blocks in use up to the current offset */
256 assert(off > 8);
257 for (off_t i = 0; i < (off / 8); i++) {
258 tempbuf[i] = 0xFF;
259 }
260 for (off_t i = 0; i < (off % 8); i++) {
261 tempbuf[off / 8] |= 1 << i;
262 }
263
264 for (int i = 0; i < bitmapSize; i++)
266}
267
268void Superblock(ObjID *objid)
269{
270 SuperBlock sb;
271
272 memset(&sb, 0, sizeof(sb));
277 sb.blockSize = blockSize;
280
281 if (objid)
282 memcpy(&sb.root, objid, sizeof(ObjID));
283
284 FlushBlock(0, &sb, sizeof(sb));
285}
286
287void usage()
288{
289 printf("Usage: newfs_o2fs [OPTIONS] special-device\n");
290 printf("Options:\n");
291 printf(" -m, --manifest Manifest of files to copy to file system\n");
292 printf(" -s, --size Size in megabytes of device or disk image\n");
293 printf(" -v, --verbose Verbose logging\n");
294 printf(" -h, --help Print help message\n");
295}
296
297int main(int argc, char * const *argv)
298{
299 int ch;
300 int status;
301
302 // Sanity check
303 assert(sizeof(BDirEntry) == 512);
304
305 struct option longopts[] = {
306 { "manifest", required_argument, NULL, 'm' },
307 { "size", required_argument, NULL, 's' },
308 { "verbose", no_argument, NULL, 'v' },
309 { "help", no_argument, NULL, 'h' },
310 { NULL, 0, NULL, 0 }
311 };
312
313 while ((ch = getopt_long(argc, argv, "m:s:vh", longopts, NULL)) != -1)
314 {
315 switch (ch) {
316 case 'm':
317 hasManifest = true;
318 LoadManifest(optarg);
319 break;
320 case 's':
321 diskSize = atol(optarg) * 1024 * 1024;
322 break;
323 case 'v':
324 verbose = true;
325 break;
326 case 'h':
327 usage();
328 return 0;
329 default:
330 usage();
331 return 1;
332 }
333 }
334
335 argc -= optind;
336 argv += optind;
337
338 if (argc != 1) {
339 usage();
340 return 1;
341 }
342
343 diskfd = open(argv[0], O_RDWR | O_CREAT, 0660);
344 if (diskfd < 0) {
345 perror("Cannot open special device or disk image");
346 return 1;
347 }
348
349 status = fstat(diskfd, &diskstat);
350 if (status < 0) {
351 perror("Cannot fstat special device or disk image");
352 return 1;
353 }
354
355 if (diskstat.st_size == 0 && diskSize == 0) {
356 printf("Error: Must specify size for disk images\n");
357 usage();
358 return 1;
359 }
360
361 if (diskstat.st_size == 0)
363
364 /* Skip superblock */
366 lseek(diskfd, diskOffset, SEEK_SET);
368
369 /* Zero the bitmap (and skip past it) */
371 for (int i = 0; i < bitmapSize; i++)
373
374 ObjID *root = NULL;
375 if (hasManifest) {
376 int tok;
377
378 tok = GetToken();
379 if (tok != TOKEN_DIR) {
380 printf("Expected 'DIR' token, but found '%s'\n", tokenString);
381 exit(1);
382 }
383 tok = GetToken();
384 if (tok != TOKEN_STRING || strcmp(tokenString, "/") != 0) {
385 printf("Expected '/' token\n");
386 exit(1);
387 }
388
389 root = AddDirectory();
390 tok = GetToken();
391 if (tok != TOKEN_EOF) {
392 printf("Expected end-of-file, but found '%s'\n", tokenString);
393 exit(1);
394 }
395 }
396
397 /* Write bitmap */
398 BlockBitmap();
399
400 Superblock(root);
401 free(root);
402
403 close(diskfd);
404}
405
#define assert(_expr)
Definition: assert.h:7
static char buf[4096]
Definition: ethdump.c:10
time_t time(time_t *t)
Definition: time.c:20
uint32_t size
Definition: multiboot.h:0
uint64_t len
Definition: multiboot.h:2
char * tokenCur
Definition: newfs_o2fs.c:41
void Superblock(ObjID *objid)
Definition: newfs_o2fs.c:268
struct stat diskstat
Definition: newfs_o2fs.c:32
ObjID * AddFile(const char *file)
Definition: newfs_o2fs.c:125
void usage()
Definition: newfs_o2fs.c:287
uint64_t bitmapSize
Definition: newfs_o2fs.c:30
#define TOKEN_DIR
Definition: newfs_o2fs.c:35
ObjID * AddDirectory()
Definition: newfs_o2fs.c:171
uint64_t blockSize
Definition: newfs_o2fs.c:29
void LoadManifest(const char *manifest)
Definition: newfs_o2fs.c:44
uint64_t AppendEmpty(void)
Definition: newfs_o2fs.c:120
bool hasManifest
Definition: newfs_o2fs.c:26
int diskfd
Definition: newfs_o2fs.c:31
char * tokenBuf
Definition: newfs_o2fs.c:40
#define TOKEN_STRING
Definition: newfs_o2fs.c:38
uint64_t diskSize
Definition: newfs_o2fs.c:27
void BlockBitmap()
Definition: newfs_o2fs.c:246
uint64_t AppendBlock(const void *buf, size_t len)
Definition: newfs_o2fs.c:109
bool verbose
Definition: newfs_o2fs.c:25
#define MAXBLOCKSIZE
Definition: newfs_o2fs.c:20
#define ROUND_UP(_a, _b)
Definition: newfs_o2fs.c:18
#define TOKEN_FILE
Definition: newfs_o2fs.c:37
uint64_t diskOffset
Definition: newfs_o2fs.c:28
int main(int argc, char *const *argv)
Definition: newfs_o2fs.c:297
#define TOKEN_END
Definition: newfs_o2fs.c:36
void FlushBlock(uint64_t offset, const void *buf, size_t len)
Definition: newfs_o2fs.c:96
char tempbuf[MAXBLOCKSIZE]
Definition: newfs_o2fs.c:22
int GetToken()
Definition: newfs_o2fs.c:63
char zerobuf[MAXBLOCKSIZE]
Definition: newfs_o2fs.c:23
#define TOKEN_EOF
Definition: newfs_o2fs.c:34
char tokenString[512]
Definition: newfs_o2fs.c:42
uint64_t flags
Definition: o2fs.h:103
uint8_t magic[8]
Definition: o2fs.h:84
#define SUPERBLOCK_MAGIC
Definition: o2fs.h:63
#define BDIR_MAGIC
Definition: o2fs.h:112
uint8_t magic[8]
Definition: o2fs.h:47
ObjID root
Definition: o2fs.h:58
uint64_t blockCount
Definition: o2fs.h:52
uint64_t offset
Definition: o2fs.h:71
#define MAXNAMELEN
Definition: o2fs.h:23
uint16_t versionMinor
Definition: o2fs.h:86
#define MAXUSERNAMELEN
Definition: o2fs.h:22
uint64_t device
Definition: o2fs.h:70
#define BNODE_MAGIC
Definition: o2fs.h:93
uint16_t versionMinor
Definition: o2fs.h:49
uint16_t versionMajor
Definition: o2fs.h:48
uint64_t mtime
Definition: o2fs.h:105
uint64_t ctime
Definition: o2fs.h:104
uint64_t bitmapSize
Definition: o2fs.h:54
uint64_t blockSize
Definition: o2fs.h:53
#define O2FS_VERSION_MINOR
Definition: o2fs.h:31
uint64_t size
Definition: o2fs.h:88
uint16_t versionMajor
Definition: o2fs.h:85
BPtr direct[O2FS_DIRECT_PTR]
Definition: o2fs.h:90
uint64_t bitmapOffset
Definition: o2fs.h:55
#define O2FS_VERSION_MAJOR
Definition: o2fs.h:30
Definition: o2fs.h:99
Definition: o2fs.h:83
Definition: o2fs.h:36
off_t st_size
Definition: stat.h:11
Definition: stat.h:5
#define NULL
Definition: stddef.h:6
#define SEEK_SET
Definition: stdio.h:14
#define SEEK_CUR
Definition: stdio.h:15
int printf(const char *fmt,...)
Definition: printf.c:212
void free(void *buf)
Definition: malloc.c:169
void exit(int status)
Definition: exit.c:36
void * malloc(size_t sz)
Definition: malloc.c:160
int strcmp(const char *s1, const char *s2)
Definition: string.c:81
char * strncpy(char *to, const char *from, size_t len)
Definition: string.c:34
void * memset(void *dst, int c, size_t len)
Definition: string.c:164
void * memcpy(void *dst, const void *src, size_t len)
Definition: string.c:177
int64_t off_t
Definition: types.h:20
unsigned long uint64_t
Definition: types.h:13