/* * Helper function which writes out a directory block. */ static int write_dir_block(ext2_filsys fs, blk_t *block_nr, e2_blkcnt_t blockcnt, blk_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { struct write_dir_struct *wd = (struct write_dir_struct *) priv_data; blk_t blk; char *dir; if (*block_nr == 0) return 0; if (blockcnt >= wd->outdir->num) { e2fsck_read_bitmaps(wd->ctx); blk = *block_nr; ext2fs_unmark_block_bitmap2(wd->ctx->block_found_map, blk); ext2fs_block_alloc_stats(fs, blk, -1); *block_nr = 0; wd->cleared++; return BLOCK_CHANGED; } if (blockcnt < 0) return 0; dir = wd->outdir->buf + (blockcnt * fs->blocksize); wd->err = ext2fs_write_dir_block(fs, *block_nr, dir); if (wd->err) return BLOCK_ABORT; return 0; }
/* * This fuction deallocates an inode */ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf) { ext2_filsys fs = ctx->fs; struct ext2_inode inode; struct problem_context pctx; __u32 count; e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode"); clear_problem_context(&pctx); pctx.ino = ino; /* * Fix up the bitmaps... */ e2fsck_read_bitmaps(ctx); ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); if (inode.i_file_acl && (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl, block_buf, -1, &count); if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) { pctx.errcode = 0; count = 1; } if (pctx.errcode) { pctx.blk = inode.i_file_acl; fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } if (count == 0) { ext2fs_unmark_block_bitmap(ctx->block_found_map, inode.i_file_acl); ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1); } inode.i_file_acl = 0; } if (!ext2fs_inode_has_valid_blocks(&inode)) return; if (LINUX_S_ISREG(inode.i_mode) && (inode.i_size_high || inode.i_size & 0x80000000UL)) ctx->large_files--; pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf, deallocate_inode_block, ctx); if (pctx.errcode) { fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } }
static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr, e2_blkcnt_t blockcnt, blk_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { struct set_badblock_record *rec = (struct set_badblock_record *) priv_data; errcode_t retval; blk_t blk; if (blockcnt >= 0) { /* * Get the next bad block. */ if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk)) return BLOCK_ABORT; rec->bad_block_count++; } else { /* * An indirect block; fetch a block from the * previously used indirect block list. The block * most be not marked as used; if so, get another one. * If we run out of reserved indirect blocks, allocate * a new one. */ retry: if (rec->ind_blocks_ptr < rec->ind_blocks_size) { blk = rec->ind_blocks[rec->ind_blocks_ptr++]; if (ext2fs_test_block_bitmap(fs->block_map, blk)) goto retry; } else { retval = ext2fs_new_block(fs, 0, 0, &blk); if (retval) { rec->err = retval; return BLOCK_ABORT; } } retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf); if (retval) { rec->err = retval; return BLOCK_ABORT; } } /* * Update block counts */ ext2fs_block_alloc_stats(fs, blk, +1); *block_nr = blk; return BLOCK_CHANGED; }
static int expand_dir_proc(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt, blk_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data; blk_t new_blk; static blk_t last_blk = 0; char *block; errcode_t retval; if (*blocknr) { last_blk = *blocknr; return 0; } retval = ext2fs_new_block(fs, last_blk, 0, &new_blk); if (retval) { es->err = retval; return BLOCK_ABORT; } if (blockcnt > 0) { retval = ext2fs_new_dir_block(fs, 0, 0, &block); if (retval) { es->err = retval; return BLOCK_ABORT; } es->done = 1; retval = ext2fs_write_dir_block(fs, new_blk, block); } else { retval = ext2fs_get_mem(fs->blocksize, &block); if (retval) { es->err = retval; return BLOCK_ABORT; } memset(block, 0, fs->blocksize); retval = io_channel_write_blk(fs->io, new_blk, 1, block); } if (retval) { es->err = retval; return BLOCK_ABORT; } ext2fs_free_mem(&block); *blocknr = new_blk; ext2fs_block_alloc_stats(fs, new_blk, +1); es->newblocks++; if (es->done) return (BLOCK_CHANGED | BLOCK_ABORT); else return BLOCK_CHANGED; }
static errcode_t ext2fs_inline_data_dir_expand(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, char *buf, size_t size) { errcode_t retval; blk64_t blk; char *blk_buf; retval = ext2fs_get_memzero(fs->blocksize, &blk_buf); if (retval) return retval; #ifdef WORDS_BIGENDIAN retval = ext2fs_dirent_swab_in2(fs, buf + EXT4_INLINE_DATA_DOTDOT_SIZE, size, 0); if (retval) goto errout; #endif /* Adjust the rec_len */ retval = ext2fs_inline_data_convert_dir(fs, ino, blk_buf, buf, size); if (retval) goto errout; /* Allocate a new block */ retval = ext2fs_new_block2(fs, 0, 0, &blk); if (retval) goto errout; retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino); if (retval) goto errout; /* Update inode */ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT3_FEATURE_INCOMPAT_EXTENTS)) inode->i_flags |= EXT4_EXTENTS_FL; inode->i_flags &= ~EXT4_INLINE_DATA_FL; retval = ext2fs_iblk_add_blocks(fs, inode, 1); if (retval) goto errout; inode->i_size = fs->blocksize; retval = ext2fs_bmap2(fs, ino, inode, 0, BMAP_SET, 0, 0, &blk); if (retval) goto errout; retval = ext2fs_write_inode(fs, ino, inode); if (retval) goto errout; ext2fs_block_alloc_stats(fs, blk, +1); errout: ext2fs_free_mem(&blk_buf); return retval; }
/* * This clever recursive function handles i_blocks[] as well as * indirect, double indirect, and triple indirect blocks. It iterates * over the entries in the i_blocks array or indirect blocks, and for * each one, will recursively handle any indirect blocks and then * frees and deallocates the blocks. */ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode, char *block_buf, blk_t *p, int level, blk_t start, blk_t count, int max) { errcode_t retval; blk_t b; int i; blk64_t offset, incr; int freed = 0; #ifdef PUNCH_DEBUG printf("Entering ind_punch, level %d, start %u, count %u, " "max %d\n", level, start, count, max); #endif incr = 1ULL << ((EXT2_BLOCK_SIZE_BITS(fs->super)-2)*level); for (i=0, offset=0; i < max; i++, p++, offset += incr) { if (offset >= start + count) break; if (*p == 0 || (offset+incr) <= start) continue; b = *p; if (level > 0) { blk_t start2; #ifdef PUNCH_DEBUG printf("Reading indirect block %u\n", b); #endif retval = ext2fs_read_ind_block(fs, b, block_buf); if (retval) return retval; start2 = (start > offset) ? start - offset : 0; retval = ind_punch(fs, inode, block_buf + fs->blocksize, (blk_t *) block_buf, level - 1, start2, count - offset, fs->blocksize >> 2); if (retval) return retval; retval = ext2fs_write_ind_block(fs, b, block_buf); if (retval) return retval; if (!check_zero_block(block_buf, fs->blocksize)) continue; } #ifdef PUNCH_DEBUG printf("Freeing block %u (offset %llu)\n", b, offset); #endif ext2fs_block_alloc_stats(fs, b, -1); *p = 0; freed++; }
static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, e2_blkcnt_t blockcnt, blk_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { struct set_badblock_record *rec = (struct set_badblock_record *) priv_data; errcode_t retval; unsigned long old_size; if (!*block_nr) return 0; /* * If the block number is outrageous, clear it and ignore it. */ if (*block_nr >= fs->super->s_blocks_count || *block_nr < fs->super->s_first_data_block) { *block_nr = 0; return BLOCK_CHANGED; } if (blockcnt < 0) { if (rec->ind_blocks_size >= rec->max_ind_blocks) { old_size = rec->max_ind_blocks * sizeof(blk_t); rec->max_ind_blocks += 10; retval = ext2fs_resize_mem(old_size, rec->max_ind_blocks * sizeof(blk_t), &rec->ind_blocks); if (retval) { rec->max_ind_blocks -= 10; rec->err = retval; return BLOCK_ABORT; } } rec->ind_blocks[rec->ind_blocks_size++] = *block_nr; } /* * Mark the block as unused, and update accounting information */ ext2fs_block_alloc_stats(fs, *block_nr, -1); *block_nr = 0; return BLOCK_CHANGED; }
static int deallocate_inode_block(ext2_filsys fs, blk_t *block_nr, e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), blk_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { e2fsck_t ctx = (e2fsck_t) priv_data; if (HOLE_BLKADDR(*block_nr)) return 0; if ((*block_nr < fs->super->s_first_data_block) || (*block_nr >= fs->super->s_blocks_count)) return 0; ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr); ext2fs_block_alloc_stats(fs, *block_nr, -1); return 0; }
static int mkjournal_proc(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt, blk_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data; blk_t new_blk; static blk_t last_blk = 0; errcode_t retval; if (*blocknr) { last_blk = *blocknr; return 0; } retval = ext2fs_new_block(fs, last_blk, 0, &new_blk); if (retval) { es->err = retval; return BLOCK_ABORT; } if (blockcnt > 0) es->num_blocks--; es->newblocks++; retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf); if (blockcnt == 0) memset(es->buf, 0, fs->blocksize); if (retval) { es->err = retval; return BLOCK_ABORT; } *blocknr = new_blk; last_blk = new_blk; ext2fs_block_alloc_stats(fs, new_blk, +1); if (es->num_blocks == 0) return (BLOCK_CHANGED | BLOCK_ABORT); else return BLOCK_CHANGED; }
/* * This function zeros out the allocated block, and updates all of the * appropriate filesystem records. */ errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, char *block_buf, blk_t *ret) { errcode_t retval; blk_t block; char *buf = 0; if (!block_buf) { retval = ext2fs_get_mem(fs->blocksize, &buf); if (retval) return retval; block_buf = buf; } memset(block_buf, 0, fs->blocksize); if (!fs->block_map) { retval = ext2fs_read_block_bitmap(fs); if (retval) goto fail; } retval = ext2fs_new_block(fs, goal, 0, &block); if (retval) goto fail; retval = io_channel_write_blk(fs->io, block, 1, block_buf); if (retval) goto fail; ext2fs_block_alloc_stats(fs, block, +1); *ret = block; return 0; fail: if (buf) ext2fs_free_mem(&buf); return retval; }
static int mkjournal_proc(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt, blk_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data; blk_t new_blk; errcode_t retval; if (*blocknr) { es->goal = *blocknr; return 0; } retval = ext2fs_new_block(fs, es->goal, 0, &new_blk); if (retval) { es->err = retval; return BLOCK_ABORT; } if (blockcnt >= 0) es->num_blocks--; es->newblocks++; retval = 0; if (blockcnt <= 0) retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf); else { if (es->zero_count) { if ((es->blk_to_zero + es->zero_count == new_blk) && (es->zero_count < 1024)) es->zero_count++; else { retval = ext2fs_zero_blocks(fs, es->blk_to_zero, es->zero_count, 0, 0); es->zero_count = 0; } } if (es->zero_count == 0) { es->blk_to_zero = new_blk; es->zero_count = 1; } } if (blockcnt == 0) memset(es->buf, 0, fs->blocksize); if (retval) { es->err = retval; return BLOCK_ABORT; } *blocknr = es->goal = new_blk; ext2fs_block_alloc_stats(fs, new_blk, +1); if (es->num_blocks == 0) return (BLOCK_CHANGED | BLOCK_ABORT); else return BLOCK_CHANGED; }
errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, const char *name) { errcode_t retval; struct ext2_inode parent_inode, inode; ext2_ino_t ino = inum; ext2_ino_t scratch_ino; blk_t blk; char *block = 0; char *ext2bp_block = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); /* * Allocate an inode, if necessary */ if (!ino) { retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &ino); if (retval) goto cleanup; } /* * Allocate a data block for the directory */ retval = ext2fs_new_block(fs, 0, 0, &blk); printf("Using block %lu for the dir\n", blk); if (retval) goto cleanup; printf("Writing the dir info into the buffer\n"); /* * Create a scratch template for the directory */ /* Vijay: Offset the block address by the backpointer information */ retval = ext2fs_new_dir_block(fs, ino, parent, &block); //ext2bp_block = block + EXT2BP_HEADER_SIZE; //retval = ext2fs_new_dir_block(fs, ino, parent, &ext2bp_block); if (retval) goto cleanup; /* * Get the parent's inode, if necessary */ if (parent != ino) { retval = ext2fs_read_inode(fs, parent, &parent_inode); if (retval) goto cleanup; } else memset(&parent_inode, 0, sizeof(parent_inode)); /* * Create the inode structure.... */ memset(&inode, 0, sizeof(struct ext2_inode)); inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask); inode.i_uid = inode.i_gid = 0; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; inode.i_links_count = 2; inode.i_size = fs->blocksize; /* Vijay: Adding backlink to the inode - Modifying position 0 * since this is a new inode - It will not have any other links * pointing to it. First, we need to reset all the backlinks. */ printf("Vijay: Adding the backlink to %s\n", name); int i; for(i=0; i < EXT2_N_LINKS; i++) inode.i_backlinks[i] = 0; inode.i_backlinks[0] = parent; printf("Going to write the dir block\n"); /* * Write out the inode and inode data block */ retval = ext2fs_write_dir_block(fs, blk, block); if (retval) goto cleanup; retval = ext2fs_write_new_inode(fs, ino, &inode); if (retval) goto cleanup; printf("Link the directory into the filesystem hierarchy\n"); /* * Link the directory into the filesystem hierarchy */ if (name) { retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, &scratch_ino); if (!retval) { retval = EXT2_ET_DIR_EXISTS; name = 0; goto cleanup; } if (retval != EXT2_ET_FILE_NOT_FOUND) goto cleanup; retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR); printf("Linking done: %lu\n", retval); if (retval) goto cleanup; } /* * Update parent inode's counts */ if (parent != ino) { parent_inode.i_links_count++; retval = ext2fs_write_inode(fs, parent, &parent_inode); if (retval) goto cleanup; } /* * Update accounting.... */ ext2fs_block_alloc_stats(fs, blk, +1); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); cleanup: if (block) ext2fs_free_mem(&block); return retval; }
errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, const char *name) { errcode_t retval; struct ext2_inode parent_inode, inode; ext2_ino_t ino = inum; ext2_ino_t scratch_ino; blk_t blk; char *block = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); /* * Allocate an inode, if necessary */ if (!ino) { retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &ino); if (retval) goto cleanup; } /* * Allocate a data block for the directory */ retval = ext2fs_new_block(fs, 0, 0, &blk); if (retval) goto cleanup; /* * Create a scratch template for the directory */ retval = ext2fs_new_dir_block(fs, ino, parent, &block); if (retval) goto cleanup; /* * Get the parent's inode, if necessary */ if (parent != ino) { retval = ext2fs_read_inode(fs, parent, &parent_inode); if (retval) goto cleanup; } else memset(&parent_inode, 0, sizeof(parent_inode)); /* * Create the inode structure.... */ memset(&inode, 0, sizeof(struct ext2_inode)); inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask); inode.i_uid = inode.i_gid = 0; inode.i_blocks = fs->blocksize / 512; inode.i_block[0] = blk; inode.i_links_count = 2; inode.i_ctime = inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(NULL); inode.i_size = fs->blocksize; /* * Write out the inode and inode data block */ retval = ext2fs_write_dir_block(fs, blk, block); if (retval) goto cleanup; retval = ext2fs_write_new_inode(fs, ino, &inode); if (retval) goto cleanup; /* * Link the directory into the filesystem hierarchy */ if (name) { retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, &scratch_ino); if (!retval) { retval = EXT2_ET_DIR_EXISTS; name = 0; goto cleanup; } if (retval != EXT2_ET_FILE_NOT_FOUND) goto cleanup; retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR); if (retval) goto cleanup; } /* * Update parent inode's counts */ if (parent != ino) { parent_inode.i_links_count++; retval = ext2fs_write_inode(fs, parent, &parent_inode); if (retval) goto cleanup; } /* * Update accounting.... */ ext2fs_block_alloc_stats(fs, blk, +1); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); cleanup: if (block) ext2fs_free_mem(&block); return retval; }
static ext2_ino_t ext2CreateSymlink(ext2_vd *vd, const char *path, const char * targetdir, const char * name, mode_t type) { ext2_inode_t *target_ni = NULL; ext2_ino_t newentry = 0; ext2_ino_t ino = 0; // Check if it does exist target_ni = ext2OpenEntry(vd, targetdir); if (!target_ni) goto cleanup; int err = ext2fs_new_inode(vd->fs, target_ni->ino, type, 0, &ino); if (err) { errno = EFAULT; goto cleanup; } while((err = ext2fs_link(vd->fs, target_ni->ino, name, ino, EXT2_FT_SYMLINK)) == EXT2_ET_DIR_NO_SPACE) { if (ext2fs_expand_dir(vd->fs, target_ni->ino) != EXT2_ET_OK) { errno = EMLINK; goto cleanup; } } if(err != EXT2_ET_OK) { errno = EMLINK; return 0; } ext2fs_inode_alloc_stats2(vd->fs, ino, +1, 0); struct ext2_inode inode; memset(&inode, 0, sizeof(inode)); inode.i_mode = type; inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL); inode.i_links_count = 1; inode.i_size = strlen(path); //initial size of file inode.i_uid = target_ni->ni.i_uid; inode.i_gid = target_ni->ni.i_gid; if (strlen(path) <= sizeof(inode.i_block)) { /* fast symlink */ strncpy((char *)&(inode.i_block[0]),path,sizeof(inode.i_blocks)); } else { /* slow symlink */ char * buffer = mem_alloc(vd->fs->blocksize); if (buffer) { blk_t blk; strncpy(buffer, path, vd->fs->blocksize); err = ext2fs_new_block(vd->fs, 0, 0, &blk); if (!err) { inode.i_block[0] = blk; inode.i_blocks = vd->fs->blocksize / 512; vd->fs->io->manager->write_blk(vd->fs->io, blk, 1, buffer); ext2fs_block_alloc_stats(vd->fs, blk, +1); } mem_free(buffer); } } if(ext2fs_write_new_inode(vd->fs, ino, &inode) != 0) newentry = ino; cleanup: if(target_ni) ext2CloseEntry(vd, target_ni); return newentry; }
/* * This routine gets the lost_and_found inode, making it a directory * if necessary */ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) { ext2_filsys fs = ctx->fs; ext2_ino_t ino; blk64_t blk; errcode_t retval; struct ext2_inode inode; char * block; static const char name[] = "lost+found"; struct problem_context pctx; if (ctx->lost_and_found) return ctx->lost_and_found; clear_problem_context(&pctx); retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino); if (retval && !fix) return 0; if (!retval) { if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino)) { ctx->lost_and_found = ino; return ino; } /* Lost+found isn't a directory! */ if (!fix) return 0; pctx.ino = ino; if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) return 0; /* OK, unlink the old /lost+found file. */ pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); if (pctx.errcode) { pctx.str = "ext2fs_unlink"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } (void) e2fsck_dir_info_set_parent(ctx, ino, 0); e2fsck_adjust_inode_count(ctx, ino, -1); } else if (retval != EXT2_ET_FILE_NOT_FOUND) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); } if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) return 0; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ e2fsck_read_bitmaps(ctx); /* * First, find a free block */ retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); return 0; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); ext2fs_block_alloc_stats(fs, blk, +1); /* * Next find a free inode. */ retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, ctx->inode_used_map, &ino); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); return 0; } ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); /* * Now let's create the actual data block for the inode */ retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); return 0; } retval = ext2fs_write_dir_block(fs, blk, block); ext2fs_free_mem(&block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); return 0; } /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); inode.i_mode = 040700; inode.i_size = fs->blocksize; inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; inode.i_links_count = 2; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; /* * Next, write out the inode. */ pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); if (pctx.errcode) { pctx.str = "ext2fs_write_inode"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Finally, create the directory link */ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); if (pctx.errcode) { pctx.str = "ext2fs_link"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Miscellaneous bookkeeping that needs to be kept straight. */ e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); ext2fs_icount_store(ctx->inode_count, ino, 2); ext2fs_icount_store(ctx->inode_link_info, ino, 2); ctx->lost_and_found = ino; #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif return ino; }