static void create_lost_and_found(ext2_filsys fs) { errcode_t retval; ext2_ino_t ino; const char *name = "lost+found"; int i; int lpf_size = 0; fs->umask = 077; retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name); if (retval) { com_err("ext2fs_mkdir", retval, _("while creating /lost+found")); exit(1); } retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino); if (retval) { com_err("ext2_lookup", retval, _("while looking up /lost+found")); exit(1); } for (i=1; i < EXT2_NDIR_BLOCKS; i++) { if ((lpf_size += fs->blocksize) >= 16*1024) break; retval = ext2fs_expand_dir(fs, ino); if (retval) { com_err("ext2fs_expand_dir", retval, _("while expanding /lost+found")); exit(1); } } }
/* * Returns 0 if not able to find the quota file, otherwise returns its * inode number. */ int quota_file_exists(ext2_filsys fs, int qtype, int fmt) { char qf_name[256]; errcode_t ret; ext2_ino_t ino; if (qtype >= MAXQUOTAS) return -EINVAL; quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); ret = ext2fs_lookup(fs, EXT2_ROOT_INO, qf_name, strlen(qf_name), 0, &ino); if (ret) return 0; return ino; }
/* * this function creates a new directory inode (returned in newdir) * and the link in the upper directory (e2c->curr_e2dir) * the name is the basename of the current path (e2c->curr_path) */ int e2mkdir(e2i_ctx_t *e2c, ext2_ino_t *newdir) { int ret; struct stat s; const char *dname; ext2_ino_t nd; ret = lstat(e2c->curr_path, &s); ERRNO_ERR(ret,"Could not 'stat': ", e2c->curr_path); /* sanity check */ if (!S_ISDIR(s.st_mode)) { fprintf(stderr, "File '%s' is not a directory\n", e2c->curr_path); return -1; } /* edit the directoryname and create it */ dname = basename(e2c->curr_path); ret = ext2fs_mkdir(e2c->fs, e2c->curr_e2dir, 0, dname); if (ret == EXT2_ET_DIR_NO_SPACE) { /* resize the directory */ if (ext2fs_expand_dir(e2c->fs, e2c->curr_e2dir) == 0) ret = ext2fs_mkdir(e2c->fs, e2c->curr_e2dir, 0, dname); } E2_ERR(ret, "Could not create dir: ", dname); /* say what we do and increase the counter */ if (e2c->verbose) printf ("Creating directory %s\n", dname); e2c->cnt->dir++; /* lookup the inode of the new directory if requested */ ret = ext2fs_lookup(e2c->fs, e2c->curr_e2dir, dname, strlen(dname), 0, &nd); E2_ERR(ret, "Could not Ext2-lookup: ", dname); modinode(e2c, dname, nd); if (newdir) { *newdir = nd; } return 0; }
static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir, const char *pathname, int pathlen, int link_count, char *buf, const char **name, int *namelen, ext2_ino_t *res_inode) { char c; const char *thisname; int len; ext2_ino_t inode; errcode_t retval; if ((c = *pathname) == '/') { dir = root; pathname++; pathlen--; } while (1) { thisname = pathname; for (len=0; --pathlen >= 0;len++) { c = *(pathname++); if (c == '/') break; } if (pathlen < 0) break; retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode); if (retval) return retval; retval = follow_link (fs, root, dir, inode, link_count, buf, &dir); if (retval) return retval; } *name = thisname; *namelen = len; *res_inode = dir; return 0; }
static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base, const char *pathname, size_t pathlen, int follow, int link_count, char *buf, ext2_ino_t *res_inode) { const char *base_name; int namelen; ext2_ino_t dir, inode; errcode_t retval; #ifdef NAMEI_DEBUG printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n", root, base, pathlen, pathname, link_count); #endif retval = dir_namei(fs, root, base, pathname, pathlen, link_count, buf, &base_name, &namelen, &dir); if (retval) return retval; if (!namelen) { *res_inode=dir; return 0; } retval = ext2fs_lookup (fs, dir, base_name, namelen, buf, &inode); if (retval) return retval; if (follow) { retval = follow_link(fs, root, dir, inode, link_count, buf, &inode); if (retval) return retval; } #ifdef NAMEI_DEBUG printf("open_namei: (link_count=%d) returns %lu\n", link_count, inode); #endif *res_inode = inode; return 0; }
void e2fsck_move_ext3_journal(e2fsck_t ctx) { struct ext2_super_block *sb = ctx->fs->super; struct problem_context pctx; struct ext2_inode inode; ext2_filsys fs = ctx->fs; ext2_ino_t ino; errcode_t retval; const char * const * cpp; int group, mount_flags; clear_problem_context(&pctx); /* * If the filesystem is opened read-only, or there is no * journal, then do nothing. */ if ((ctx->options & E2F_OPT_READONLY) || (sb->s_journal_inum == 0) || !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) return; /* * Read in the journal inode */ if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0) return; /* * If it's necessary to backup the journal inode, do so. */ if ((sb->s_jnl_backup_type == 0) || ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) && memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) { if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) { memcpy(sb->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); sb->s_jnl_blocks[16] = inode.i_size; sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; ext2fs_mark_super_dirty(fs); fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; } } /* * If the journal is already the hidden inode, then do nothing */ if (sb->s_journal_inum == EXT2_JOURNAL_INO) return; /* * The journal inode had better have only one link and not be readable. */ if (inode.i_links_count != 1) return; /* * If the filesystem is mounted, or we can't tell whether * or not it's mounted, do nothing. */ retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags); if (retval || (mount_flags & EXT2_MF_MOUNTED)) return; /* * If we can't find the name of the journal inode, then do * nothing. */ for (cpp = journal_names; *cpp; cpp++) { retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp, strlen(*cpp), 0, &ino); if ((retval == 0) && (ino == sb->s_journal_inum)) break; } if (*cpp == 0) return; /* We need the inode bitmap to be loaded */ retval = ext2fs_read_bitmaps(fs); if (retval) return; pctx.str = *cpp; if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx)) return; /* * OK, we've done all the checks, let's actually move the * journal inode. Errors at this point mean we need to force * an ext2 filesystem check. */ if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0) goto err_out; if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0) goto err_out; sb->s_journal_inum = EXT2_JOURNAL_INO; ext2fs_mark_super_dirty(fs); fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; inode.i_links_count = 0; inode.i_dtime = ctx->now; if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0) goto err_out; group = ext2fs_group_of_ino(fs, ino); ext2fs_unmark_inode_bitmap(fs->inode_map, ino); ext2fs_mark_ib_dirty(fs); fs->group_desc[group].bg_free_inodes_count++; fs->super->s_free_inodes_count++; return; err_out: pctx.errcode = retval; fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx); fs->super->s_state &= ~EXT2_VALID_FS; ext2fs_mark_super_dirty(fs); return; }
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; }
static errcode_t dir_test(ext2_filsys fs) { const char *dot_name = "."; const char *stub_name = "stub"; const char *parent_name = "test"; ext2_ino_t parent, dir, tmp; errcode_t retval; char dirname[PATH_MAX]; int i; retval = ext2fs_mkdir(fs, 11, 11, stub_name); if (retval) { com_err("dir_test", retval, "while creating %s dir", stub_name); return retval; } retval = ext2fs_mkdir(fs, 11, 0, parent_name); if (retval) { com_err("dir_test", retval, "while creating %s dir", parent_name); return retval; } retval = ext2fs_lookup(fs, 11, parent_name, strlen(parent_name), 0, &parent); if (retval) { com_err("dir_test", retval, "while looking up %s dir", parent_name); return retval; } retval = ext2fs_lookup(fs, parent, dot_name, strlen(dot_name), 0, &tmp); if (retval) { com_err("dir_test", retval, "while looking up %s dir", parent_name); return retval; } if (parent != tmp) { fprintf(stderr, "tst_inline_data: parent (%u) != tmp (%u)\n", parent, tmp); return 1; } for (i = 0, dir = 13; i < 4; i++, dir++) { tmp = 0; snprintf(dirname, sizeof(dirname), "%d", i); retval = ext2fs_mkdir(fs, parent, 0, dirname); if (retval) { com_err("dir_test", retval, "while creating %s dir", dirname); return retval; } retval = ext2fs_lookup(fs, parent, dirname, strlen(dirname), 0, &tmp); if (retval) { com_err("dir_test", retval, "while looking up %s dir", parent_name); return retval; } if (dir != tmp) { fprintf(stderr, "tst_inline_data: dir (%u) != tmp (%u)\n", dir, tmp); return 1; } } snprintf(dirname, sizeof(dirname), "%d", i); retval = ext2fs_mkdir(fs, parent, 0, dirname); if (retval && retval != EXT2_ET_DIR_NO_SPACE) { com_err("dir_test", retval, "while creating %s dir", dirname); return retval; } retval = ext2fs_expand_dir(fs, parent); if (retval) { com_err("dir_test", retval, "while expanding %s dir", parent_name); return retval; } return 0; }
/* * 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_check_directory(fs, ino) == 0) { 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_stats2(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_block4(fs, blk, block, 0, ino); 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; quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); quota_data_inodes(ctx->qctx, &inode, ino, +1); #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif return ino; }
errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, const char *name, char *target) { ext2_extent_handle_t handle; errcode_t retval; struct ext2_inode inode; ext2_ino_t scratch_ino; blk64_t blk; int fastlink; unsigned int target_len; char *block_buf = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); /* The Linux kernel doesn't allow for links longer than a block */ target_len = strlen(target); if (target_len > fs->blocksize) { retval = EXT2_ET_INVALID_ARGUMENT; goto cleanup; } /* * Allocate a data block for slow links */ fastlink = (target_len < sizeof(inode.i_block)); if (!fastlink) { retval = ext2fs_new_block2(fs, 0, 0, &blk); if (retval) goto cleanup; retval = ext2fs_get_mem(fs->blocksize, &block_buf); if (retval) goto cleanup; } /* * Allocate an inode, if necessary */ if (!ino) { retval = ext2fs_new_inode(fs, parent, LINUX_S_IFLNK | 0755, 0, &ino); if (retval) goto cleanup; } /* * Create the inode structure.... */ memset(&inode, 0, sizeof(struct ext2_inode)); inode.i_mode = LINUX_S_IFLNK | 0777; inode.i_uid = inode.i_gid = 0; ext2fs_iblk_set(fs, &inode, fastlink ? 0 : 1); inode.i_links_count = 1; inode.i_size = target_len; /* The time fields are set by ext2fs_write_new_inode() */ if (fastlink) { /* Fast symlinks, target stored in inode */ strcpy((char *)&inode.i_block, target); } else { /* Slow symlinks, target stored in the first block */ memset(block_buf, 0, fs->blocksize); strcpy(block_buf, target); if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { /* * The extent bmap is setup after the inode and block * have been written out below. */ inode.i_flags |= EXT4_EXTENTS_FL; } } /* * Write out the inode and inode data block. The inode generation * number is assigned by write_new_inode, which means that the * operations using ino must come after it. */ retval = ext2fs_write_new_inode(fs, ino, &inode); if (retval) goto cleanup; if (!fastlink) { retval = ext2fs_bmap2(fs, ino, &inode, NULL, BMAP_SET, 0, NULL, &blk); if (retval) goto cleanup; retval = io_channel_write_blk64(fs->io, blk, 1, block_buf); if (retval) goto cleanup; } /* * Link the symlink into the filesystem hierarchy */ if (name) { retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, &scratch_ino); if (!retval) { retval = EXT2_ET_FILE_EXISTS; goto cleanup; } if (retval != EXT2_ET_FILE_NOT_FOUND) goto cleanup; retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_SYMLINK); if (retval) goto cleanup; } /* * Update accounting.... */ if (!fastlink) ext2fs_block_alloc_stats2(fs, blk, +1); ext2fs_inode_alloc_stats2(fs, ino, +1, 0); cleanup: if (block_buf) ext2fs_free_mem(&block_buf); 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; }
errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, const char *name) { ext2_extent_handle_t handle; errcode_t retval; struct ext2_inode parent_inode, inode; ext2_ino_t ino = inum; ext2_ino_t scratch_ino; blk64_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_block2(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; ext2fs_iblk_set(fs, &inode, 1); if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) inode.i_flags |= EXT4_EXTENTS_FL; else inode.i_block[0] = blk; inode.i_links_count = 2; 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; if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { retval = ext2fs_extent_open2(fs, ino, &inode, &handle); if (retval) goto cleanup; retval = ext2fs_extent_set_bmap(handle, 0, blk, 0); ext2fs_extent_free(handle); 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_stats2(fs, blk, +1); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); cleanup: if (block) ext2fs_free_mem(&block); return retval; }
/* * 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; int will_rehash, flags; if (ctx->lost_and_found) return ctx->lost_and_found; clear_problem_context(&pctx); will_rehash = e2fsck_dir_will_be_rehashed(ctx, EXT2_ROOT_INO); if (will_rehash) { flags = ctx->fs->flags; ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; } retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino); if (will_rehash) ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); if (retval && !fix) return 0; if (!retval) { /* Lost+found shouldn't have inline data */ retval = ext2fs_read_inode(fs, ino, &inode); if (fix && retval) return 0; if (fix && (inode.i_flags & EXT4_INLINE_DATA_FL)) { if (!fix_problem(ctx, PR_3_LPF_INLINE_DATA, &pctx)) return 0; goto unlink; } if (fix && (inode.i_flags & EXT4_ENCRYPT_FL)) { if (!fix_problem(ctx, PR_3_LPF_ENCRYPTED, &pctx)) return 0; goto unlink; } if (ext2fs_check_directory(fs, ino) == 0) { 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; unlink: /* 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); /* * If the old lost+found was a directory, we've just * disconnected it from the directory tree, which * means we need to restart the directory tree scan. * The simplest way to do this is restart the whole * e2fsck operation. */ if (LINUX_S_ISDIR(inode.i_mode)) ctx->flags |= E2F_FLAG_RESTART; } 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 */ if (ctx->lnf_repair_block) { blk = ctx->lnf_repair_block; ctx->lnf_repair_block = 0; goto skip_new_block; } retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval == EXT2_ET_BLOCK_ALLOC_FAIL && fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) { fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx); ctx->lost_and_found = EXT2_ROOT_INO; return 0; } 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); skip_new_block: ext2fs_block_alloc_stats2(fs, blk, +1); /* * Next find a free inode. */ retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, ctx->inode_used_map, &ino); if (retval == EXT2_ET_INODE_ALLOC_FAIL && fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) { fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx); ctx->lost_and_found = EXT2_ROOT_INO; return 0; } 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); /* * 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; } /* * Now let's create the actual data block for the inode. * Due to metadata_csum, the directory block MUST be written * after the inode is written to disk! */ 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_block4(fs, blk, block, 0, ino); ext2fs_free_mem(&block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); return 0; } /* * Finally, create the directory link */ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); if (pctx.errcode == EXT2_ET_DIR_NO_SPACE) { pctx.errcode = ext2fs_expand_dir(fs, EXT2_ROOT_INO); if (pctx.errcode) goto link_error; pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); } if (pctx.errcode) { link_error: 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; quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); quota_data_inodes(ctx->qctx, &inode, ino, +1); #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif return ino; }