/* * 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; }
/* * cap_lookup() * * This is the lookup() entry in the inode_operations structure for * HFS directories in the CAP scheme. The purpose is to generate the * inode corresponding to an entry in a directory, given the inode for * the directory and the name (and its length) of the entry. */ static struct dentry *cap_lookup(struct inode * dir, struct dentry *dentry) { ino_t dtype; struct hfs_name cname; struct hfs_cat_entry *entry; struct hfs_cat_key key; struct inode *inode = NULL; dentry->d_op = &hfs_dentry_operations; entry = HFS_I(dir)->entry; dtype = HFS_ITYPE(dir->i_ino); /* Perform name-mangling */ hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len); /* no need to check for "." or ".." */ /* Check for special directories if in a normal directory. Note that cap_dupdir() does an iput(dir). */ if (dtype==HFS_CAP_NDIR) { /* Check for ".resource", ".finderinfo" and ".rootinfo" */ if (hfs_streq(cname.Name, cname.Len, DOT_RESOURCE->Name, DOT_RESOURCE_LEN)) { ++entry->count; /* __hfs_iget() eats one */ inode = hfs_iget(entry, HFS_CAP_RDIR, dentry); goto done; } else if (hfs_streq(cname.Name, cname.Len, DOT_FINDERINFO->Name, DOT_FINDERINFO_LEN)) { ++entry->count; /* __hfs_iget() eats one */ inode = hfs_iget(entry, HFS_CAP_FDIR, dentry); goto done; } else if ((entry->cnid == htonl(HFS_ROOT_CNID)) && hfs_streq(cname.Name, cname.Len, DOT_ROOTINFO->Name, DOT_ROOTINFO_LEN)) { ++entry->count; /* __hfs_iget() eats one */ inode = hfs_iget(entry, HFS_CAP_FNDR, dentry); goto done; } } /* Do an hfs_iget() on the mangled name. */ hfs_cat_build_key(entry->cnid, &cname, &key); inode = hfs_iget(hfs_cat_get(entry->mdb, &key), HFS_I(dir)->file_type, dentry); /* Don't return a resource fork for a directory */ if (inode && (dtype == HFS_CAP_RDIR) && (HFS_I(inode)->entry->type == HFS_CDR_DIR)) { iput(inode); /* this does an hfs_cat_put */ inode = NULL; } done: d_add(dentry, inode); return NULL; }
/* * 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_read_super() * * This is the function that is responsible for mounting an HFS * filesystem. It performs all the tasks necessary to get enough data * from the disk to read the root inode. This includes parsing the * mount options, dealing with Macintosh partitions, reading the * superblock and the allocation bitmap blocks, calling * hfs_btree_init() to get the necessary data about the extents and * catalog B-trees and, finally, reading the root inode into memory. */ struct super_block *hfs_read_super(struct super_block *s, void *data, int silent) { struct hfs_mdb *mdb; struct hfs_cat_key key; kdev_t dev = s->s_dev; hfs_s32 part_size, part_start; struct inode *root_inode; int part; if (!parse_options((char *)data, HFS_SB(s), &part)) { hfs_warn("hfs_fs: unable to parse mount options.\n"); goto bail3; } /* set the device driver to 512-byte blocks */ set_blocksize(dev, HFS_SECTOR_SIZE); s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS; s->s_blocksize = HFS_SECTOR_SIZE; #ifdef CONFIG_MAC_PARTITION /* check to see if we're in a partition */ mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, 0); /* erk. try parsing the partition table ourselves */ if (!mdb) { if (hfs_part_find(s, part, silent, &part_size, &part_start)) { goto bail2; } mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, part_start); } #else if (hfs_part_find(s, part, silent, &part_size, &part_start)) { goto bail2; } mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, part_start); #endif if (!mdb) { if (!silent) { hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n", kdevname(dev)); } goto bail2; } HFS_SB(s)->s_mdb = mdb; if (HFS_ITYPE(mdb->next_id) != 0) { hfs_warn("hfs_fs: too many files.\n"); goto bail1; } s->s_magic = HFS_SUPER_MAGIC; s->s_op = &hfs_super_operations; /* try to get the root inode */ hfs_cat_build_key(htonl(HFS_POR_CNID), (struct hfs_name *)(mdb->vname), &key); root_inode = hfs_iget(hfs_cat_get(mdb, &key), HFS_ITYPE_NORM, NULL); if (!root_inode) goto bail_no_root; s->s_root = d_alloc_root(root_inode); if (!s->s_root) goto bail_no_root; /* fix up pointers. */ HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] = s->s_root; s->s_root->d_op = &hfs_dentry_operations; /* everything's okay */ return s; bail_no_root: hfs_warn("hfs_fs: get root inode failed.\n"); iput(root_inode); bail1: hfs_mdb_put(mdb, s->s_flags & MS_RDONLY); bail2: set_blocksize(dev, BLOCK_SIZE); bail3: return NULL; }