13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * mkdir.c --- make a directory in the filesystem
3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * Copyright (C) 1994, 1995 Theodore Ts'o.
519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
7543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library
8543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2.
919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
144cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
164cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h>
191d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h>
211d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
221d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H
233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h>
241d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
26b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "ext2fs.h"
283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
29e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o#ifndef EXT2_FT_DIR
30e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o#define EXT2_FT_DIR		2
31e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o#endif
32e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o
3331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oerrcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		       const char *name)
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
36e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2_extent_handle_t	handle;
373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t		retval;
382e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o	struct ext2_inode	parent_inode, inode;
3931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	ext2_ino_t		ino = inum;
4031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	ext2_ino_t		scratch_ino;
41e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t			blk;
423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char			*block = 0;
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
44f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
45f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Allocate an inode, if necessary
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!ino) {
5050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755,
5150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o					  0, &ino);
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval)
533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			goto cleanup;
543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Allocate a data block for the directory
583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
59e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_new_block2(fs, 0, 0, &blk);
603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Create a scratch template for the directory
653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	retval = ext2fs_new_dir_block(fs, ino, parent, &block);
673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
712e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o	 * Get the parent's inode, if necessary
722e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o	 */
732e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o	if (parent != ino) {
742e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o		retval = ext2fs_read_inode(fs, parent, &parent_inode);
752e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o		if (retval)
762e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o			goto cleanup;
772e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o	} else
782e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o		memset(&parent_inode, 0, sizeof(parent_inode));
792e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o
802e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o	/*
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Create the inode structure....
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(&inode, 0, sizeof(struct ext2_inode));
846a525069a99787ef3ae1156f12230044b3568f4bTheodore Ts'o	inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_uid = inode.i_gid = 0;
861ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o	ext2fs_iblk_set(fs, &inode, 1);
87e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)
88e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		inode.i_flags |= EXT4_EXTENTS_FL;
89e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	else
90e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		inode.i_block[0] = blk;
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_links_count = 2;
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	inode.i_size = fs->blocksize;
933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Write out the inode and inode data block
963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
9750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	retval = ext2fs_write_dir_block(fs, blk, block);
983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
100efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	retval = ext2fs_write_new_inode(fs, ino, &inode);
1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (retval)
1023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
104e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
105e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_extent_open2(fs, ino, &inode, &handle);
106e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (retval)
107e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			goto cleanup;
108e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
109e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_extent_free(handle);
110e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (retval)
111e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			goto cleanup;
112e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
113e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
1143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Link the directory into the filesystem hierarchy
1163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (name) {
1183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = ext2fs_lookup(fs, parent, name, strlen(name), 0,
1193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				       &scratch_ino);
1203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (!retval) {
1211f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o			retval = EXT2_ET_DIR_EXISTS;
1223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			name = 0;
1233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			goto cleanup;
1243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
1251f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o		if (retval != EXT2_ET_FILE_NOT_FOUND)
1263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			goto cleanup;
127e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o		retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR);
1283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (retval)
1293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			goto cleanup;
1303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
133dab278af8180bc85783da0b908e2a1af1388522dTheodore Ts'o	 * Update parent inode's counts
134dab278af8180bc85783da0b908e2a1af1388522dTheodore Ts'o	 */
135dab278af8180bc85783da0b908e2a1af1388522dTheodore Ts'o	if (parent != ino) {
1362e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o		parent_inode.i_links_count++;
1372e8d40d562ec93d68505800a46c5b9dcc229264eTheodore Ts'o		retval = ext2fs_write_inode(fs, parent, &parent_inode);
138dab278af8180bc85783da0b908e2a1af1388522dTheodore Ts'o		if (retval)
139dab278af8180bc85783da0b908e2a1af1388522dTheodore Ts'o			goto cleanup;
140dab278af8180bc85783da0b908e2a1af1388522dTheodore Ts'o	}
141efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
142dab278af8180bc85783da0b908e2a1af1388522dTheodore Ts'o	/*
1433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * Update accounting....
1443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
145e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_block_alloc_stats2(fs, blk, +1);
1467f961d424b1ba527e835d01ad24e0e4c3f4088c5Theodore Ts'o	ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
1478bd0c95908baa3af706b9e731daff9472bec74c9Theodore Ts'o
1483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
1493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (block)
150c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&block);
1513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
1523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
156