Beispiel #1
0
/*
 * 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;
}
Beispiel #2
0
/*
 * 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);
	  }
	}
}
Beispiel #3
0
/*
 * 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();
}
Beispiel #4
0
/*
 * 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;
}
Beispiel #5
0
/*
 * __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;
}