1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * linux/fs/hfsplus/dir.c 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Copyright (C) 2001 5*1da177e4SLinus Torvalds * Brad Boyer (flar@allandria.com) 6*1da177e4SLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com> 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * Handling of directories 9*1da177e4SLinus Torvalds */ 10*1da177e4SLinus Torvalds 11*1da177e4SLinus Torvalds #include <linux/errno.h> 12*1da177e4SLinus Torvalds #include <linux/fs.h> 13*1da177e4SLinus Torvalds #include <linux/sched.h> 14*1da177e4SLinus Torvalds #include <linux/slab.h> 15*1da177e4SLinus Torvalds #include <linux/random.h> 16*1da177e4SLinus Torvalds #include <linux/version.h> 17*1da177e4SLinus Torvalds 18*1da177e4SLinus Torvalds #include "hfsplus_fs.h" 19*1da177e4SLinus Torvalds #include "hfsplus_raw.h" 20*1da177e4SLinus Torvalds 21*1da177e4SLinus Torvalds static inline void hfsplus_instantiate(struct dentry *dentry, 22*1da177e4SLinus Torvalds struct inode *inode, u32 cnid) 23*1da177e4SLinus Torvalds { 24*1da177e4SLinus Torvalds dentry->d_fsdata = (void *)(unsigned long)cnid; 25*1da177e4SLinus Torvalds d_instantiate(dentry, inode); 26*1da177e4SLinus Torvalds } 27*1da177e4SLinus Torvalds 28*1da177e4SLinus Torvalds /* Find the entry inside dir named dentry->d_name */ 29*1da177e4SLinus Torvalds static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, 30*1da177e4SLinus Torvalds struct nameidata *nd) 31*1da177e4SLinus Torvalds { 32*1da177e4SLinus Torvalds struct inode *inode = NULL; 33*1da177e4SLinus Torvalds struct hfs_find_data fd; 34*1da177e4SLinus Torvalds struct super_block *sb; 35*1da177e4SLinus Torvalds hfsplus_cat_entry entry; 36*1da177e4SLinus Torvalds int err; 37*1da177e4SLinus Torvalds u32 cnid, linkid = 0; 38*1da177e4SLinus Torvalds u16 type; 39*1da177e4SLinus Torvalds 40*1da177e4SLinus Torvalds sb = dir->i_sb; 41*1da177e4SLinus Torvalds dentry->d_fsdata = NULL; 42*1da177e4SLinus Torvalds hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); 43*1da177e4SLinus Torvalds hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); 44*1da177e4SLinus Torvalds again: 45*1da177e4SLinus Torvalds err = hfs_brec_read(&fd, &entry, sizeof(entry)); 46*1da177e4SLinus Torvalds if (err) { 47*1da177e4SLinus Torvalds if (err == -ENOENT) { 48*1da177e4SLinus Torvalds hfs_find_exit(&fd); 49*1da177e4SLinus Torvalds /* No such entry */ 50*1da177e4SLinus Torvalds inode = NULL; 51*1da177e4SLinus Torvalds goto out; 52*1da177e4SLinus Torvalds } 53*1da177e4SLinus Torvalds goto fail; 54*1da177e4SLinus Torvalds } 55*1da177e4SLinus Torvalds type = be16_to_cpu(entry.type); 56*1da177e4SLinus Torvalds if (type == HFSPLUS_FOLDER) { 57*1da177e4SLinus Torvalds if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) { 58*1da177e4SLinus Torvalds err = -EIO; 59*1da177e4SLinus Torvalds goto fail; 60*1da177e4SLinus Torvalds } 61*1da177e4SLinus Torvalds cnid = be32_to_cpu(entry.folder.id); 62*1da177e4SLinus Torvalds dentry->d_fsdata = (void *)(unsigned long)cnid; 63*1da177e4SLinus Torvalds } else if (type == HFSPLUS_FILE) { 64*1da177e4SLinus Torvalds if (fd.entrylength < sizeof(struct hfsplus_cat_file)) { 65*1da177e4SLinus Torvalds err = -EIO; 66*1da177e4SLinus Torvalds goto fail; 67*1da177e4SLinus Torvalds } 68*1da177e4SLinus Torvalds cnid = be32_to_cpu(entry.file.id); 69*1da177e4SLinus Torvalds if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) && 70*1da177e4SLinus Torvalds entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR)) { 71*1da177e4SLinus Torvalds struct qstr str; 72*1da177e4SLinus Torvalds char name[32]; 73*1da177e4SLinus Torvalds 74*1da177e4SLinus Torvalds if (dentry->d_fsdata) { 75*1da177e4SLinus Torvalds err = -ENOENT; 76*1da177e4SLinus Torvalds inode = NULL; 77*1da177e4SLinus Torvalds goto out; 78*1da177e4SLinus Torvalds } 79*1da177e4SLinus Torvalds dentry->d_fsdata = (void *)(unsigned long)cnid; 80*1da177e4SLinus Torvalds linkid = be32_to_cpu(entry.file.permissions.dev); 81*1da177e4SLinus Torvalds str.len = sprintf(name, "iNode%d", linkid); 82*1da177e4SLinus Torvalds str.name = name; 83*1da177e4SLinus Torvalds hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str); 84*1da177e4SLinus Torvalds goto again; 85*1da177e4SLinus Torvalds } else if (!dentry->d_fsdata) 86*1da177e4SLinus Torvalds dentry->d_fsdata = (void *)(unsigned long)cnid; 87*1da177e4SLinus Torvalds } else { 88*1da177e4SLinus Torvalds printk("HFS+-fs: Illegal catalog entry type in lookup\n"); 89*1da177e4SLinus Torvalds err = -EIO; 90*1da177e4SLinus Torvalds goto fail; 91*1da177e4SLinus Torvalds } 92*1da177e4SLinus Torvalds hfs_find_exit(&fd); 93*1da177e4SLinus Torvalds inode = iget(dir->i_sb, cnid); 94*1da177e4SLinus Torvalds if (!inode) 95*1da177e4SLinus Torvalds return ERR_PTR(-EACCES); 96*1da177e4SLinus Torvalds if (S_ISREG(inode->i_mode)) 97*1da177e4SLinus Torvalds HFSPLUS_I(inode).dev = linkid; 98*1da177e4SLinus Torvalds out: 99*1da177e4SLinus Torvalds d_add(dentry, inode); 100*1da177e4SLinus Torvalds return NULL; 101*1da177e4SLinus Torvalds fail: 102*1da177e4SLinus Torvalds hfs_find_exit(&fd); 103*1da177e4SLinus Torvalds return ERR_PTR(err); 104*1da177e4SLinus Torvalds } 105*1da177e4SLinus Torvalds 106*1da177e4SLinus Torvalds static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) 107*1da177e4SLinus Torvalds { 108*1da177e4SLinus Torvalds struct inode *inode = filp->f_dentry->d_inode; 109*1da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 110*1da177e4SLinus Torvalds int len, err; 111*1da177e4SLinus Torvalds char strbuf[HFSPLUS_MAX_STRLEN + 1]; 112*1da177e4SLinus Torvalds hfsplus_cat_entry entry; 113*1da177e4SLinus Torvalds struct hfs_find_data fd; 114*1da177e4SLinus Torvalds struct hfsplus_readdir_data *rd; 115*1da177e4SLinus Torvalds u16 type; 116*1da177e4SLinus Torvalds 117*1da177e4SLinus Torvalds if (filp->f_pos >= inode->i_size) 118*1da177e4SLinus Torvalds return 0; 119*1da177e4SLinus Torvalds 120*1da177e4SLinus Torvalds hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); 121*1da177e4SLinus Torvalds hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); 122*1da177e4SLinus Torvalds err = hfs_brec_find(&fd); 123*1da177e4SLinus Torvalds if (err) 124*1da177e4SLinus Torvalds goto out; 125*1da177e4SLinus Torvalds 126*1da177e4SLinus Torvalds switch ((u32)filp->f_pos) { 127*1da177e4SLinus Torvalds case 0: 128*1da177e4SLinus Torvalds /* This is completely artificial... */ 129*1da177e4SLinus Torvalds if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR)) 130*1da177e4SLinus Torvalds goto out; 131*1da177e4SLinus Torvalds filp->f_pos++; 132*1da177e4SLinus Torvalds /* fall through */ 133*1da177e4SLinus Torvalds case 1: 134*1da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); 135*1da177e4SLinus Torvalds if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) { 136*1da177e4SLinus Torvalds printk("HFS+-fs: bad catalog folder thread\n"); 137*1da177e4SLinus Torvalds err = -EIO; 138*1da177e4SLinus Torvalds goto out; 139*1da177e4SLinus Torvalds } 140*1da177e4SLinus Torvalds if (fd.entrylength < HFSPLUS_MIN_THREAD_SZ) { 141*1da177e4SLinus Torvalds printk("HFS+-fs: truncated catalog thread\n"); 142*1da177e4SLinus Torvalds err = -EIO; 143*1da177e4SLinus Torvalds goto out; 144*1da177e4SLinus Torvalds } 145*1da177e4SLinus Torvalds if (filldir(dirent, "..", 2, 1, 146*1da177e4SLinus Torvalds be32_to_cpu(entry.thread.parentID), DT_DIR)) 147*1da177e4SLinus Torvalds goto out; 148*1da177e4SLinus Torvalds filp->f_pos++; 149*1da177e4SLinus Torvalds /* fall through */ 150*1da177e4SLinus Torvalds default: 151*1da177e4SLinus Torvalds if (filp->f_pos >= inode->i_size) 152*1da177e4SLinus Torvalds goto out; 153*1da177e4SLinus Torvalds err = hfs_brec_goto(&fd, filp->f_pos - 1); 154*1da177e4SLinus Torvalds if (err) 155*1da177e4SLinus Torvalds goto out; 156*1da177e4SLinus Torvalds } 157*1da177e4SLinus Torvalds 158*1da177e4SLinus Torvalds for (;;) { 159*1da177e4SLinus Torvalds if (be32_to_cpu(fd.key->cat.parent) != inode->i_ino) { 160*1da177e4SLinus Torvalds printk("HFS+-fs: walked past end of dir\n"); 161*1da177e4SLinus Torvalds err = -EIO; 162*1da177e4SLinus Torvalds goto out; 163*1da177e4SLinus Torvalds } 164*1da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); 165*1da177e4SLinus Torvalds type = be16_to_cpu(entry.type); 166*1da177e4SLinus Torvalds len = HFSPLUS_MAX_STRLEN; 167*1da177e4SLinus Torvalds err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len); 168*1da177e4SLinus Torvalds if (err) 169*1da177e4SLinus Torvalds goto out; 170*1da177e4SLinus Torvalds if (type == HFSPLUS_FOLDER) { 171*1da177e4SLinus Torvalds if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) { 172*1da177e4SLinus Torvalds printk("HFS+-fs: small dir entry\n"); 173*1da177e4SLinus Torvalds err = -EIO; 174*1da177e4SLinus Torvalds goto out; 175*1da177e4SLinus Torvalds } 176*1da177e4SLinus Torvalds if (HFSPLUS_SB(sb).hidden_dir && 177*1da177e4SLinus Torvalds HFSPLUS_SB(sb).hidden_dir->i_ino == be32_to_cpu(entry.folder.id)) 178*1da177e4SLinus Torvalds goto next; 179*1da177e4SLinus Torvalds if (filldir(dirent, strbuf, len, filp->f_pos, 180*1da177e4SLinus Torvalds be32_to_cpu(entry.folder.id), DT_DIR)) 181*1da177e4SLinus Torvalds break; 182*1da177e4SLinus Torvalds } else if (type == HFSPLUS_FILE) { 183*1da177e4SLinus Torvalds if (fd.entrylength < sizeof(struct hfsplus_cat_file)) { 184*1da177e4SLinus Torvalds printk("HFS+-fs: small file entry\n"); 185*1da177e4SLinus Torvalds err = -EIO; 186*1da177e4SLinus Torvalds goto out; 187*1da177e4SLinus Torvalds } 188*1da177e4SLinus Torvalds if (filldir(dirent, strbuf, len, filp->f_pos, 189*1da177e4SLinus Torvalds be32_to_cpu(entry.file.id), DT_REG)) 190*1da177e4SLinus Torvalds break; 191*1da177e4SLinus Torvalds } else { 192*1da177e4SLinus Torvalds printk("HFS+-fs: bad catalog entry type\n"); 193*1da177e4SLinus Torvalds err = -EIO; 194*1da177e4SLinus Torvalds goto out; 195*1da177e4SLinus Torvalds } 196*1da177e4SLinus Torvalds next: 197*1da177e4SLinus Torvalds filp->f_pos++; 198*1da177e4SLinus Torvalds if (filp->f_pos >= inode->i_size) 199*1da177e4SLinus Torvalds goto out; 200*1da177e4SLinus Torvalds err = hfs_brec_goto(&fd, 1); 201*1da177e4SLinus Torvalds if (err) 202*1da177e4SLinus Torvalds goto out; 203*1da177e4SLinus Torvalds } 204*1da177e4SLinus Torvalds rd = filp->private_data; 205*1da177e4SLinus Torvalds if (!rd) { 206*1da177e4SLinus Torvalds rd = kmalloc(sizeof(struct hfsplus_readdir_data), GFP_KERNEL); 207*1da177e4SLinus Torvalds if (!rd) { 208*1da177e4SLinus Torvalds err = -ENOMEM; 209*1da177e4SLinus Torvalds goto out; 210*1da177e4SLinus Torvalds } 211*1da177e4SLinus Torvalds filp->private_data = rd; 212*1da177e4SLinus Torvalds rd->file = filp; 213*1da177e4SLinus Torvalds list_add(&rd->list, &HFSPLUS_I(inode).open_dir_list); 214*1da177e4SLinus Torvalds } 215*1da177e4SLinus Torvalds memcpy(&rd->key, fd.key, sizeof(struct hfsplus_cat_key)); 216*1da177e4SLinus Torvalds out: 217*1da177e4SLinus Torvalds hfs_find_exit(&fd); 218*1da177e4SLinus Torvalds return err; 219*1da177e4SLinus Torvalds } 220*1da177e4SLinus Torvalds 221*1da177e4SLinus Torvalds static int hfsplus_dir_release(struct inode *inode, struct file *file) 222*1da177e4SLinus Torvalds { 223*1da177e4SLinus Torvalds struct hfsplus_readdir_data *rd = file->private_data; 224*1da177e4SLinus Torvalds if (rd) { 225*1da177e4SLinus Torvalds list_del(&rd->list); 226*1da177e4SLinus Torvalds kfree(rd); 227*1da177e4SLinus Torvalds } 228*1da177e4SLinus Torvalds return 0; 229*1da177e4SLinus Torvalds } 230*1da177e4SLinus Torvalds 231*1da177e4SLinus Torvalds static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode, 232*1da177e4SLinus Torvalds struct nameidata *nd) 233*1da177e4SLinus Torvalds { 234*1da177e4SLinus Torvalds struct inode *inode; 235*1da177e4SLinus Torvalds int res; 236*1da177e4SLinus Torvalds 237*1da177e4SLinus Torvalds inode = hfsplus_new_inode(dir->i_sb, mode); 238*1da177e4SLinus Torvalds if (!inode) 239*1da177e4SLinus Torvalds return -ENOSPC; 240*1da177e4SLinus Torvalds 241*1da177e4SLinus Torvalds res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); 242*1da177e4SLinus Torvalds if (res) { 243*1da177e4SLinus Torvalds inode->i_nlink = 0; 244*1da177e4SLinus Torvalds hfsplus_delete_inode(inode); 245*1da177e4SLinus Torvalds iput(inode); 246*1da177e4SLinus Torvalds return res; 247*1da177e4SLinus Torvalds } 248*1da177e4SLinus Torvalds hfsplus_instantiate(dentry, inode, inode->i_ino); 249*1da177e4SLinus Torvalds mark_inode_dirty(inode); 250*1da177e4SLinus Torvalds return 0; 251*1da177e4SLinus Torvalds } 252*1da177e4SLinus Torvalds 253*1da177e4SLinus Torvalds static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, 254*1da177e4SLinus Torvalds struct dentry *dst_dentry) 255*1da177e4SLinus Torvalds { 256*1da177e4SLinus Torvalds struct super_block *sb = dst_dir->i_sb; 257*1da177e4SLinus Torvalds struct inode *inode = src_dentry->d_inode; 258*1da177e4SLinus Torvalds struct inode *src_dir = src_dentry->d_parent->d_inode; 259*1da177e4SLinus Torvalds struct qstr str; 260*1da177e4SLinus Torvalds char name[32]; 261*1da177e4SLinus Torvalds u32 cnid, id; 262*1da177e4SLinus Torvalds int res; 263*1da177e4SLinus Torvalds 264*1da177e4SLinus Torvalds if (HFSPLUS_IS_RSRC(inode)) 265*1da177e4SLinus Torvalds return -EPERM; 266*1da177e4SLinus Torvalds 267*1da177e4SLinus Torvalds if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) { 268*1da177e4SLinus Torvalds for (;;) { 269*1da177e4SLinus Torvalds get_random_bytes(&id, sizeof(cnid)); 270*1da177e4SLinus Torvalds id &= 0x3fffffff; 271*1da177e4SLinus Torvalds str.name = name; 272*1da177e4SLinus Torvalds str.len = sprintf(name, "iNode%d", id); 273*1da177e4SLinus Torvalds res = hfsplus_rename_cat(inode->i_ino, 274*1da177e4SLinus Torvalds src_dir, &src_dentry->d_name, 275*1da177e4SLinus Torvalds HFSPLUS_SB(sb).hidden_dir, &str); 276*1da177e4SLinus Torvalds if (!res) 277*1da177e4SLinus Torvalds break; 278*1da177e4SLinus Torvalds if (res != -EEXIST) 279*1da177e4SLinus Torvalds return res; 280*1da177e4SLinus Torvalds } 281*1da177e4SLinus Torvalds HFSPLUS_I(inode).dev = id; 282*1da177e4SLinus Torvalds cnid = HFSPLUS_SB(sb).next_cnid++; 283*1da177e4SLinus Torvalds src_dentry->d_fsdata = (void *)(unsigned long)cnid; 284*1da177e4SLinus Torvalds res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode); 285*1da177e4SLinus Torvalds if (res) 286*1da177e4SLinus Torvalds /* panic? */ 287*1da177e4SLinus Torvalds return res; 288*1da177e4SLinus Torvalds HFSPLUS_SB(sb).file_count++; 289*1da177e4SLinus Torvalds } 290*1da177e4SLinus Torvalds cnid = HFSPLUS_SB(sb).next_cnid++; 291*1da177e4SLinus Torvalds res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode); 292*1da177e4SLinus Torvalds if (res) 293*1da177e4SLinus Torvalds return res; 294*1da177e4SLinus Torvalds 295*1da177e4SLinus Torvalds inode->i_nlink++; 296*1da177e4SLinus Torvalds hfsplus_instantiate(dst_dentry, inode, cnid); 297*1da177e4SLinus Torvalds atomic_inc(&inode->i_count); 298*1da177e4SLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 299*1da177e4SLinus Torvalds mark_inode_dirty(inode); 300*1da177e4SLinus Torvalds HFSPLUS_SB(sb).file_count++; 301*1da177e4SLinus Torvalds sb->s_dirt = 1; 302*1da177e4SLinus Torvalds 303*1da177e4SLinus Torvalds return 0; 304*1da177e4SLinus Torvalds } 305*1da177e4SLinus Torvalds 306*1da177e4SLinus Torvalds static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) 307*1da177e4SLinus Torvalds { 308*1da177e4SLinus Torvalds struct super_block *sb = dir->i_sb; 309*1da177e4SLinus Torvalds struct inode *inode = dentry->d_inode; 310*1da177e4SLinus Torvalds struct qstr str; 311*1da177e4SLinus Torvalds char name[32]; 312*1da177e4SLinus Torvalds u32 cnid; 313*1da177e4SLinus Torvalds int res; 314*1da177e4SLinus Torvalds 315*1da177e4SLinus Torvalds if (HFSPLUS_IS_RSRC(inode)) 316*1da177e4SLinus Torvalds return -EPERM; 317*1da177e4SLinus Torvalds 318*1da177e4SLinus Torvalds cnid = (u32)(unsigned long)dentry->d_fsdata; 319*1da177e4SLinus Torvalds if (inode->i_ino == cnid && 320*1da177e4SLinus Torvalds atomic_read(&HFSPLUS_I(inode).opencnt)) { 321*1da177e4SLinus Torvalds str.name = name; 322*1da177e4SLinus Torvalds str.len = sprintf(name, "temp%lu", inode->i_ino); 323*1da177e4SLinus Torvalds res = hfsplus_rename_cat(inode->i_ino, 324*1da177e4SLinus Torvalds dir, &dentry->d_name, 325*1da177e4SLinus Torvalds HFSPLUS_SB(sb).hidden_dir, &str); 326*1da177e4SLinus Torvalds if (!res) 327*1da177e4SLinus Torvalds inode->i_flags |= S_DEAD; 328*1da177e4SLinus Torvalds return res; 329*1da177e4SLinus Torvalds } 330*1da177e4SLinus Torvalds res = hfsplus_delete_cat(cnid, dir, &dentry->d_name); 331*1da177e4SLinus Torvalds if (res) 332*1da177e4SLinus Torvalds return res; 333*1da177e4SLinus Torvalds 334*1da177e4SLinus Torvalds inode->i_nlink--; 335*1da177e4SLinus Torvalds hfsplus_delete_inode(inode); 336*1da177e4SLinus Torvalds if (inode->i_ino != cnid && !inode->i_nlink) { 337*1da177e4SLinus Torvalds if (!atomic_read(&HFSPLUS_I(inode).opencnt)) { 338*1da177e4SLinus Torvalds res = hfsplus_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL); 339*1da177e4SLinus Torvalds if (!res) 340*1da177e4SLinus Torvalds hfsplus_delete_inode(inode); 341*1da177e4SLinus Torvalds } else 342*1da177e4SLinus Torvalds inode->i_flags |= S_DEAD; 343*1da177e4SLinus Torvalds } 344*1da177e4SLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 345*1da177e4SLinus Torvalds mark_inode_dirty(inode); 346*1da177e4SLinus Torvalds 347*1da177e4SLinus Torvalds return res; 348*1da177e4SLinus Torvalds } 349*1da177e4SLinus Torvalds 350*1da177e4SLinus Torvalds static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, int mode) 351*1da177e4SLinus Torvalds { 352*1da177e4SLinus Torvalds struct inode *inode; 353*1da177e4SLinus Torvalds int res; 354*1da177e4SLinus Torvalds 355*1da177e4SLinus Torvalds inode = hfsplus_new_inode(dir->i_sb, S_IFDIR | mode); 356*1da177e4SLinus Torvalds if (!inode) 357*1da177e4SLinus Torvalds return -ENOSPC; 358*1da177e4SLinus Torvalds 359*1da177e4SLinus Torvalds res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); 360*1da177e4SLinus Torvalds if (res) { 361*1da177e4SLinus Torvalds inode->i_nlink = 0; 362*1da177e4SLinus Torvalds hfsplus_delete_inode(inode); 363*1da177e4SLinus Torvalds iput(inode); 364*1da177e4SLinus Torvalds return res; 365*1da177e4SLinus Torvalds } 366*1da177e4SLinus Torvalds hfsplus_instantiate(dentry, inode, inode->i_ino); 367*1da177e4SLinus Torvalds mark_inode_dirty(inode); 368*1da177e4SLinus Torvalds return 0; 369*1da177e4SLinus Torvalds } 370*1da177e4SLinus Torvalds 371*1da177e4SLinus Torvalds static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry) 372*1da177e4SLinus Torvalds { 373*1da177e4SLinus Torvalds struct inode *inode; 374*1da177e4SLinus Torvalds int res; 375*1da177e4SLinus Torvalds 376*1da177e4SLinus Torvalds inode = dentry->d_inode; 377*1da177e4SLinus Torvalds if (inode->i_size != 2) 378*1da177e4SLinus Torvalds return -ENOTEMPTY; 379*1da177e4SLinus Torvalds res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); 380*1da177e4SLinus Torvalds if (res) 381*1da177e4SLinus Torvalds return res; 382*1da177e4SLinus Torvalds inode->i_nlink = 0; 383*1da177e4SLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 384*1da177e4SLinus Torvalds hfsplus_delete_inode(inode); 385*1da177e4SLinus Torvalds mark_inode_dirty(inode); 386*1da177e4SLinus Torvalds return 0; 387*1da177e4SLinus Torvalds } 388*1da177e4SLinus Torvalds 389*1da177e4SLinus Torvalds static int hfsplus_symlink(struct inode *dir, struct dentry *dentry, 390*1da177e4SLinus Torvalds const char *symname) 391*1da177e4SLinus Torvalds { 392*1da177e4SLinus Torvalds struct super_block *sb; 393*1da177e4SLinus Torvalds struct inode *inode; 394*1da177e4SLinus Torvalds int res; 395*1da177e4SLinus Torvalds 396*1da177e4SLinus Torvalds sb = dir->i_sb; 397*1da177e4SLinus Torvalds inode = hfsplus_new_inode(sb, S_IFLNK | S_IRWXUGO); 398*1da177e4SLinus Torvalds if (!inode) 399*1da177e4SLinus Torvalds return -ENOSPC; 400*1da177e4SLinus Torvalds 401*1da177e4SLinus Torvalds res = page_symlink(inode, symname, strlen(symname) + 1); 402*1da177e4SLinus Torvalds if (res) { 403*1da177e4SLinus Torvalds inode->i_nlink = 0; 404*1da177e4SLinus Torvalds hfsplus_delete_inode(inode); 405*1da177e4SLinus Torvalds iput(inode); 406*1da177e4SLinus Torvalds return res; 407*1da177e4SLinus Torvalds } 408*1da177e4SLinus Torvalds 409*1da177e4SLinus Torvalds mark_inode_dirty(inode); 410*1da177e4SLinus Torvalds res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); 411*1da177e4SLinus Torvalds 412*1da177e4SLinus Torvalds if (!res) { 413*1da177e4SLinus Torvalds hfsplus_instantiate(dentry, inode, inode->i_ino); 414*1da177e4SLinus Torvalds mark_inode_dirty(inode); 415*1da177e4SLinus Torvalds } 416*1da177e4SLinus Torvalds 417*1da177e4SLinus Torvalds return res; 418*1da177e4SLinus Torvalds } 419*1da177e4SLinus Torvalds 420*1da177e4SLinus Torvalds static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, 421*1da177e4SLinus Torvalds int mode, dev_t rdev) 422*1da177e4SLinus Torvalds { 423*1da177e4SLinus Torvalds struct super_block *sb; 424*1da177e4SLinus Torvalds struct inode *inode; 425*1da177e4SLinus Torvalds int res; 426*1da177e4SLinus Torvalds 427*1da177e4SLinus Torvalds sb = dir->i_sb; 428*1da177e4SLinus Torvalds inode = hfsplus_new_inode(sb, mode); 429*1da177e4SLinus Torvalds if (!inode) 430*1da177e4SLinus Torvalds return -ENOSPC; 431*1da177e4SLinus Torvalds 432*1da177e4SLinus Torvalds res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); 433*1da177e4SLinus Torvalds if (res) { 434*1da177e4SLinus Torvalds inode->i_nlink = 0; 435*1da177e4SLinus Torvalds hfsplus_delete_inode(inode); 436*1da177e4SLinus Torvalds iput(inode); 437*1da177e4SLinus Torvalds return res; 438*1da177e4SLinus Torvalds } 439*1da177e4SLinus Torvalds init_special_inode(inode, mode, rdev); 440*1da177e4SLinus Torvalds hfsplus_instantiate(dentry, inode, inode->i_ino); 441*1da177e4SLinus Torvalds mark_inode_dirty(inode); 442*1da177e4SLinus Torvalds 443*1da177e4SLinus Torvalds return 0; 444*1da177e4SLinus Torvalds } 445*1da177e4SLinus Torvalds 446*1da177e4SLinus Torvalds static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry, 447*1da177e4SLinus Torvalds struct inode *new_dir, struct dentry *new_dentry) 448*1da177e4SLinus Torvalds { 449*1da177e4SLinus Torvalds int res; 450*1da177e4SLinus Torvalds 451*1da177e4SLinus Torvalds /* Unlink destination if it already exists */ 452*1da177e4SLinus Torvalds if (new_dentry->d_inode) { 453*1da177e4SLinus Torvalds res = hfsplus_unlink(new_dir, new_dentry); 454*1da177e4SLinus Torvalds if (res) 455*1da177e4SLinus Torvalds return res; 456*1da177e4SLinus Torvalds } 457*1da177e4SLinus Torvalds 458*1da177e4SLinus Torvalds res = hfsplus_rename_cat((u32)(unsigned long)old_dentry->d_fsdata, 459*1da177e4SLinus Torvalds old_dir, &old_dentry->d_name, 460*1da177e4SLinus Torvalds new_dir, &new_dentry->d_name); 461*1da177e4SLinus Torvalds if (!res) 462*1da177e4SLinus Torvalds new_dentry->d_fsdata = old_dentry->d_fsdata; 463*1da177e4SLinus Torvalds return res; 464*1da177e4SLinus Torvalds } 465*1da177e4SLinus Torvalds 466*1da177e4SLinus Torvalds struct inode_operations hfsplus_dir_inode_operations = { 467*1da177e4SLinus Torvalds .lookup = hfsplus_lookup, 468*1da177e4SLinus Torvalds .create = hfsplus_create, 469*1da177e4SLinus Torvalds .link = hfsplus_link, 470*1da177e4SLinus Torvalds .unlink = hfsplus_unlink, 471*1da177e4SLinus Torvalds .mkdir = hfsplus_mkdir, 472*1da177e4SLinus Torvalds .rmdir = hfsplus_rmdir, 473*1da177e4SLinus Torvalds .symlink = hfsplus_symlink, 474*1da177e4SLinus Torvalds .mknod = hfsplus_mknod, 475*1da177e4SLinus Torvalds .rename = hfsplus_rename, 476*1da177e4SLinus Torvalds }; 477*1da177e4SLinus Torvalds 478*1da177e4SLinus Torvalds struct file_operations hfsplus_dir_operations = { 479*1da177e4SLinus Torvalds .read = generic_read_dir, 480*1da177e4SLinus Torvalds .readdir = hfsplus_readdir, 481*1da177e4SLinus Torvalds .ioctl = hfsplus_ioctl, 482*1da177e4SLinus Torvalds .llseek = generic_file_llseek, 483*1da177e4SLinus Torvalds .release = hfsplus_dir_release, 484*1da177e4SLinus Torvalds }; 485