2 * JOS file system format
7 // We don't actually want to define off_t!
8 #define off_t xxx_off_t
19 #include <sys/types.h>
25 // Prevent inc/types.h, included from inc/fs.h,
26 // from attempting to redefine types defined in the host's inttypes.h.
27 #define JOS_INC_TYPES_H
28 // Typedef the types that inc/mmu.h needs.
29 typedef uint32_t physaddr_t
;
30 typedef uint32_t off_t
;
36 #define nelem(x) (sizeof(x) / sizeof((x)[0]))
37 typedef struct Super Super
;
38 typedef struct File File
;
62 struct Block cache
[16];
65 readn(int f
, void *av
, size_t n
)
73 size_t m
= read(f
, a
+ t
, n
- t
);
94 z
[1] = (y
>> 8) & 0xFF;
95 z
[2] = (y
>> 16) & 0xFF;
96 z
[3] = (y
>> 24) & 0xFF;
100 swizzlefile(struct File
*f
)
104 if (f
->f_name
[0] == 0)
106 swizzle((uint32_t*) &f
->f_size
);
108 for (i
= 0; i
< NDIRECT
; i
++)
109 swizzle(&f
->f_direct
[i
]);
110 swizzle(&f
->f_indirect
);
114 swizzleblock(struct Block
*b
)
123 s
= (struct Super
*) b
->buf
;
124 swizzle(&s
->s_magic
);
125 swizzle(&s
->s_nblocks
);
126 swizzlefile(&s
->s_root
);
129 f
= (struct File
*) b
->buf
;
130 for (i
= 0; i
< BLKFILES
; i
++)
134 u
= (uint32_t*) b
->buf
;
135 for (i
= 0; i
< BLKSIZE
/ 4; i
++)
142 flushb(struct Block
*b
)
145 if (lseek(diskfd
, b
->bno
* BLKSIZE
, 0) < 0
146 || write(diskfd
, b
->buf
, BLKSIZE
) != BLKSIZE
) {
148 fprintf(stderr
, "\n");
155 getblk(uint32_t bno
, int clr
, uint32_t type
)
161 if (bno
>= nblocks
) {
162 fprintf(stderr
, "attempt to access past end of disk bno=%d\n", bno
);
167 for (i
= 0; i
< nelem(cache
); i
++) {
168 if (cache
[i
].bno
== bno
) {
173 && (least
== -1 || cache
[i
].used
< cache
[least
].used
))
178 fprintf(stderr
, "panic: block cache full\n");
186 if (lseek(diskfd
, bno
*BLKSIZE
, 0) < 0
187 || readn(diskfd
, b
->buf
, BLKSIZE
) != BLKSIZE
) {
188 fprintf(stderr
, "read block %d: ", bno
);
190 fprintf(stderr
, "\n");
199 memset(b
->buf
, 0, sizeof(b
->buf
));
202 fprintf(stderr
, "panic: block #%d is busy\n", b
->bno
);
205 /* it is important to reset b->type in case we reuse a block for a
206 * different purpose while it is still in the cache - this can happen
207 * for example if a file ends exactly on a block boundary */
214 putblk(struct Block
*b
)
220 opendisk(const char *name
)
225 if ((diskfd
= open(name
, O_RDWR
| O_CREAT
, 0666)) < 0) {
226 fprintf(stderr
, "open %s: ", name
);
228 fprintf(stderr
, "\n");
232 if ((r
= ftruncate(diskfd
, 0)) < 0
233 || (r
= ftruncate(diskfd
, nblocks
* BLKSIZE
)) < 0) {
234 fprintf(stderr
, "truncate %s: ", name
);
239 nbitblock
= (nblocks
+ BLKBITSIZE
- 1) / BLKBITSIZE
;
240 for (i
= 0; i
< nbitblock
; i
++){
241 b
= getblk(2 + i
, 0, BLOCK_BITS
);
242 memset(b
->buf
, 0xFF, BLKSIZE
);
246 nextb
= 2 + nbitblock
;
248 super
.s_magic
= FS_MAGIC
;
249 super
.s_nblocks
= nblocks
;
250 super
.s_root
.f_type
= FTYPE_DIR
;
251 strcpy(super
.s_root
.f_name
, "/");
255 storeblk(struct File
*f
, struct Block
*b
, int nblk
)
258 f
->f_direct
[nblk
] = b
->bno
;
259 else if (nblk
< NINDIRECT
) {
260 struct Block
*bindir
;
261 if (f
->f_indirect
== 0) {
262 bindir
= getblk(nextb
++, 1, BLOCK_BITS
);
263 f
->f_indirect
= bindir
->bno
;
265 bindir
= getblk(f
->f_indirect
, 0, BLOCK_BITS
);
266 ((uint32_t*)bindir
->buf
)[nblk
] = b
->bno
;
269 fprintf(stderr
, "file too large\n");
275 allocfile(struct File
*dirf
, const char *name
, struct Block
**dirb
)
280 nblk
= (int)((dirf
->f_size
+ BLKSIZE
- 1) / BLKSIZE
) - 1;
281 if (nblk
>= NDIRECT
) {
282 struct Block
*idirb
= getblk(dirf
->f_indirect
, 0, BLOCK_BITS
);
283 *dirb
= getblk(((uint32_t*)idirb
->buf
) [nblk
], 0, BLOCK_DIR
);
285 } else if (nblk
>= 0)
286 *dirb
= getblk(dirf
->f_direct
[nblk
], 0, BLOCK_DIR
);
290 ino
= (struct File
*) (*dirb
)->buf
;
291 for (i
= 0; i
< BLKFILES
; i
++)
292 if (ino
[i
].f_name
[0] == '\0') {
300 *dirb
= getblk(nextb
++, 1, BLOCK_DIR
);
301 storeblk(dirf
, *dirb
, ++nblk
);
302 dirf
->f_size
+= BLKSIZE
;
303 assert((nblk
+ 1) * BLKSIZE
== dirf
->f_size
);
305 ino
= (struct File
*) (*dirb
)->buf
;
308 strcpy(ino
->f_name
, name
);
313 writefile(struct File
*dirf
, const char *name
)
319 struct Block
*dirb
, *b
;
321 if ((fd
= open(name
, O_RDONLY
)) < 0) {
322 fprintf(stderr
, "open %s:", name
);
327 last
= strrchr(name
, '/');
333 f
= allocfile(dirf
, last
, &dirb
);
334 f
->f_type
= FTYPE_REG
;
337 for (nblk
= 0; ; nblk
++) {
338 b
= getblk(nextb
, 1, BLOCK_FILE
);
339 n
= readn(fd
, b
->buf
, BLKSIZE
);
341 fprintf(stderr
, "reading %s: ", name
);
350 storeblk(f
, b
, nblk
);
355 f
->f_size
= nblk
*BLKSIZE
+ n
;
360 writedirectory(struct File
*parentdirf
, char *name
, int root
)
366 char pathbuf
[PATH_MAX
];
368 struct Block
*dirb
= NULL
;
370 if ((dir
= opendir(name
)) == NULL
) {
371 fprintf(stderr
, "open %s:", name
);
377 const char *last
= strrchr(name
, '/');
383 dirf
= allocfile(parentdirf
, last
, &dirb
);
384 dirf
->f_type
= FTYPE_DIR
;
389 strcpy(pathbuf
, name
);
390 namelen
= strlen(pathbuf
);
391 if (pathbuf
[namelen
- 1] != '/') {
392 pathbuf
[namelen
++] = '/';
393 pathbuf
[namelen
] = 0;
396 while ((ent
= readdir(dir
)) != NULL
) {
397 int ent_namlen
= strlen(ent
->d_name
);
398 strcpy(pathbuf
+ namelen
, ent
->d_name
);
400 // don't depend on unreliable parts of the dirent structure
401 if (stat(pathbuf
, &s
) < 0)
404 if (S_ISREG(s
.st_mode
))
405 writefile(dirf
, pathbuf
);
406 else if (S_ISDIR(s
.st_mode
)
407 && (ent_namlen
> 1 || ent
->d_name
[0] != '.')
408 && (ent_namlen
> 2 || ent
->d_name
[0] != '.' || ent
->d_name
[1] != '.')
409 && (ent_namlen
> 3 || ent
->d_name
[0] != 'C' || ent
->d_name
[1] != 'V' || ent
->d_name
[2] != 'S'))
410 writedirectory(dirf
, pathbuf
, 0);
424 for (i
= 0; i
< nextb
; i
++) {
425 b
= getblk(2 + i
/BLKBITSIZE
, 0, BLOCK_BITS
);
426 ((uint32_t*)b
->buf
)[(i
%BLKBITSIZE
)/32] &= ~(1<<(i
%32));
430 // this is slow but not too slow. i do not care
431 if (nblocks
!= nbitblock
*BLKBITSIZE
) {
432 b
= getblk(2+nbitblock
-1, 0, BLOCK_BITS
);
433 for (i
= nblocks
% BLKBITSIZE
; i
< BLKBITSIZE
; i
++)
434 ((uint32_t*)b
->buf
)[i
/32] &= ~(1<<(i
%32));
438 b
= getblk(1, 1, BLOCK_SUPER
);
439 memmove(b
->buf
, &super
, sizeof(Super
));
448 for (i
= 0; i
< nelem(cache
); i
++)
456 fprintf(stderr
, "Usage: fsformat kern/fs.img NBLOCKS files...\n\
457 fsformat kern/fs.img NBLOCKS -r DIR\n");
462 main(int argc
, char **argv
)
467 assert(BLKSIZE
% sizeof(struct File
) == 0);
472 nblocks
= strtol(argv
[2], &s
, 0);
473 if (*s
|| s
== argv
[2] || nblocks
< 2 || nblocks
> 1024)
478 if (strcmp(argv
[3], "-r") == 0) {
481 writedirectory(&super
.s_root
, argv
[4], 1);
483 for (i
= 3; i
< argc
; i
++)
484 writefile(&super
.s_root
, argv
[i
]);