Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
/*
 * cap_readdir()
 *
 * This is the readdir() entry in the file_operations structure for
 * HFS directories in the CAP scheme.  The purpose is to enumerate the
 * entries in a directory, given the inode of the directory and a
 * (struct file *), the 'f_pos' field of which indicates the location
 * in the directory.  The (struct file *) is updated so that the next
 * call with the same 'dir' and 'filp' arguments will produce the next
 * directory entry.  The entries are returned in 'dirent', which is
 * "filled-in" by calling filldir().  This allows the same readdir()
 * function be used for different dirent formats.  We try to read in
 * as many entries as we can before filldir() refuses to take any more.
 *
 * XXX: In the future it may be a good idea to consider not generating
 * metadata files for covered directories since the data doesn't
 * correspond to the mounted directory.	 However this requires an
 * iget() for every directory which could be considered an excessive
 * amount of overhead.	Since the inode for a mount point is always
 * in-core this is another argument for a call to get an inode if it
 * is in-core or NULL if it is not.
 */
static int cap_readdir(struct file * filp,
		       void * dirent, filldir_t filldir)
{
	ino_t type;
	int skip_dirs;
	struct hfs_brec brec;
        struct hfs_cat_entry *entry;
	struct inode *dir = filp->f_dentry->d_inode;

	entry = HFS_I(dir)->entry;
	type = HFS_ITYPE(dir->i_ino);
	skip_dirs = (type == HFS_CAP_RDIR);

	if (filp->f_pos == 0) {
		/* Entry 0 is for "." */
		if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino, DT_DIR)) {
			return 0;
		}
		filp->f_pos = 1;
	}

	if (filp->f_pos == 1) {
		/* Entry 1 is for ".." */
		hfs_u32 cnid;

		if (type == HFS_CAP_NDIR) {
			cnid = hfs_get_nl(entry->key.ParID);
		} else {
			cnid = entry->cnid;
		}

		if (filldir(dirent, DOT_DOT->Name,
			    DOT_DOT_LEN, 1, ntohl(cnid), DT_DIR)) {
			return 0;
		}
		filp->f_pos = 2;
	}

	if (filp->f_pos < (dir->i_size - 3)) {
		hfs_u32 cnid;
		hfs_u8 type;

	    	if (hfs_cat_open(entry, &brec) ||
	    	    hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) {
			return 0;
		}
		while (filp->f_pos < (dir->i_size - 3)) {
			if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) {
				return 0;
			}
			if (!skip_dirs || (type != HFS_CDR_DIR)) {
				ino_t ino;
				unsigned int len;
				unsigned char tmp_name[HFS_NAMEMAX];

				ino = ntohl(cnid) | HFS_I(dir)->file_type;
				len = hfs_namein(dir, tmp_name,
				    &((struct hfs_cat_key *)brec.key)->CName);
				if (filldir(dirent, tmp_name, len,
					    filp->f_pos, ino, DT_UNKNOWN)) {
					hfs_cat_close(entry, &brec);
					return 0;
				}
			}
			++filp->f_pos;
		}
		hfs_cat_close(entry, &brec);
	}

	if (filp->f_pos == (dir->i_size - 3)) {
		if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
		    (type == HFS_CAP_NDIR)) {
			/* In root dir last-2 entry is for ".rootinfo" */
			if (filldir(dirent, DOT_ROOTINFO->Name,
				    DOT_ROOTINFO_LEN, filp->f_pos,
				    ntohl(entry->cnid) | HFS_CAP_FNDR,
				    DT_UNKNOWN)) {
				return 0;
			}
		}
		++filp->f_pos;
	}

	if (filp->f_pos == (dir->i_size - 2)) {
		if (type == HFS_CAP_NDIR) {
			/* In normal dirs last-1 entry is for ".finderinfo" */
			if (filldir(dirent, DOT_FINDERINFO->Name,
				    DOT_FINDERINFO_LEN, filp->f_pos,
				    ntohl(entry->cnid) | HFS_CAP_FDIR,
				    DT_UNKNOWN)) {
				return 0;
			}
		}
		++filp->f_pos;
	}

	if (filp->f_pos == (dir->i_size - 1)) {
		if (type == HFS_CAP_NDIR) {
			/* In normal dirs last entry is for ".resource" */
			if (filldir(dirent, DOT_RESOURCE->Name,
				    DOT_RESOURCE_LEN, filp->f_pos,
				    ntohl(entry->cnid) | HFS_CAP_RDIR,
				    DT_UNKNOWN)) {
				return 0;
			}
		}
		++filp->f_pos;
	}

	return 0;
}
Ejemplo n.º 4
0
/*
 * 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;	
}
Ejemplo n.º 5
0
/*
 * nat_readdir()
 *
 * This is the readdir() entry in the file_operations structure for
 * HFS directories in the netatalk scheme.  The purpose is to
 * enumerate the entries in a directory, given the inode of the
 * directory and a struct file which indicates the location in the
 * directory.  The struct file is updated so that the next call with
 * the same dir and filp will produce the next directory entry.	 The
 * entries are returned in dirent, which is "filled-in" by calling
 * filldir().  This allows the same readdir() function be used for
 * different dirent formats.  We try to read in as many entries as we
 * can before filldir() refuses to take any more.
 *
 * Note that the Netatalk format doesn't have the problem with
 * metadata for covered directories that exists in the other formats,
 * since the metadata is contained within the directory.
 */
