📄 genext2fs.c
字号:
bkref = &get_nod(fs, nod)->i_block[++bw->bpdir]; if(extend) // allocate block *bkref = hole ? 0 : alloc_blk(fs); } // first block in indirect block else if(bw->bpdir == EXT2_NDIR_BLOCKS) { bw->bnum++; bw->bpdir = EXT2_IND_BLOCK; bw->bpind = 0; if(extend) // allocate indirect block get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs); b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); bkref = &b[bw->bpind]; if(extend) // allocate first block *bkref = hole ? 0 : alloc_blk(fs); } // block in indirect block else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1)) { bw->bpind++; b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); bkref = &b[bw->bpind]; if(extend) // allocate block *bkref = hole ? 0 : alloc_blk(fs); } // first block in first indirect block in first double indirect block else if(bw->bpdir == EXT2_IND_BLOCK) { bw->bnum += 2; bw->bpdir = EXT2_DIND_BLOCK; bw->bpind = 0; bw->bpdind = 0; if(extend) // allocate double indirect block get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs); b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); if(extend) // allocate first indirect block b[bw->bpind] = alloc_blk(fs); b = (uint32*)get_blk(fs, b[bw->bpind]); bkref = &b[bw->bpdind]; if(extend) // allocate first block *bkref = hole ? 0 : alloc_blk(fs); } // block in indirect block in double indirect block else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1)) { bw->bpdind++; b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); b = (uint32*)get_blk(fs, b[bw->bpind]); bkref = &b[bw->bpdind]; if(extend) // allocate block *bkref = hole ? 0 : alloc_blk(fs); } // first block in indirect block in double indirect block else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1)) { bw->bnum++; bw->bpdind = 0; bw->bpind++; b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); if(extend) // allocate indirect block b[bw->bpind] = alloc_blk(fs); b = (uint32*)get_blk(fs, b[bw->bpind]); bkref = &b[bw->bpdind]; if(extend) // allocate first block *bkref = hole ? 0 : alloc_blk(fs); } // I don't do triple indirect - it's such a small filesystem ... else errexit("file too big ! blocks list for inode %d extends past double indirect blocks!", nod); if(*bkref) { bw->bnum++; if(!allocated(fs->bbm, *bkref)) errexit("[block %d of inode %d is unallocated !]", *bkref, nod); } if(extend) get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK; return *bkref;}// add blocks to an inode (file/dir/etc...)void extend_blk(filesystem *fs, uint32 nod, block b, int amount){ int create = amount; blockwalker bw, lbw; uint32 bk; init_bw(fs, nod, &bw); lbw = bw; while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END) lbw = bw; bw = lbw; while(create) { int i, copyb = 0; if(!(fs->sb.s_reserved[200] & OP_HOLES)) copyb = 1; else for(i = 0; i < BLOCKSIZE / 4; i++) if(((int32*)(b + BLOCKSIZE * (amount - create)))[i]) { copyb = 1; break; } if((bk = walk_bw(fs, nod, &bw, &create, !copyb)) == WALK_END) break; if(copyb) memcpy(get_blk(fs, bk), b + BLOCKSIZE * (amount - create - 1), BLOCKSIZE); }}// link an entry (inode #) to a directoryvoid add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name){ blockwalker bw; uint32 bk; uint8 *b; directory *d; int reclen, nlen; if((get_nod(fs, dnod)->i_mode & FM_IFMT) != FM_IFDIR) errexit("can't add '%s' to a non-directory", name); if(!*name) errexit("bad name '%s' (not meaningful)", name); if(strchr(name, '/')) errexit("bad name '%s' (contains a slash)", name); nlen = strlen(name); reclen = sizeof(directory) + rndup(nlen, 4); if(reclen > BLOCKSIZE) errexit("bad name '%s' (too long)", name); init_bw(fs, dnod, &bw); while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir { b = get_blk(fs, bk); // for all dir entries in block for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len)) { // if empty dir entry, large enough, use it if((!d->d_inode) && (d->d_rec_len >= reclen)) { d->d_inode = nod; get_nod(fs, nod)->i_links_count++; d->d_name_len = nlen; strncpy(d->d_name, name, nlen); return; } // if entry with enough room (last one?), shrink it & use it if(d->d_rec_len >= (sizeof(directory) + rndup(d->d_name_len, 4) + reclen)) { reclen = d->d_rec_len; d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4); reclen -= d->d_rec_len; d = (directory*) (((int8*)d) + d->d_rec_len); d->d_rec_len = reclen; d->d_inode = nod; get_nod(fs, nod)->i_links_count++; d->d_name_len = nlen; strncpy(d->d_name, name, nlen); return; } } } // we found no free entry in the directory, so we add a block b = get_workblk(); d = (directory*)b; d->d_inode = nod; get_nod(fs, nod)->i_links_count++; d->d_rec_len = BLOCKSIZE; d->d_name_len = nlen; strncpy(d->d_name, name, nlen); extend_blk(fs, dnod, b, 1); get_nod(fs, dnod)->i_size += BLOCKSIZE; free_workblk(b);}// find an entry in a directoryuint32 find_dir(filesystem *fs, uint32 nod, const char * name){ blockwalker bw; uint32 bk; int nlen = strlen(name); init_bw(fs, nod, &bw); while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END) { directory *d; uint8 *b; b = get_blk(fs, bk); for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len)) if(d->d_inode && (nlen == d->d_name_len) && !strncmp(d->d_name, name, nlen)) return d->d_inode; } return 0;}// find the inode of a full pathuint32 find_path(filesystem *fs, uint32 nod, const char * name){ char *p, *n, *n2 = strdup(name); n = n2; while(*n == '/') { nod = EXT2_ROOT_INO; n++; } while(*n) { if((p = strchr(n, '/'))) (*p) = 0; if(!(nod = find_dir(fs, nod, n))) break; if(p) n = p + 1; else break; } free(n2); return nod;}// make a full-fledged directory (i.e. with "." & "..")uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode){ uint32 nod; if((nod = find_dir(fs, parent_nod, name))) return nod; nod = alloc_nod(fs); get_nod(fs, nod)->i_mode = FM_IFDIR | mode; add2dir(fs, parent_nod, nod, name); add2dir(fs, nod, nod, "."); add2dir(fs, nod, parent_nod, ".."); fs->gd.bg_used_dirs_count++; return nod;}// make a symlinkuint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint8 * b){ uint32 nod = alloc_nod(fs); get_nod(fs, nod)->i_mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO; get_nod(fs, nod)->i_size = size; add2dir(fs, parent_nod, nod, name); if(size <= 4 * (EXT2_TIND_BLOCK+1)) { strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size); return nod; } extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE); return nod;}// make a file from a FILE*uint32 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f){ uint8 * b; uint32 nod = alloc_nod(fs); get_nod(fs, nod)->i_mode = FM_IFREG | mode; get_nod(fs, nod)->i_size = size; add2dir(fs, parent_nod, nod, name); if(!(b = (uint8*)malloc(rndup(size, BLOCKSIZE)))) errexit("not enough mem to read file '%s'", name); memset(b, 0,rndup(size, BLOCKSIZE)); if(f) fread(b, size, 1, f); else memset(b, 0, size); extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE); free(b); return nod;}// retrieves a mode info from a struct statuint32 get_mode(struct stat *st){ uint32 mode = 0; if(st->st_mode & S_IRUSR) mode |= FM_IRUSR | FM_IRGRP | FM_IROTH; if(st->st_mode & S_IWUSR) mode |= FM_IWUSR | FM_IWGRP | FM_IWOTH; if(st->st_mode & S_IXUSR) mode |= FM_IXUSR | FM_IXGRP | FM_IXOTH; return mode;}// retrieves a mode info from a stringuint32 get_modestr(const char *p){ uint32 mode = 0; if(p[0] == 'r') mode |= FM_IRUSR | FM_IRGRP | FM_IROTH; if(p[1] == 'w') mode |= FM_IWUSR | FM_IWGRP | FM_IWOTH; if(p[2] == 'x' || p[2] == 's') mode |= FM_IXUSR | FM_IXGRP | FM_IXOTH; return mode;}// basename of a path - free mechar * basename(const char * fullpath){ char * p = strrchr(fullpath, '/'); return strdup(p ? p + 1 : fullpath);}// dirname of a path - free mechar * dirname(const char * fullpath){ char * p, * n = strdup(fullpath); if((p = strrchr(n, '/'))) *(p+1) = 0; else *n = 0; return n;}// adds entries to the filesystem from a text filevoid add2fs_from_file(filesystem *fs, uint32 this_nod, FILE * fh){ uint32 mode; uint32 nod, nod2; char cmod[11], *path, *name, *dir; int major, minor; while(fscanf(fh, "%10s", cmod)) { if(feof(fh)) break; mode = get_modestr(cmod + 1); switch(*cmod) { case 'd': fscanf(fh, "%" SCANF_PREFIX "s\n", SCANF_STRING(path)); break; case 'c': mode |= FM_IFCHR; fscanf(fh, "%i, %i %" SCANF_PREFIX "s\n", &major, &minor, SCANF_STRING(path)); break; case 'b': mode |= FM_IFBLK; fscanf(fh, "%i, %i %" SCANF_PREFIX "s\n", &major, &minor, SCANF_STRING(path)); break; case '#': while(fgetc(fh) != '\n'); continue; default: errexit("malformed text input file"); } name = basename(path); dir = dirname(path); free(path); if(!(nod = find_path(fs, this_nod, dir))) errexit("can't find directory '%s' to create '%s''", dir, name); free(dir); if((!strcmp(name, ".")) || (!strcmp(name, ".."))) { free(name); continue; } switch(*cmod) { case 'd': mkdir_fs(fs, nod, name, mode); break; case 'c': case 'b': nod2 = alloc_nod(fs); get_nod(fs, nod2)->i_mode = mode; ((uint8*)get_nod(fs, nod2)->i_block)[0] = minor; ((uint8*)get_nod(fs, nod2)->i_block)[1] = major; add2dir(fs, nod, nod2, name); break; } free(name); }}// adds a tree of entries to the filesystem from current dirvoid add2fs_from_dir(filesystem *fs, uint32 this_nod){ uint32 nod; FILE *fh; DIR *dh; struct dirent *dent; struct stat st; uint8 *b; if(!(dh = opendir("."))) pexit("."); while((dent = readdir(dh))) { if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue; lstat(dent->d_name, &st); switch(st.st_mode & S_IFMT) { case S_IFCHR: case S_IFBLK: nod = alloc_nod(fs); get_nod(fs, nod)->i_mode = (((st.st_mode & S_IFMT) == S_IFCHR) ? FM_IFCHR : FM_IFBLK) | get_mode(&st); ((uint8*)get_nod(fs, nod)->i_block)[0] = (st.st_rdev & 0xff); ((uint8*)get_nod(fs, nod)->i_block)[1] = (st.st_rdev >> 8); add2dir(fs, this_nod, nod, dent->d_name); break; case S_IFLNK: if(!(b = (uint8*)malloc(rndup(st.st_size, BLOCKSIZE)))) errexit("out of memory"); if(readlink(dent->d_name, (char*)b, st.st_size) < 0) pexit(dent->d_name); mklink_fs(fs, this_nod, dent->d_name, st.st_size, b); free(b); break; case S_IFREG: if(!(fh = fopen(dent->d_name, "r"))) pexit(dent->d_name); mkfile_fs(fs, this_nod, dent->d_name, get_mode(&st), st.st_size, fh); fclose(fh); break; case S_IFDIR: nod = mkdir_fs(fs, this_nod, dent->d_name, get_mode(&st)); if(chdir(dent->d_name) < 0) pexit(dent->d_name); add2fs_from_dir(fs, nod); chdir(".."); break; default: fprintf(stderr, "ignoring entry %s", dent->d_name); } } closedir(dh);}// endianness swap of x-indirect blocksvoid swap_goodblocks(filesystem *fs, inode *nod){ int i; int nblk = nod->i_blocks / INOBLK; if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR))) for(i = 0; i <= EXT2_TIND_BLOCK; i++) nod->i_block[i] = swab32(nod->i_block[i]); if(nblk <= EXT2_IND_BLOCK) return; swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK])); if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4) return; for(i = 0; i < BLOCKSIZE/4; i++) if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i) swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i])); swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK])); if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4) return; errexit("too big file on the filesystem");}void swap_badblocks(filesystem *fs, inode *nod){ int i; int nblk = nod->i_blocks / INOBLK; if((nod->i_size && !nblk) || (nod->i_mode & (FM_IFBLK | FM_IFCHR))) for(i = 0; i <= EXT2_TIND_BLOCK; i++) nod->i_block[i] = swab32(nod->i_block[i]); if(nblk <= EXT2_IND_BLOCK) return; swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK])); if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4) return; swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK])); for(i = 0; i < BLOCKSIZE/4; i++) if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i) swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i])); if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4) return; errexit("too big file on the filesystem");}// endianness swap of the whole filesystemvoid swap_goodfs(filesystem *fs){ int i; for(i = 1; i < fs->sb.s_inodes_count; i++) { inode *nod = get_nod(fs, i); if(nod->i_mode & FM_IFDIR) { blockwalker bw; uint32 bk; init_bw(fs, i, &bw); while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END) { directory *d; uint8 *b; b = get_blk(fs, bk); for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + swab16(d->d_rec_len))) swap_dir(d); } } swap_goodblocks(fs, nod); swap_nod(nod); } swap_gd(&fs->gd); swap_sb(&fs->sb);}void swap_badfs(filesystem *fs){ int i; swap_sb(&fs->sb); swap_gd(&fs->gd); for(i = 1; i < fs->sb.s_inodes_count; i++) { inode *nod = get_nod(fs, i); swap_nod(nod); swap_badblocks(fs, nod); if(nod->i_mode & FM_IFDIR) { blockwalker bw; uint32 bk; init_bw(fs, i, &bw); while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END) { directory *d; uint8 *b; b = get_blk(fs, bk); for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len)) swap_dir(d); } } }}// initialize an empty filesystemfilesystem * init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes){ int i; filesystem *fs; directory *d; uint8 * b; uint32 nod; if(nbblocks < 16) // totally arbitrary errexit("too small filesystem"); if(nbblocks >BLOCKS_PER_GROUP) // I build only one group errexit("too big filesystem"); if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE))) errexit("not enough memory for filesystem"); // create the superblock for an empty filesystem fs->sb.s_inodes_count = rndup(nbinodes, BLOCKSIZE/sizeof(inode)); fs->sb.s_blocks_count = nbblocks; fs->sb.s_r_blocks_count = nbresrvd; fs->sb.s_free_blocks_count = nbblocks; fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1; fs->sb.s_first_data_block = (BLOCKSIZE == 1024); fs->sb.s_log_block_size = BLOCKSIZE >> 11; fs->sb.s_log_frag_size = BLOCKSIZE >> 11; fs->sb.s_blocks_per_group = BLOCKS_PER_GROUP; fs->sb.s_frags_per_group = BLOCKS_PER_GROUP; fs->sb.s_inodes_per_group = fs->sb.s_inodes_count;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -