Esempio n. 1
0
/*
 * build_key()
 *
 * Build a key for a file by the given name in the given directory.
 * If the name matches one of the reserved names returns 1 otherwise 0.
 */
static int build_key(struct hfs_cat_key *key, struct inode *dir,
		     const char *name, int len)
{
	struct hfs_name cname;
	const struct hfs_name *reserved;

	/* mangle the name */
	hfs_nameout(dir, &cname, name, len);

	/* check against reserved names */
	reserved = HFS_SB(dir->i_sb)->s_reserved1;
	while (reserved->Len) {
		if (hfs_streq(reserved, &cname)) {
			return 1;
		}
		++reserved;
	}

	/* check against the names reserved only in the root directory */
	if (HFS_I(dir)->entry->cnid == htonl(HFS_ROOT_CNID)) {
		reserved = HFS_SB(dir->i_sb)->s_reserved2;
		while (reserved->Len) {
			if (hfs_streq(reserved, &cname)) {
				return 1;
			}
			++reserved;
		}
	}

	/* build the key */
	hfs_cat_build_key(HFS_I(dir)->entry->cnid, &cname, key);

	return 0;
}
Esempio n. 2
0
/*
 * init_file_inode()
 *
 * Given an HFS catalog entry initialize an inode for a file.
 */
static void init_file_inode(struct inode *inode, hfs_u8 fork)
{
    struct hfs_fork *fk;
    struct hfs_cat_entry *entry = HFS_I(inode)->entry;

    if (fork == HFS_FK_DATA) {
        inode->i_mode = S_IRWXUGO | S_IFREG;
    } else {
        inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG;
    }

    if (fork == HFS_FK_DATA) {
#if 0 /* XXX: disable crlf translations for now */
        hfs_u32 type = hfs_get_nl(entry->info.file.finfo.fdType);

        HFS_I(inode)->convert =
            ((HFS_SB(inode->i_sb)->s_conv == 't') ||
             ((HFS_SB(inode->i_sb)->s_conv == 'a') &&
              ((type == htonl(0x54455854)) ||   /* "TEXT" */
               (type == htonl(0x7474726f)))));  /* "ttro" */
#else
        HFS_I(inode)->convert = 0;
#endif
        fk = &entry->u.file.data_fork;
    } else {
        fk = &entry->u.file.rsrc_fork;
        HFS_I(inode)->convert = 0;
    }
    HFS_I(inode)->fork = fk;
    inode->i_size = fk->lsize;
    inode->i_blocks = fk->psize;
    inode->i_nlink = 1;
}
Esempio n. 3
0
/*
 * hfs_create()
 *
 * This is the create() entry in the inode_operations structure for
 * regular HFS directories.  The purpose is to create a new file in
 * a directory and return a corresponding inode, given the inode for
 * the directory and the name (and its length) of the new file.
 */
int hfs_create(struct inode * dir, const char * name, int len, int mode,
	       struct inode ** result)
{
	struct hfs_cat_entry *entry = HFS_I(dir)->entry;
	struct hfs_cat_entry *new;
	struct hfs_cat_key key;
	int error;

	*result = NULL;

	/* build the key, checking against reserved names */
	if (build_key(&key, dir, name, len)) {
		error = -EEXIST;
	} else {
		/* try to create the file */
		error = hfs_cat_create(entry, &key, 
				       (mode & S_IWUSR) ? 0 : HFS_FIL_LOCK,
				       HFS_SB(dir->i_sb)->s_type,
				       HFS_SB(dir->i_sb)->s_creator, &new);
	}

	if (!error) {
		update_dirs_plus(entry, 0);

		/* create an inode for the new file */
		*result = __hfs_iget(new, HFS_I(dir)->file_type, 0);
		if (!(*result)) {
			/* XXX correct error? */
			error = -EIO;
		}
	}
Esempio n. 4
0
/*
 * 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;
}
Esempio n. 5
0
static int hfs_dir_release(struct inode *inode, struct file *file)
{
	struct hfs_readdir_data *rd = file->private_data;
	if (rd) {
		spin_lock(&HFS_I(inode)->open_dir_lock);
		list_del(&rd->list);
		spin_unlock(&HFS_I(inode)->open_dir_lock);
		kfree(rd);
	}
	return 0;
}
Esempio n. 6
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);
	  }
	}
}
Esempio n. 7
0
static int hfs_ext_read_extent(struct inode *inode, u16 block)
{
	struct hfs_find_data fd;
	int res;

	if (block >= HFS_I(inode)->cached_start &&
	    block < HFS_I(inode)->cached_start + HFS_I(inode)->cached_blocks)
		return 0;

	hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, &fd);
	res = __hfs_ext_cache_extent(&fd, inode, block);
	hfs_find_exit(&fd);
	return res;
}
Esempio n. 8
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();
}
Esempio n. 9
0
/*
 * hfs_rename()
 *
 * This is the rename() entry in the inode_operations structure for
 * regular HFS directories.  The purpose is to rename an existing
 * file or directory, given the inode for the current directory and
 * the name (and its length) of the existing file/directory and the
 * inode for the new directory and the name (and its length) of the
 * new file/directory.
 * XXX: how do you handle must_be dir?
 */
static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		      struct inode *new_dir, struct dentry *new_dentry,
		      unsigned int flags)
{
	int res;

	if (flags & ~RENAME_NOREPLACE)
		return -EINVAL;

	/* Unlink destination if it already exists */
	if (d_really_is_positive(new_dentry)) {
		res = hfs_remove(new_dir, new_dentry);
		if (res)
			return res;
	}

	res = hfs_cat_move(d_inode(old_dentry)->i_ino,
			   old_dir, &old_dentry->d_name,
			   new_dir, &new_dentry->d_name);
	if (!res)
		hfs_cat_build_key(old_dir->i_sb,
				  (btree_key *)&HFS_I(d_inode(old_dentry))->cat_key,
				  new_dir->i_ino, &new_dentry->d_name);
	return res;
}
Esempio n. 10
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;
}
Esempio n. 11
0
/*
 * cap_info_read()
 *
 * This is the read() entry in the file_operations structure for CAP
 * metadata files.  The purpose is to transfer up to 'count' bytes
 * from the file corresponding to 'inode' beginning at offset
 * 'file->f_pos' to user-space at the address 'buf'.  The return value
 * is the number of bytes actually transferred.
 */
static hfs_rwret_t cap_info_read(struct file *filp, char *buf,
				 hfs_rwarg_t count, loff_t *ppos)
{
	struct inode *inode = filp->f_dentry->d_inode;
	struct hfs_cat_entry *entry = HFS_I(inode)->entry;
	hfs_s32 left, size, read = 0;
	hfs_u32 pos;

	if (!S_ISREG(inode->i_mode)) {
		hfs_warn("hfs_cap_info_read: mode = %07o\n", inode->i_mode);
		return -EINVAL;
	}

	pos = *ppos;
	if (pos > HFS_FORK_MAX) {
		return 0;
	}
	size = inode->i_size;
	if (pos > size) {
		left = 0;
	} else {
		left = size - pos;
	}
	if (left > count) {
		left = count;
	}
	if (left <= 0) {
		return 0;
	}

	if (pos < sizeof(struct hfs_cap_info)) {
		int memcount = sizeof(struct hfs_cap_info) - pos;
		struct hfs_cap_info meta;

		if (memcount > left) {
			memcount = left;
		}
		cap_build_meta(&meta, entry);
		memcount -= copy_to_user(buf, ((char *)&meta) + pos, memcount);
		left -= memcount;
		read += memcount;
		pos += memcount;
		buf += memcount;
	}

	if (left > 0) {
		clear_user(buf, left);
	        pos += left;
	}

	if (read) {
		inode->i_atime = CURRENT_TIME;
		*ppos = pos;
		mark_inode_dirty(inode);
	}

	return read;
}
Esempio n. 12
0
File: sysdep.c Progetto: 274914765/C
static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd)
{
    struct inode *inode = dentry->d_inode;
    int diff;

    if(!inode)
        return 1;

    /* fix up inode on a timezone change */
    diff = sys_tz.tz_minuteswest * 60 - HFS_I(inode)->tz_secondswest;
    if (diff) {
        inode->i_ctime.tv_sec += diff;
        inode->i_atime.tv_sec += diff;
        inode->i_mtime.tv_sec += diff;
        HFS_I(inode)->tz_secondswest += diff;
    }
    return 1;
}
Esempio n. 13
0
static int hfs_write_begin(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata)
{
	*pagep = NULL;
	return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
				hfs_get_block,
				&HFS_I(mapping->host)->phys_size);
}
Esempio n. 14
0
void hfs_ext_write_extent(struct inode *inode)
{
	struct hfs_find_data fd;

	if (HFS_I(inode)->flags & HFS_FLG_EXT_DIRTY) {
		hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, &fd);
		__hfs_ext_write_extent(inode, &fd);
		hfs_find_exit(&fd);
	}
}
Esempio n. 15
0
/* 
 * hfs_dbl_ifill()
 *
 * This function serves the same purpose as a read_inode() function does
 * in other filesystems.  It is called by __hfs_iget() to fill in
 * the missing fields of an uninitialized inode under the AppleDouble
 * scheme.
 */
void hfs_dbl_ifill(struct inode * inode, ino_t type, const int version)
{
	struct hfs_cat_entry *entry = HFS_I(inode)->entry;

	HFS_I(inode)->d_drop_op = hfs_dbl_drop_dentry;
	if (type == HFS_DBL_HDR) {
		if (entry->type == HFS_CDR_FIL) {
			init_file_inode(inode, HFS_FK_RSRC);
			inode->i_size += HFS_DBL_HDR_LEN;
			HFS_I(inode)->default_layout = &hfs_dbl_fil_hdr_layout;
		} else {
			inode->i_size = HFS_DBL_HDR_LEN;
			inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG;
			inode->i_nlink = 1;
			HFS_I(inode)->default_layout = &hfs_dbl_dir_hdr_layout;
		}
		inode->i_op = &hfs_hdr_inode_operations;
	} else if (entry->type == HFS_CDR_FIL) {
		init_file_inode(inode, HFS_FK_DATA);
		inode->i_op = &hfs_file_inode_operations;
	} else { /* Directory */
		struct hfs_dir *hdir = &entry->u.dir;

		inode->i_blocks = 0;
		inode->i_nlink = hdir->dirs + 2;
		inode->i_size = 3 + 2 * (hdir->dirs + hdir->files);
		inode->i_mode = S_IRWXUGO | S_IFDIR;
		inode->i_op = &hfs_dbl_dir_inode_operations;
		HFS_I(inode)->file_type = HFS_DBL_NORM;
		HFS_I(inode)->dir_size = 2;
	}
}
Esempio n. 16
0
/*
 * cap_info_write()
 *
 * This is the write() entry in the file_operations structure for CAP
 * metadata files.  The purpose is to transfer up to 'count' bytes
 * to the file corresponding to 'inode' beginning at offset
 * '*ppos' from user-space at the address 'buf'.
 * The return value is the number of bytes actually transferred.
 */
static hfs_rwret_t cap_info_write(struct file *filp, const char *buf, 
				  hfs_rwarg_t count, loff_t *ppos)
{
        struct inode *inode = filp->f_dentry->d_inode;
	hfs_u32 pos;

	if (!S_ISREG(inode->i_mode)) {
		hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode);
		return -EINVAL;
	}
	if (count <= 0) {
		return 0;
	}
	
	pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;

	if (pos > HFS_FORK_MAX) {
		return 0;
	}

	*ppos += count;
	if (*ppos > HFS_FORK_MAX) {
		*ppos = HFS_FORK_MAX;
		count = HFS_FORK_MAX - pos;
	}

	if (*ppos > inode->i_size)
	        inode->i_size = *ppos;

	/* Only deal with the part we store in memory */
	if (pos < sizeof(struct hfs_cap_info)) {
		int end, mem_count;
		struct hfs_cat_entry *entry = HFS_I(inode)->entry;
		struct hfs_cap_info meta;

		mem_count = sizeof(struct hfs_cap_info) - pos;
		if (mem_count > count) {
			mem_count = count;
		}
		end = pos + mem_count;

		cap_build_meta(&meta, entry);
		mem_count -= copy_from_user(((char *)&meta) + pos, buf, mem_count);

		/* Update finder attributes if changed */
		if (OVERLAPS(pos, end, struct hfs_cap_info, fi_fndr)) {
			memcpy(&entry->info, meta.fi_fndr, 32);
			hfs_cat_mark_dirty(entry);
		}
Esempio n. 17
0
static int hfs_write_begin(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata)
{
	int ret;

	*pagep = NULL;
	ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
				hfs_get_block,
				&HFS_I(mapping->host)->phys_size);
	if (unlikely(ret))
		hfs_write_failed(mapping, pos + len);

	return ret;
}
Esempio n. 18
0
static ssize_t __hfs_getxattr(struct inode *inode, enum hfs_xattr_type type,
			      void *value, size_t size)
{
	struct hfs_find_data fd;
	hfs_cat_rec rec;
	struct hfs_cat_file *file;
	ssize_t res = 0;

	if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
		return -EOPNOTSUPP;

	if (size) {
		res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
		if (res)
			return res;
		fd.search_key->cat = HFS_I(inode)->cat_key;
		res = hfs_brec_find(&fd);
		if (res)
			goto out;
		hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
				sizeof(struct hfs_cat_file));
	}
	file = &rec.file;

	switch (type) {
	case HFS_TYPE:
		if (size >= 4) {
			memcpy(value, &file->UsrWds.fdType, 4);
			res = 4;
		} else
			res = size ? -ERANGE : 4;
		break;

	case HFS_CREATOR:
		if (size >= 4) {
			memcpy(value, &file->UsrWds.fdCreator, 4);
			res = 4;
		} else
			res = size ? -ERANGE : 4;
		break;
	}

out:
	if (size)
		hfs_find_exit(&fd);
	return res;
}
Esempio n. 19
0
static inline int __hfs_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block)
{
	int res;

	if (HFS_I(inode)->flags & HFS_FLG_EXT_DIRTY)
		__hfs_ext_write_extent(inode, fd);

	res = __hfs_ext_read_extent(fd, HFS_I(inode)->cached_extents, inode->i_ino,
				    block, HFS_IS_RSRC(inode) ? HFS_FK_RSRC : HFS_FK_DATA);
	if (!res) {
		HFS_I(inode)->cached_start = be16_to_cpu(fd->key->ext.FABN);
		HFS_I(inode)->cached_blocks = hfs_ext_block_count(HFS_I(inode)->cached_extents);
	} else {
		HFS_I(inode)->cached_start = HFS_I(inode)->cached_blocks = 0;
		HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW);
	}
	return res;
}
Esempio n. 20
0
static int __hfs_setxattr(struct inode *inode, enum hfs_xattr_type type,
			  const void *value, size_t size, int flags)
{
	struct hfs_find_data fd;
	hfs_cat_rec rec;
	struct hfs_cat_file *file;
	int res;

	if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
		return -EOPNOTSUPP;

	res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
	if (res)
		return res;
	fd.search_key->cat = HFS_I(inode)->cat_key;
	res = hfs_brec_find(&fd);
	if (res)
		goto out;
	hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
			sizeof(struct hfs_cat_file));
	file = &rec.file;

	switch (type) {
	case HFS_TYPE:
		if (size == 4)
			memcpy(&file->UsrWds.fdType, value, 4);
		else
			res = -ERANGE;
		break;

	case HFS_CREATOR:
		if (size == 4)
			memcpy(&file->UsrWds.fdCreator, value, 4);
		else
			res = -ERANGE;
		break;
	}

	if (!res)
		hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
				sizeof(struct hfs_cat_file));
out:
	hfs_find_exit(&fd);
	return res;
}
Esempio n. 21
0
ssize_t hfs_getxattr(struct dentry *dentry, const char *name,
			 void *value, size_t size)
{
	struct inode *inode = dentry->d_inode;
	struct hfs_find_data fd;
	hfs_cat_rec rec;
	struct hfs_cat_file *file;
	ssize_t res = 0;

	if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
		return -EOPNOTSUPP;

	if (size) {
		res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
		if (res)
			return res;
		fd.search_key->cat = HFS_I(inode)->cat_key;
		res = hfs_brec_find(&fd);
		if (res)
			goto out;
		hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
				sizeof(struct hfs_cat_file));
	}
	file = &rec.file;

	if (!strcmp(name, "hfs.type")) {
		if (size >= 4) {
			memcpy(value, &file->UsrWds.fdType, 4);
			res = 4;
		} else
			res = size ? -ERANGE : 4;
	} else if (!strcmp(name, "hfs.creator")) {
		if (size >= 4) {
			memcpy(value, &file->UsrWds.fdCreator, 4);
			res = 4;
		} else
			res = size ? -ERANGE : 4;
	} else
		res = -ENODATA;
out:
	if (size)
		hfs_find_exit(&fd);
	return res;
}
Esempio n. 22
0
/*
 * hfs_cap_ifill()
 *
 * This function serves the same purpose as a read_inode() function does
 * in other filesystems.  It is called by __hfs_iget() to fill in
 * the missing fields of an uninitialized inode under the CAP scheme.
 */
void hfs_cap_ifill(struct inode * inode, ino_t type, const int version)
{
    struct hfs_cat_entry *entry = HFS_I(inode)->entry;

    HFS_I(inode)->d_drop_op = hfs_cap_drop_dentry;
    if (type == HFS_CAP_FNDR) {
        inode->i_size = sizeof(struct hfs_cap_info);
        inode->i_blocks = 0;
        inode->i_nlink = 1;
        inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG;
        inode->i_op = &hfs_cap_info_inode_operations;
        inode->i_fop = &hfs_cap_info_operations;
    } else if (entry->type == HFS_CDR_FIL) {
        init_file_inode(inode, (type == HFS_CAP_DATA) ?
                        HFS_FK_DATA : HFS_FK_RSRC);
        inode->i_op = &hfs_file_inode_operations;
        inode->i_fop = &hfs_file_operations;
        inode->i_mapping->a_ops = &hfs_aops;
        HFS_I(inode)->mmu_private = inode->i_size;
    } else { /* Directory */
        struct hfs_dir *hdir = &entry->u.dir;

        inode->i_blocks = 0;
        inode->i_size = hdir->files + hdir->dirs + 5;
        HFS_I(inode)->dir_size = 1;
        if (type == HFS_CAP_NDIR) {
            inode->i_mode = S_IRWXUGO | S_IFDIR;
            inode->i_nlink = hdir->dirs + 4;
            inode->i_op = &hfs_cap_ndir_inode_operations;
            inode->i_fop = &hfs_cap_dir_operations;
            HFS_I(inode)->file_type = HFS_CAP_NORM;
        } else if (type == HFS_CAP_FDIR) {
            inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
            inode->i_nlink = 2;
            inode->i_op = &hfs_cap_fdir_inode_operations;
            inode->i_fop = &hfs_cap_dir_operations;
            HFS_I(inode)->file_type = HFS_CAP_FNDR;
        } else if (type == HFS_CAP_RDIR) {
            inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
            inode->i_nlink = 2;
            inode->i_op = &hfs_cap_rdir_inode_operations;
            inode->i_fop = &hfs_cap_dir_operations;
            HFS_I(inode)->file_type = HFS_CAP_RSRC;
        }
    }
}
Esempio n. 23
0
int hfs_setxattr(struct dentry *dentry, const char *name,
		 const void *value, size_t size, int flags)
{
	struct inode *inode = dentry->d_inode;
	struct hfs_find_data fd;
	hfs_cat_rec rec;
	struct hfs_cat_file *file;
	int res;

	if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
		return -EOPNOTSUPP;

	res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
	if (res)
		return res;
	fd.search_key->cat = HFS_I(inode)->cat_key;
	res = hfs_brec_find(&fd);
	if (res)
		goto out;
	hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
			sizeof(struct hfs_cat_file));
	file = &rec.file;

	if (!strcmp(name, "hfs.type")) {
		if (size == 4)
			memcpy(&file->UsrWds.fdType, value, 4);
		else
			res = -ERANGE;
	} else if (!strcmp(name, "hfs.creator")) {
		if (size == 4)
			memcpy(&file->UsrWds.fdCreator, value, 4);
		else
			res = -ERANGE;
	} else
		res = -EOPNOTSUPP;
	if (!res)
		hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
				sizeof(struct hfs_cat_file));
