/* * nat_hdr_unlink() * * This is the unlink() entry in the inode_operations structure for * Netatalk .AppleDouble directories. The purpose is to delete an * existing file, given the inode for the parent directory and the name * (and its length) of the existing file. * * WE DON'T ACTUALLY DELETE HEADER THE FILE. * In non-afpd-compatible mode: * We return -EPERM. * In afpd-compatible mode: * We return success if the file exists or is .Parent. * Otherwise we return -ENOENT. */ static int nat_hdr_unlink(struct inode *dir, const char *name, int len) { struct hfs_cat_entry *entry = HFS_I(dir)->entry; int error = 0; if (!HFS_SB(dir->i_sb)->s_afpd) { /* Not in AFPD compatibility mode */ error = -EPERM; } else { struct hfs_name cname; hfs_nameout(dir, &cname, name, len); if (!hfs_streq(&cname, DOT_PARENT)) { struct hfs_cat_entry *victim; struct hfs_cat_key key; hfs_cat_build_key(entry->cnid, &cname, &key); victim = hfs_cat_get(entry->mdb, &key); if (victim) { /* pretend to succeed */ hfs_cat_put(victim); } else { error = -ENOENT; } } } iput(dir); return error; }
/* * hfs_put_inode() * * This is the put_inode() entry in the super_operations for HFS * filesystems. The purpose is to perform any filesystem-dependent * cleanup necessary when the use-count of an inode falls to zero. */ void hfs_put_inode(struct inode * inode) { struct hfs_cat_entry *entry = HFS_I(inode)->entry; hfs_cat_put(entry); if (inode->i_count == 1) { struct hfs_hdr_layout *tmp = HFS_I(inode)->layout; if (tmp) { HFS_I(inode)->layout = NULL; HFS_DELETE(tmp); } } }
/* * hfs_put_inode() * * This is the put_inode() entry in the super_operations for HFS * filesystems. The purpose is to perform any filesystem-dependent * cleanup necessary when the use-count of an inode falls to zero. */ void hfs_put_inode(struct inode * inode) { struct hfs_cat_entry *entry = HFS_I(inode)->entry; lock_kernel(); hfs_cat_put(entry); if (atomic_read(&inode->i_count) == 1) { struct hfs_hdr_layout *tmp = HFS_I(inode)->layout; if (tmp) { HFS_I(inode)->layout = NULL; HFS_DELETE(tmp); } } unlock_kernel(); }
/* * nat_hdr_rename() * * This is the rename() entry in the inode_operations structure for * Netatalk header directories. The purpose is to rename an existing * file given the inode for the current directory and the name * (and its length) of the existing file and the inode for the new * directory and the name (and its length) of the new file/directory. * * WE NEVER MOVE ANYTHING. * In non-afpd-compatible mode: * We return -EPERM. * In afpd-compatible mode: * If the source header doesn't exist, we return -ENOENT. * If the destination is not a header directory we return -EPERM. * We return success if the destination is also a header directory * and the header exists or is ".Parent". */ static int nat_hdr_rename(struct inode *old_dir, const char *old_name, int old_len, struct inode *new_dir, const char *new_name, int new_len, int must_be_dir) { struct hfs_cat_entry *entry = HFS_I(old_dir)->entry; int error = 0; if (!HFS_SB(old_dir->i_sb)->s_afpd) { /* Not in AFPD compatibility mode */ error = -EPERM; } else { struct hfs_name cname; hfs_nameout(old_dir, &cname, old_name, old_len); if (!hfs_streq(&cname, DOT_PARENT)) { struct hfs_cat_entry *victim; struct hfs_cat_key key; hfs_cat_build_key(entry->cnid, &cname, &key); victim = hfs_cat_get(entry->mdb, &key); if (victim) { /* pretend to succeed */ hfs_cat_put(victim); } else { error = -ENOENT; } } if (!error && (HFS_ITYPE(new_dir->i_ino) != HFS_NAT_HDIR)) { error = -EPERM; } } iput(old_dir); iput(new_dir); return error; }
/* * __hfs_iget() * * Given the MDB for a HFS filesystem, a 'key' and an 'entry' in * the catalog B-tree and the 'type' of the desired file return the * inode for that file/directory or NULL. Note that 'type' indicates * whether we want the actual file or directory, or the corresponding * metadata (AppleDouble header file or CAP metadata file). * * In an ideal world we could call iget() and would not need this * function. However, since there is no way to even know the inode * number until we've found the file/directory in the catalog B-tree * that simply won't happen. * * The main idea here is to look in the catalog B-tree to get the * vital info about the file or directory (including the file id which * becomes the inode number) and then to call iget() and return the * inode if it is complete. If it is not then we use the catalog * entry to fill in the missing info, by calling the appropriate * 'fillin' function. Note that these fillin functions are * essentially hfs_*_read_inode() functions, but since there is no way * to pass the catalog entry through iget() to such a read_inode() * function, we have to call them after iget() returns an incomplete * inode to us. This is pretty much the same problem faced in the NFS * code, and pretty much the same solution. The SMB filesystem deals * with this in a different way: by using the address of the * kmalloc()'d space which holds the data as the inode number. * * XXX: Both this function and NFS's corresponding nfs_fhget() would * benefit from a way to pass an additional (void *) through iget() to * the VFS read_inode() function. * * this will hfs_cat_put() the entry if it fails. */ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type, struct dentry *dentry) { struct dentry **sys_entry; struct super_block *sb; struct inode *inode; if (!entry) { return NULL; } /* If there are several processes all calling __iget() for the same inode then they will all get the same one back. The first one to return from __iget() will notice that the i_mode field of the inode is blank and KNOW that it is the first to return. Therefore, it will set the appropriate 'sys_entry' field in the entry and initialize the inode. All the initialization must be done without sleeping, or else other processes could end up using a partially initialized inode. */ sb = entry->mdb->sys_mdb; sys_entry = &entry->sys_entry[HFS_ITYPE_TO_INT(type)]; if (!(inode = iget(sb, ntohl(entry->cnid) | type))) { hfs_cat_put(entry); return NULL; } if (!inode->i_mode || (*sys_entry == NULL)) { /* Initialize the inode */ struct hfs_sb_info *hsb = HFS_SB(sb); inode->i_ctime.tv_sec = inode->i_atime.tv_sec = inode->i_mtime.tv_sec = hfs_m_to_utime(entry->modify_date); inode->i_ctime.tv_nsec = 0; inode->i_mtime.tv_nsec = 0; inode->i_atime.tv_nsec = 0; inode->i_blksize = HFS_SECTOR_SIZE; inode->i_uid = hsb->s_uid; inode->i_gid = hsb->s_gid; HFS_I(inode)->mmu_private = 0; HFS_I(inode)->fork = NULL; HFS_I(inode)->convert = 0; HFS_I(inode)->file_type = 0; HFS_I(inode)->dir_size = 0; HFS_I(inode)->default_layout = NULL; HFS_I(inode)->layout = NULL; HFS_I(inode)->magic = HFS_INO_MAGIC; HFS_I(inode)->entry = entry; HFS_I(inode)->tz_secondswest = hfs_to_utc(0); hsb->s_ifill(inode, type, hsb->s_version); if (!hsb->s_afpd && (entry->type == HFS_CDR_FIL) && (entry->u.file.flags & HFS_FIL_LOCK)) { inode->i_mode &= ~S_IWUGO; } inode->i_mode &= ~hsb->s_umask; if (!inode->i_mode) { iput(inode); /* does an hfs_cat_put */ inode = NULL; } else *sys_entry = dentry; /* cache dentry */ } return inode; }