/*================================================================ * eat_dir - recursively install directory *===============================================================*/ void eat_dir(ino_t parent) { /* Read prototype lines and set up directory. Recurse if need be. */ char *token[MAX_TOKENS], *p; char line[LINE_LEN]; int mode, usrid, grpid, maj, min, f; ino_t n; zone_t z; size_t size; while (1) { get_line(line, token); p = token[0]; if (*p == '$') return; p = token[1]; mode = mode_con(p); usrid = atoi(token[2]); grpid = atoi(token[3]); n = alloc_inode(mode, usrid, grpid); /* Enter name in directory and update directory's size. */ enter_dir(parent, token[0], n); incr_size(parent, sizeof(struct direct)); /* Check to see if file is directory or special. */ incr_link(n); if (*p == 'd') { /* This is a directory. */ z = alloc_zone(); /* zone for new directory */ add_zone(n, z, 2 * sizeof(struct direct), current_time); enter_dir(n, ".", n); enter_dir(n, "..", parent); incr_link(parent); incr_link(n); eat_dir(n); } else if (*p == 'b' || *p == 'c') { /* Special file. */ maj = atoi(token[4]); min = atoi(token[5]); size = 0; if (token[6]) size = atoi(token[6]); size = block_size * size; add_zone(n, (zone_t) (makedev(maj,min)), size, current_time); } else if (*p == 's') { enter_symlink(n, token[4]); } else { /* Regular file. Go read it. */ if ((f = open(token[4], O_RDONLY)) < 0) { fprintf(stderr, "%s: Can't open %s: %s\n", progname, token[4], strerror(errno)); } else { eat_file(n, f); } } } }
/*================================================================ * rootdir - install the root directory *===============================================================*/ void rootdir(ino_t inode) { zone_t z; z = alloc_zone(); add_zone(inode, z, 2 * sizeof(struct direct), current_time); enter_dir(inode, ".", inode); enter_dir(inode, "..", inode); incr_link(inode); incr_link(inode); }
void enter_symlink(ino_t inode, char *lnk) { zone_t z; size_t len; char *buf; buf = alloc_block(); z = alloc_zone(); len = strlen(lnk); if (len >= block_size) pexit("symlink too long, max length is %u", (unsigned)block_size - 1); strcpy(buf, lnk); put_block((z << zone_shift), buf); add_zone(inode, z, len, current_time); free(buf); }
/* Zonesize >= blocksize */ void eat_file(ino_t inode, int f) { int ct = 0, i, j; zone_t z = 0; char *buf; time_t timeval; buf = alloc_block(); do { for (i = 0, j = 0; i < zone_per_block; i++, j += ct) { memset(buf, 0, block_size); if ((ct = read(f, buf, block_size)) > 0) { if (i == 0) z = alloc_zone(); put_block((z << zone_shift) + i, buf); } } timeval = (dflag ? current_time : file_time(f)); if (ct) add_zone(inode, z, (size_t) j, timeval); } while (ct == block_size); close(f); free(buf); }
void add_zone(ino_t n, zone_t z, size_t bytes, time_t mtime) { /* Add zone z to inode n. The file has grown by 'bytes' bytes. */ int off, i, j; block_t b; zone_t indir, dindir; struct inode *p, *inode; zone_t *blk, *dblk; assert(inodes_per_block*sizeof(*inode) == block_size); if(!(inode = alloc_block())) err(1, "Couldn't allocate block of inodes"); b = ((n - 1) / inodes_per_block) + inode_offset; off = (n - 1) % inodes_per_block; get_block(b, inode); p = &inode[off]; p->i_size += bytes; p->i_mtime = mtime; #ifndef MFS_INODE_ONLY_MTIME /* V1 file systems did not have them... */ p->i_atime = p->i_ctime = current_time; #endif for (i = 0; i < NR_DZONES; i++) if (p->i_zone[i] == 0) { p->i_zone[i] = z; put_block(b, inode); free(inode); return; } assert(indir_per_block*sizeof(*blk) == block_size); if(!(blk = alloc_block())) err(1, "Couldn't allocate indirect block"); /* File has grown beyond a small file. */ if (p->i_zone[S_INDIRECT_IDX] == 0) p->i_zone[S_INDIRECT_IDX] = alloc_zone(); indir = p->i_zone[S_INDIRECT_IDX] << zone_shift; put_block(b, inode); --indir; /* Compensate for ++indir below */ for (i = 0; i < (indir_per_zone); i++) { if (i % indir_per_block == 0) get_block(++indir, blk); if (blk[i % indir_per_block] == 0) { blk[i] = z; put_block(indir, blk); free(blk); free(inode); return; } } /* File has grown beyond single indirect; we need a double indirect */ assert(indir_per_block*sizeof(*dblk) == block_size); if(!(dblk = alloc_block())) err(1, "Couldn't allocate double indirect block"); if (p->i_zone[D_INDIRECT_IDX] == 0) p->i_zone[D_INDIRECT_IDX] = alloc_zone(); dindir = p->i_zone[D_INDIRECT_IDX] << zone_shift; put_block(b, inode); --dindir; /* Compensate for ++indir below */ for (j = 0; j < (indir_per_zone); j++) { if (j % indir_per_block == 0) get_block(++dindir, dblk); if (dblk[j % indir_per_block] == 0) dblk[j % indir_per_block] = alloc_zone(); indir = dblk[j % indir_per_block] << zone_shift; --indir; /* Compensate for ++indir below */ for (i = 0; i < (indir_per_zone); i++) { if (i % indir_per_block == 0) get_block(++indir, blk); if (blk[i % indir_per_block] == 0) { blk[i] = z; put_block(dindir, dblk); put_block(indir, blk); free(dblk); free(blk); free(inode); return; } } } pexit("File has grown beyond double indirect"); }
/*================================================================ * directory & inode management assist group *===============================================================*/ void enter_dir(ino_t parent, char const *name, ino_t child) { /* Enter child in parent directory */ /* Works for dir > 1 block and zone > block */ unsigned int k; block_t b, indir; zone_t z; int off; struct inode *ino; struct inode *inoblock = alloc_block(); zone_t *indirblock = alloc_block(); assert(!(block_size % sizeof(struct direct))); /* Obtain the inode structure */ b = ((parent - 1) / inodes_per_block) + inode_offset; off = (parent - 1) % inodes_per_block; get_block(b, inoblock); ino = inoblock + off; for (k = 0; k < NR_DZONES; k++) { z = ino->i_zone[k]; if (z == 0) { z = alloc_zone(); ino->i_zone[k] = z; } if(dir_try_enter(z, child, __UNCONST(name))) { put_block(b, inoblock); free(inoblock); free(indirblock); return; } } /* no space in directory using just direct blocks; try indirect */ if (ino->i_zone[S_INDIRECT_IDX] == 0) ino->i_zone[S_INDIRECT_IDX] = alloc_zone(); indir = ino->i_zone[S_INDIRECT_IDX] << zone_shift; --indir; /* Compensate for ++indir below */ for(k = 0; k < (indir_per_zone); k++) { if (k % indir_per_block == 0) get_block(++indir, indirblock); z = indirblock[k % indir_per_block]; if(!z) { z = indirblock[k % indir_per_block] = alloc_zone(); put_block(indir, indirblock); } if(dir_try_enter(z, child, __UNCONST(name))) { put_block(b, inoblock); free(inoblock); free(indirblock); return; } } pexit("Directory-inode %u beyond single indirect blocks. Could not enter %s", (unsigned)parent, name); }
/* * === FUNCTION ====================================================================== * Name: rdwt_zones * Description: read of write the buf to the zones * @param pos: the current position in the file * @param buf_len: the length of the buf * @param src: the source of the buf * @param buf: the buf should be read or written * @param i_nr_sects: the current amount of the sects of the file * @param i_zone: the i_zone of this inode * @param mode: READ or WRITE * @return : how many bytes writed or read * ===================================================================================== */ PRIVATE int rdwt_zones ( int pos, int len, int src, char * buf, struct inode * pin, int mode) { //check if the mode is right assert(WRITE == mode || READ == mode); int i; int align = 0; int pos_end = pos + len; //larger than file in read mode if (READ == mode) { if (pos > pin->i_size) { //read start is larger than the file, get nothing return 0; } else if (pos_end > pin->i_size) { //read end is larger than the file, just end at the EOF len -= (pos_end - pin->i_size); pos_end = pin->i_size; } } //how many sects does the buf need to take int nr_sect_start = pos >> SECTOR_SIZE_SHIFT; int nr_rw_sect = len >> SECTOR_SIZE_SHIFT; int off = pos_end % SECTOR_SIZE; //if the buf is not n * SECTOR_SIZE, just give one more sector if (off > 0) { nr_rw_sect ++; } int nr_sect = nr_sect_start + nr_rw_sect; //if the sects in the file is not enough if (nr_sect > pin->i_nr_sects) { //allocate the sectors that needed assert(WRITE == mode); u32 zone_amount = alloc_zone(pin->i_dev, pin->i_nr_sects, nr_sect - pin->i_nr_sects, pin->i_zone); assert(nr_sect - pin->i_nr_sects == zone_amount); pin->i_nr_sects += zone_amount; } if (nr_sect_start < NR_DIRECT_ZONE) { //the sectors are only in the direct zone int flag_direct_zone = 1; //asumpt the amount of the sect is less than direct zone int direct_nr_rw_sect = nr_rw_sect; if (nr_sect > NR_DIRECT_ZONE) { //the amount of sects is more than the direct zone flag_direct_zone = 0; direct_nr_rw_sect = NR_DIRECT_ZONE - nr_sect_start; nr_rw_sect -= direct_nr_rw_sect; } for (i = 0; i < direct_nr_rw_sect; i++, align++) { if (WRITE == mode) { phys_copy((void*)va2la(TASK_FS, fsbuf), (void*)va2la(src, buf + align * SECTOR_SIZE), SECTOR_SIZE); WR_SECT(pin->i_dev, pin->i_zone[nr_sect_start + i]); } else if (READ == mode) { RD_SECT(pin->i_dev, pin->i_zone[nr_sect_start + i]); phys_copy((void*)va2la(src, buf + align * SECTOR_SIZE), (void*)va2la(TASK_FS, fsbuf), SECTOR_SIZE); } } if (flag_direct_zone) { return len; } } //the first level indirect zone zone_t sectors[NR_ZONE_PER_SECT]; if (nr_sect_start < NR_SECOND_LEVEL_ZONE) { int second_level_start = NR_DIRECT_ZONE; if (nr_sect_start > second_level_start) { second_level_start = nr_sect_start; } //the sectors are only reach the second level int flag_second_level = 1; int second_nr_rw_sect = nr_rw_sect; if (nr_sect > NR_SECOND_LEVEL_ZONE) { //the amount of sects is more than the second level zone flag_second_level = 0; second_nr_rw_sect = NR_SECOND_LEVEL_ZONE - second_level_start; nr_rw_sect -= second_nr_rw_sect; } //get the begin and end in second level zone second_level_start -= NR_DIRECT_ZONE; RD_SECT(pin->i_dev, pin->i_zone[SECOND_LEVEL_ZONE]); memcpy((void *)sectors, (void *)fsbuf, NR_ZONE_PER_SECT * sizeof(int) ); for (i = 0; i < second_nr_rw_sect; i++, align++) { if (WRITE == mode) { phys_copy((void*)va2la(TASK_FS, fsbuf), (void*)va2la(src, buf + align * SECTOR_SIZE), SECTOR_SIZE); WR_SECT(pin->i_dev, sectors[second_level_start + i]); } else if(READ == mode) { RD_SECT(pin->i_dev, sectors[second_level_start + i]); phys_copy((void*)va2la(src, buf + align * SECTOR_SIZE), (void*)va2la(TASK_FS, fsbuf), SECTOR_SIZE); } } //if the zones only reach second level if (flag_second_level) { return len; } } if (nr_sect_start < NR_THIRD_LEVEL_ZONE) { //less than the third level indirect zone int third_level_start = NR_SECOND_LEVEL_ZONE; if (nr_sect_start > third_level_start) { third_level_start = nr_sect_start; } //the sectors are only reach the third level int flag_third_level = 1; int third_nr_rw_sect = nr_rw_sect; if (nr_sect > NR_THIRD_LEVEL_ZONE) { //the amount of sects is more than the third level zone flag_third_level = 0; third_nr_rw_sect = NR_THIRD_LEVEL_ZONE - third_level_start; nr_rw_sect -= third_nr_rw_sect; } //get the start and end in third level zone third_level_start -= NR_SECOND_LEVEL_ZONE; RD_SECT(pin->i_dev, pin->i_zone[THIRD_LEVEL_ZONE]); memcpy((void *)sectors, (void *)fsbuf, NR_ZONE_PER_SECT * sizeof(int) ); int current_second_level_zone = NO_ZONE; zone_t current_zones[NR_ZONE_PER_SECT]; for (i = 0; i < third_nr_rw_sect; i++, align++) { int second_level_index = (third_level_start + i) / NR_SECT_PER_SECOND_LEVEL_ZONE; int third_level_index = (third_level_start + i) % NR_SECT_PER_SECOND_LEVEL_ZONE; if (NO_ZONE == current_second_level_zone || current_second_level_zone != sectors[second_level_index]){ RD_SECT(pin->i_dev, sectors[second_level_index]); memcpy((void *)current_zones, (void *)fsbuf, NR_ZONE_PER_SECT * sizeof(int) ); } //record the current second level zone for compare in next time //to comfirm if that the current second level zone is finished current_second_level_zone = sectors[second_level_index]; if (WRITE == mode) { phys_copy((void*)va2la(TASK_FS, fsbuf), (void*)va2la(src, buf + align * SECTOR_SIZE), SECTOR_SIZE); WR_SECT(pin->i_dev, current_zones[third_level_index]); } else if(READ == mode) { RD_SECT(pin->i_dev, current_zones[third_level_index]); phys_copy((void*)va2la(src, buf + align * SECTOR_SIZE), (void*)va2la(TASK_FS, fsbuf), SECTOR_SIZE); } } //if the zones only reach third level if (flag_third_level) { return len; } } if (nr_sect > NR_THIRD_LEVEL_ZONE) { //do not support zones larger than third level panic("buf is too large"); } return -1; } /* ----- end of function rdwt_zones ----- */