out:
	hfs_find_exit(&fd);
	return res;
}
Esempio n. 24
0
/*
 * hfs_rename()
 *
 * This is the rename() entry in the inode_operations structure for
 * regular HFS directories.  The purpose is to rename an existing
 * file or directory, given the inode for the current directory and
 * the name (and its length) of the existing file/directory and the
 * inode for the new directory and the name (and its length) of the
 * new file/directory.
 * XXX: how do you handle must_be dir?
 */
int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
	       struct inode *new_dir, struct dentry *new_dentry)
{
	int res;

	/* Unlink destination if it already exists */
	if (new_dentry->d_inode) {
		res = hfs_unlink(new_dir, new_dentry);
		if (res)
			return res;
	}

	res = hfs_cat_move(old_dentry->d_inode->i_ino,
			   old_dir, &old_dentry->d_name,
			   new_dir, &new_dentry->d_name);
	if (!res)
		hfs_cat_build_key((btree_key *)&HFS_I(old_dentry->d_inode)->cat_key,
				  new_dir->i_ino, &new_dentry->d_name);
	return res;
}
Esempio n. 25
0
/*
 * update_dirs_plus()
 *
 * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
 * 'i_version' of the inodes associated with a directory that has
 * had a file ('is_dir'==0) or directory ('is_dir'!=0) added to it.
 */
