Beispiel #1
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;
}
Beispiel #2
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;
}