static int nat_readdir(struct inode * dir, struct file * filp,
		       void * dirent, filldir_t filldir)
{
	ino_t type;
	int skip_dirs;
	struct hfs_brec brec;
        struct hfs_cat_entry *entry;

	if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) {
		return -EBADF;
	}

        entry = HFS_I(dir)->entry;
	type = HFS_ITYPE(dir->i_ino);
	skip_dirs = (type == HFS_NAT_HDIR);

	if (filp->f_pos == 0) {
		/* Entry 0 is for "." */
		if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) {
			return 0;
		}
		filp->f_pos = 1;
	}

	if (filp->f_pos == 1) {
		/* Entry 1 is for ".." */
		hfs_u32 cnid;

		if (type == HFS_NAT_NDIR) {
			cnid = hfs_get_nl(entry->key.ParID);
		} else {
			cnid = entry->cnid;
		}

		if (filldir(dirent, DOT_DOT->Name,
			    DOT_DOT_LEN, 1, ntohl(cnid))) {
			return 0;
		}
		filp->f_pos = 2;
	}

	if (filp->f_pos < (dir->i_size - 1)) {
		hfs_u32 cnid;
		hfs_u8 type;

	    	if (hfs_cat_open(entry, &brec) ||
		    hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) {
			return 0;
		}
		while (filp->f_pos < (dir->i_size - 1)) {
			if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) {
				return 0;
			}
			if (!skip_dirs || (type != HFS_CDR_DIR)) {
				ino_t ino;
				unsigned int len;
				unsigned char tmp_name[HFS_NAMEMAX];

				ino = ntohl(cnid) | HFS_I(dir)->file_type;
				len = hfs_namein(dir, tmp_name,
				    &((struct hfs_cat_key *)brec.key)->CName);
				if (filldir(dirent, tmp_name, len,
					    filp->f_pos, ino)) {
					hfs_cat_close(entry, &brec);
					return 0;
				}
			}
			++filp->f_pos;
		}
		hfs_cat_close(entry, &brec);
	}

	if (filp->f_pos == (dir->i_size - 1)) {
		if (type == HFS_NAT_NDIR) {
			/* In normal dirs entry 2 is for ".AppleDouble" */
			if (filldir(dirent, DOT_APPLEDOUBLE->Name,
				    DOT_APPLEDOUBLE_LEN, filp->f_pos,
				    ntohl(entry->cnid) | HFS_NAT_HDIR)) {
				return 0;
			}
		} else if (type == HFS_NAT_HDIR) {
			/* In .AppleDouble entry 2 is for ".Parent" */
			if (filldir(dirent, DOT_PARENT->Name,
				    DOT_PARENT_LEN, filp->f_pos,
				    ntohl(entry->cnid) | HFS_NAT_HDR)) {
				return 0;
			}
		}
		++filp->f_pos;
	}

	return 0;
}
Ejemplo n.º 6
0
/*
 * nat_lookup()
 *
 * This is the lookup() entry in the inode_operations structure for
 * HFS directories in the Netatalk 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 int nat_lookup(struct inode * dir, const char * name,
		      int len, struct inode ** result)
{
	ino_t dtype;
	struct hfs_name cname;
	struct hfs_cat_entry *entry;
	struct hfs_cat_key key;
	struct inode *inode = NULL;

	if (!dir || !S_ISDIR(dir->i_mode)) {
		goto done;
	}

	entry = HFS_I(dir)->entry;
	dtype = HFS_ITYPE(dir->i_ino);

	if (len && !name) {
		*result = NULL;
		iput(dir);
		return -EINVAL;
	}

	/* Perform name-mangling */
	hfs_nameout(dir, &cname, name, len);

	/* Check for "." */
	if (hfs_streq(&cname, DOT)) {
		/* this little trick skips the iget and iput */
		*result = dir;
		return 0;
	}

	/* Check for "..". */
	if (hfs_streq(&cname, DOT_DOT)) {
		struct hfs_cat_entry *parent;

		if (dtype != HFS_NAT_NDIR) {
			/* Case for ".." in ".AppleDouble" */
			parent = entry;
			++entry->count; /* __hfs_iget() eats one */
		} else {
			/* Case for ".." in a normal directory */
			parent = hfs_cat_parent(entry);
		}
		inode = __hfs_iget(parent, HFS_NAT_NDIR, 0);
		goto done;
	}

	/* Check for ".AppleDouble" if in a normal directory,
	   and for ".Parent" in ".AppleDouble". */
	if (dtype==HFS_NAT_NDIR) {
		/* Check for ".AppleDouble" */
		if (hfs_streq(&cname, DOT_APPLEDOUBLE)) {
			++entry->count; /* __hfs_iget() eats one */
			inode = __hfs_iget(entry, HFS_NAT_HDIR, 1);
			goto done;
		}
	} else if (dtype==HFS_NAT_HDIR) {
		if (hfs_streq(&cname, DOT_PARENT)) {
			++entry->count; /* __hfs_iget() eats one */
			inode = __hfs_iget(entry, HFS_NAT_HDR, 0);
			goto done;
		}
	}

	/* Do an hfs_iget() on the mangled name. */
	hfs_cat_build_key(entry->cnid, &cname, &key);
	inode = hfs_iget(entry->mdb, &key, HFS_I(dir)->file_type);

	/* Don't return a header file for a directory other than .Parent */
	if (inode && (dtype == HFS_NAT_HDIR) &&
	    (HFS_I(inode)->entry != entry) &&
	    (HFS_I(inode)->entry->type == HFS_CDR_DIR)) {
		iput(inode);
		inode = NULL;
	}

done:
	iput(dir);
	*result = inode;
	return inode ? 0 : -ENOENT;
}