Example #1
0
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);
		}
	}
}
Example #2
0
/*
 * 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;
}
Example #3
0
/*
 * 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;
}
Example #4
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;
}
Example #5
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;
}
Example #6
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;
}
Example #7
0
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;

}
Example #8
0
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;
}
Example #9
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;
}
Example #11
0
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;

}
Example #13
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;
	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;
}