btrfs_free_path(path);
return ret;
}
+
+/* Fill inode item with 'mode'. Uid/gid to root/root */
+static void fill_inode_item(struct btrfs_trans_handle *trans,
+ struct btrfs_inode_item *inode_item,
+ u32 mode, u32 nlink)
+{
+ time_t now = time(NULL);
+
+ btrfs_set_stack_inode_generation(inode_item, trans->transid);
+ btrfs_set_stack_inode_uid(inode_item, 0);
+ btrfs_set_stack_inode_gid(inode_item, 0);
+ btrfs_set_stack_inode_size(inode_item, 0);
+ btrfs_set_stack_inode_mode(inode_item, mode);
+ btrfs_set_stack_inode_nlink(inode_item, nlink);
+ btrfs_set_stack_timespec_sec(&inode_item->atime, now);
+ btrfs_set_stack_timespec_nsec(&inode_item->atime, 0);
+ btrfs_set_stack_timespec_sec(&inode_item->mtime, now);
+ btrfs_set_stack_timespec_nsec(&inode_item->mtime, 0);
+ btrfs_set_stack_timespec_sec(&inode_item->ctime, now);
+ btrfs_set_stack_timespec_nsec(&inode_item->ctime, 0);
+}
+
+/*
+ * Unlike kernel btrfs_new_inode(), we only create the INODE_ITEM, without
+ * its backref.
+ * The backref is added by btrfs_add_link().
+ */
+static int btrfs_new_inode(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u64 ino, u32 mode)
+{
+ struct btrfs_inode_item inode_item = {0};
+ int ret = 0;
+
+ fill_inode_item(trans, &inode_item, mode, 0);
+ ret = btrfs_insert_inode(trans, root, ino, &inode_item);
+ return ret;
+}
+
+/*
+ * Make a dir under the parent inode 'parent_ino' with 'name'
+ * and 'mode', The owner will be root/root.
+ */
+int btrfs_mkdir(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ char *name, int namelen, u64 parent_ino, u64 *ino, int mode)
+{
+ struct btrfs_dir_item *dir_item;
+ struct btrfs_path *path;
+ u64 ret_ino = 0;
+ int ret = 0;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ if (ino && *ino)
+ ret_ino = *ino;
+
+ dir_item = btrfs_lookup_dir_item(NULL, root, path, parent_ino,
+ name, namelen, 0);
+ if (IS_ERR(dir_item)) {
+ ret = PTR_ERR(dir_item);
+ goto out;
+ }
+
+ if (dir_item) {
+ struct btrfs_key found_key;
+
+ /*
+ * Already have conflicting name, check if it is a dir.
+ * Either way, no need to continue.
+ */
+ btrfs_dir_item_key_to_cpu(path->nodes[0], dir_item, &found_key);
+ ret_ino = found_key.objectid;
+ if (btrfs_dir_type(path->nodes[0], dir_item) != BTRFS_FT_DIR)
+ ret = -EEXIST;
+ goto out;
+ }
+
+ if (!ret_ino)
+ /*
+ * This is *UNSAFE* if some leaf is corrupted,
+ * only used as a fallback method. Caller should either
+ * ensure the fs is OK or pass ino with unused inode number.
+ */
+ ret = btrfs_find_free_objectid(NULL, root, parent_ino,
+ &ret_ino);
+ if (ret)
+ goto out;
+ ret = btrfs_new_inode(trans, root, ret_ino, mode | S_IFDIR);
+ if (ret)
+ goto out;
+ ret = btrfs_add_link(trans, root, ret_ino, parent_ino, name, namelen,
+ BTRFS_FT_DIR, NULL, 1);
+ if (ret)
+ goto out;
+out:
+ btrfs_free_path(path);
+ if (ret == 0 && ino)
+ *ino = ret_ino;
+ return ret;
+}