static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir)
{
	int i;

	for (i = 0; i < 4; ++i) {
		struct inode *tmp = dir->sys_entry[i];
		if (tmp) {
			if (S_ISDIR(tmp->i_mode)) {
				if (is_dir &&
				    (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) {
					/* In "normal" directory only */
					++(tmp->i_nlink);
				}
				tmp->i_size += HFS_I(tmp)->dir_size;
				tmp->i_version = ++event;
			}
			tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
		}
	}
}
Esempio n. 26
0
/*
 * hfs_nat_ifill()
 *
 * This function serves the same purpose as a read_inode() function does
 * in other filesystems.  It is called by __hfs_iget() to fill in
 * the missing fields of an uninitialized inode under the Netatalk
 * scheme.
 */
void hfs_nat_ifill(struct inode * inode, ino_t type, const int version)
{
    struct hfs_cat_entry *entry = HFS_I(inode)->entry;

    HFS_I(inode)->d_drop_op = hfs_nat_drop_dentry;
    if (type == HFS_NAT_HDR) {
        if (entry->type == HFS_CDR_FIL) {
            init_file_inode(inode, HFS_FK_RSRC);
            inode->i_size += HFS_NAT_HDR_LEN;
        } else {
            inode->i_size = HFS_NAT_HDR_LEN;
            inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG;
            inode->i_nlink = 1;
        }
        inode->i_op = &hfs_hdr_inode_operations;
        inode->i_fop = &hfs_hdr_operations;
        HFS_I(inode)->default_layout = (version == 2) ?
                                       &hfs_nat2_hdr_layout : &hfs_nat_hdr_layout;
    } else if (entry->type == HFS_CDR_FIL) {
        init_file_inode(inode, HFS_FK_DATA);
        inode->i_op = &hfs_file_inode_operations;
        inode->i_fop = &hfs_file_operations;
        inode->i_mapping->a_ops = &hfs_aops;
        HFS_I(inode)->mmu_private = inode->i_size;
    } else { /* Directory */
        struct hfs_dir *hdir = &entry->u.dir;

        inode->i_blocks = 0;
        inode->i_size = hdir->files + hdir->dirs + 4;
        inode->i_mode = S_IRWXUGO | S_IFDIR;
        HFS_I(inode)->dir_size = 1;
        if (type == HFS_NAT_NDIR) {
            inode->i_nlink = hdir->dirs + 3;
            inode->i_op = &hfs_nat_ndir_inode_operations;
            HFS_I(inode)->file_type = HFS_NAT_NORM;
        } else if (type == HFS_NAT_HDIR) {
            inode->i_nlink = 2;
            inode->i_op = &hfs_nat_hdir_inode_operations;
            HFS_I(inode)->file_type = HFS_NAT_HDR;
        }
        inode->i_fop = &hfs_nat_dir_operations;
    }
}
Esempio n. 27
0
static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		      struct inode *new_dir, struct dentry *new_dentry)
{
	int res;

	
	if (new_dentry->d_inode) {
		res = hfs_remove(new_dir, new_dentry);
		if (res)
			return res;
	}

	res = hfs_cat_move(old_dentry->d_inode->i_ino,
			   old_dir, &old_dentry->d_name,
			   new_dir, &new_dentry->d_name);
	if (!res)
		hfs_cat_build_key(old_dir->i_sb,
				  (btree_key *)&HFS_I(old_dentry->d_inode)->cat_key,
				  new_dir->i_ino, &new_dentry->d_name);
	return res;
}
Esempio n. 28
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;
}
Esempio n. 29
0
/*
 * nat_rmdir()
 *
 * This is the rmdir() entry in the inode_operations structure for
 * Netatalk directories.  The purpose is to delete an existing
 * directory, given the inode for the parent directory and the name
 * (and its length) of the existing directory.
 *
 * We handle .AppleDouble and call hfs_rmdir() for all other cases.
 */
static int nat_rmdir(struct inode *parent, const char *name, int len)
{
	struct hfs_cat_entry *entry = HFS_I(parent)->entry;
	struct hfs_name cname;
	int error;

	hfs_nameout(parent, &cname, name, len);
	if (hfs_streq(&cname, DOT_APPLEDOUBLE)) {
		if (!HFS_SB(parent->i_sb)->s_afpd) {
			/* Not in AFPD compatibility mode */
			error = -EPERM;
		} else if (entry->u.dir.files || entry->u.dir.dirs) {
			/* AFPD compatible, but the directory is not empty */
			error = -ENOTEMPTY;
		} else {
			/* AFPD compatible, so pretend to succeed */
			error = 0;
		}
		iput(parent);
	} else {
		error = hfs_rmdir(parent, name, len);
	}
	return error;
}
Esempio n. 30
0
static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd)
{
	int res;

	hfs_ext_build_key(fd->search_key, inode->i_ino, HFS_I(inode)->cached_start,
			  HFS_IS_RSRC(inode) ?  HFS_FK_RSRC : HFS_FK_DATA);
	res = hfs_brec_find(fd);
	if (HFS_I(inode)->flags & HFS_FLG_EXT_NEW) {
		if (res != -ENOENT)
			return;
		hfs_brec_insert(fd, HFS_I(inode)->cached_extents, sizeof(hfs_extent_rec));
		HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW);
	} else {
		if (res)
			return;
		hfs_bnode_write(fd->bnode, HFS_I(inode)->cached_extents, fd->entryoffset, fd->entrylength);
		HFS_I(inode)->flags &= ~HFS_FLG_EXT_DIRTY;
	}
}