Beispiel #1
0
/**
 * Case insensitive sorting for directory entry names, so
 * that directory entries are listed first.
 */
static int filesort(const struct dirent **d1, const struct dirent **d2)
{
	const char *name1 = (*d1)->d_name;
	const char *name2 = (*d2)->d_name;
#ifndef HAVE_DIRENT_D_TYPE
	int type1 = DT_UNKNOWN;
	int type2 = DT_UNKNOWN;
#else
	int type1 = (*d1)->d_type;
	int type2 = (*d2)->d_type;
#endif

	/* OS / file system that doesn't support d_type field, or symlink */
	if (type1 == DT_UNKNOWN || type1 == DT_LNK)
		type1 = get_dtype(name1);
	if (type2 == DT_UNKNOWN || type2 == DT_LNK)
		type2 = get_dtype(name2);

	if (type1 == DT_DIR)
	{
		if (type2 != DT_DIR)
			return -1;
	} else if (type2 == DT_DIR)
	{
		if (type1 != DT_DIR)
			return 1;
	}
	return strcasecmp(name1, name2);
}
Beispiel #2
0
/* Scan the list and let the last match determine the fate.
 * Return 1 for exclude, 0 for include and -1 for undecided.
 */
int excluded_from_list(const char *pathname,
		       int pathlen, const char *basename, int *dtype,
		       struct exclude_list *el)
{
	int i;

	if (el->nr) {
		for (i = el->nr - 1; 0 <= i; i--) {
			struct exclude *x = el->excludes[i];
			const char *exclude = x->pattern;
			int to_exclude = x->to_exclude;

			if (x->flags & EXC_FLAG_MUSTBEDIR) {
				if (*dtype == DT_UNKNOWN)
					*dtype = get_dtype(NULL, pathname, pathlen);
				if (*dtype != DT_DIR)
					continue;
			}

			if (x->flags & EXC_FLAG_NODIR) {
				/* match basename */
				if (x->flags & EXC_FLAG_NOWILDCARD) {
					if (!strcmp_icase(exclude, basename))
						return to_exclude;
				} else if (x->flags & EXC_FLAG_ENDSWITH) {
					if (x->patternlen - 1 <= pathlen &&
					    !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1))
						return to_exclude;
				} else {
					if (fnmatch_icase(exclude, basename, 0) == 0)
						return to_exclude;
				}
			}
			else {
				/* match with FNM_PATHNAME:
				 * exclude has base (baselen long) implicitly
				 * in front of it.
				 */
				int baselen = x->baselen;
				if (*exclude == '/')
					exclude++;

				if (pathlen < baselen ||
				    (baselen && pathname[baselen-1] != '/') ||
				    strncmp_icase(pathname, x->base, baselen))
				    continue;

				if (x->flags & EXC_FLAG_NOWILDCARD) {
					if (!strcmp_icase(exclude, pathname + baselen))
						return to_exclude;
				} else {
					if (fnmatch_icase(exclude, pathname+baselen,
						    FNM_PATHNAME) == 0)
					    return to_exclude;
				}
			}
		}
	}
	return -1; /* undecided */
}
Beispiel #3
0
Datei: dir.c Projekt: B-Rich/git
static enum path_treatment treat_one_path(struct dir_struct *dir,
					  struct strbuf *path,
					  const struct path_simplify *simplify,
					  int dtype, struct dirent *de)
{
	int exclude;
	int has_path_in_index = !!cache_file_exists(path->buf, path->len, ignore_case);

	if (dtype == DT_UNKNOWN)
		dtype = get_dtype(de, path->buf, path->len);

	/* Always exclude indexed files */
	if (dtype != DT_DIR && has_path_in_index)
		return path_none;

	/*
	 * When we are looking at a directory P in the working tree,
	 * there are three cases:
	 *
	 * (1) P exists in the index.  Everything inside the directory P in
	 * the working tree needs to go when P is checked out from the
	 * index.
	 *
	 * (2) P does not exist in the index, but there is P/Q in the index.
	 * We know P will stay a directory when we check out the contents
	 * of the index, but we do not know yet if there is a directory
	 * P/Q in the working tree to be killed, so we need to recurse.
	 *
	 * (3) P does not exist in the index, and there is no P/Q in the index
	 * to require P to be a directory, either.  Only in this case, we
	 * know that everything inside P will not be killed without
	 * recursing.
	 */
	if ((dir->flags & DIR_COLLECT_KILLED_ONLY) &&
	    (dtype == DT_DIR) &&
	    !has_path_in_index &&
	    (directory_exists_in_index(path->buf, path->len) == index_nonexistent))
		return path_none;

	exclude = is_excluded(dir, path->buf, &dtype);

	/*
	 * Excluded? If we don't explicitly want to show
	 * ignored files, ignore it
	 */
	if (exclude && !(dir->flags & (DIR_SHOW_IGNORED|DIR_SHOW_IGNORED_TOO)))
		return path_excluded;

	switch (dtype) {
	default:
		return path_none;
	case DT_DIR:
		strbuf_addch(path, '/');
		return treat_directory(dir, path->buf, path->len, exclude,
			simplify);
	case DT_REG:
	case DT_LNK:
		return exclude ? path_excluded : path_untracked;
	}
}
Beispiel #4
0
static enum path_treatment treat_one_path(struct dir_struct *dir,
					  struct strbuf *path,
					  const struct path_simplify *simplify,
					  int dtype, struct dirent *de)
{
	int exclude;
	if (dtype == DT_UNKNOWN)
		dtype = get_dtype(de, path->buf, path->len);

	/* Always exclude indexed files */
	if (dtype != DT_DIR &&
	    cache_name_exists(path->buf, path->len, ignore_case))
		return path_none;

	exclude = is_excluded(dir, path->buf, &dtype);

	/*
	 * Excluded? If we don't explicitly want to show
	 * ignored files, ignore it
	 */
	if (exclude && !(dir->flags & (DIR_SHOW_IGNORED|DIR_SHOW_IGNORED_TOO)))
		return path_excluded;

	switch (dtype) {
	default:
		return path_none;
	case DT_DIR:
		strbuf_addch(path, '/');
		return treat_directory(dir, path->buf, path->len, exclude,
			simplify);
	case DT_REG:
	case DT_LNK:
		return exclude ? path_excluded : path_untracked;
	}
}
Beispiel #5
0
static enum path_treatment treat_one_path(struct dir_struct *dir,
					  char *path, int *len,
					  const struct path_simplify *simplify,
					  int dtype, struct dirent *de)
{
	int exclude = excluded(dir, path, &dtype);
	if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
	    && exclude_matches_pathspec(path, *len, simplify))
		dir_add_ignored(dir, path, *len);

	/*
	 * Excluded? If we don't explicitly want to show
	 * ignored files, ignore it
	 */
	if (exclude && !(dir->flags & DIR_SHOW_IGNORED))
		return path_ignored;

	if (dtype == DT_UNKNOWN)
		dtype = get_dtype(de, path, *len);

	/*
	 * Do we want to see just the ignored files?
	 * We still need to recurse into directories,
	 * even if we don't ignore them, since the
	 * directory may contain files that we do..
	 */
	if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) {
		if (dtype != DT_DIR)
			return path_ignored;
	}

	switch (dtype) {
	default:
		return path_ignored;
	case DT_DIR:
		memcpy(path + *len, "/", 2);
		(*len)++;
		switch (treat_directory(dir, path, *len, simplify)) {
		case show_directory:
			if (exclude != !!(dir->flags
					  & DIR_SHOW_IGNORED))
				return path_ignored;
			break;
		case recurse_into_directory:
			return path_recurse;
		case ignore_directory:
			return path_ignored;
		}
		break;
	case DT_REG:
	case DT_LNK:
		break;
	}
	return path_handled;
}
Beispiel #6
0
Datei: dir.c Projekt: B-Rich/git
/*
 * Scan the given exclude list in reverse to see whether pathname
 * should be ignored.  The first match (i.e. the last on the list), if
 * any, determines the fate.  Returns the exclude_list element which
 * matched, or NULL for undecided.
 */
static struct exclude *last_exclude_matching_from_list(const char *pathname,
						       int pathlen,
						       const char *basename,
						       int *dtype,
						       struct exclude_list *el)
{
	int i;

	if (!el->nr)
		return NULL;	/* undefined */

	for (i = el->nr - 1; 0 <= i; i--) {
		struct exclude *x = el->excludes[i];
		const char *exclude = x->pattern;
		int prefix = x->nowildcardlen;

		if (x->flags & EXC_FLAG_MUSTBEDIR) {
			if (*dtype == DT_UNKNOWN)
				*dtype = get_dtype(NULL, pathname, pathlen);
			if (*dtype != DT_DIR)
				continue;
		}

		if (x->flags & EXC_FLAG_NODIR) {
			if (match_basename(basename,
					   pathlen - (basename - pathname),
					   exclude, prefix, x->patternlen,
					   x->flags))
				return x;
			continue;
		}

		assert(x->baselen == 0 || x->base[x->baselen - 1] == '/');
		if (match_pathname(pathname, pathlen,
				   x->base, x->baselen ? x->baselen - 1 : 0,
				   exclude, prefix, x->patternlen, x->flags))
			return x;
	}
	return NULL; /* undecided */
}
Beispiel #7
0
/*
 * So this function is called when the volume is mkfsed with
 * dir_index disabled. In order to keep f_pos persistent
 * after we convert from an inlined dir to a blocked based,
 * we just pretend that we are a normal dir and return the
 * offset as if '.' and '..' really take place.
 *
 */
int ext4_read_inline_dir(struct file *file,
			 struct dir_context *ctx,
			 int *has_inline_data)
{
	unsigned int offset, parent_ino;
	int i;
	struct ext4_dir_entry_2 *de;
	struct super_block *sb;
	struct inode *inode = file_inode(file);
	int ret, inline_size = 0;
	struct ext4_iloc iloc;
	void *dir_buf = NULL;
	int dotdot_offset, dotdot_size, extra_offset, extra_size;

	ret = ext4_get_inode_loc(inode, &iloc);
	if (ret)
		return ret;

	down_read(&EXT4_I(inode)->xattr_sem);
	if (!ext4_has_inline_data(inode)) {
		up_read(&EXT4_I(inode)->xattr_sem);
		*has_inline_data = 0;
		goto out;
	}

	inline_size = ext4_get_inline_size(inode);
	dir_buf = kmalloc(inline_size, GFP_NOFS);
	if (!dir_buf) {
		ret = -ENOMEM;
		up_read(&EXT4_I(inode)->xattr_sem);
		goto out;
	}

	ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc);
	up_read(&EXT4_I(inode)->xattr_sem);
	if (ret < 0)
		goto out;

	ret = 0;
	sb = inode->i_sb;
	parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode);
	offset = ctx->pos;

	/*
	 * dotdot_offset and dotdot_size is the real offset and
	 * size for ".." and "." if the dir is block based while
	 * the real size for them are only EXT4_INLINE_DOTDOT_SIZE.
	 * So we will use extra_offset and extra_size to indicate them
	 * during the inline dir iteration.
	 */
	dotdot_offset = EXT4_DIR_REC_LEN(1);
	dotdot_size = dotdot_offset + EXT4_DIR_REC_LEN(2);
	extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE;
	extra_size = extra_offset + inline_size;

	/*
	 * If the version has changed since the last call to
	 * readdir(2), then we might be pointing to an invalid
	 * dirent right now.  Scan from the start of the inline
	 * dir to make sure.
	 */
	if (file->f_version != inode->i_version) {
		for (i = 0; i < extra_size && i < offset;) {
			/*
			 * "." is with offset 0 and
			 * ".." is dotdot_offset.
			 */
			if (!i) {
				i = dotdot_offset;
				continue;
			} else if (i == dotdot_offset) {
				i = dotdot_size;
				continue;
			}
			/* for other entry, the real offset in
			 * the buf has to be tuned accordingly.
			 */
			de = (struct ext4_dir_entry_2 *)
				(dir_buf + i - extra_offset);
			/* It's too expensive to do a full
			 * dirent test each time round this
			 * loop, but we do have to test at
			 * least that it is non-zero.  A
			 * failure will be detected in the
			 * dirent test below. */
			if (ext4_rec_len_from_disk(de->rec_len, extra_size)
				< EXT4_DIR_REC_LEN(1))
				break;
			i += ext4_rec_len_from_disk(de->rec_len,
						    extra_size);
		}
		offset = i;
		ctx->pos = offset;
		file->f_version = inode->i_version;
	}

	while (ctx->pos < extra_size) {
		if (ctx->pos == 0) {
			if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR))
				goto out;
			ctx->pos = dotdot_offset;
			continue;
		}

		if (ctx->pos == dotdot_offset) {
			if (!dir_emit(ctx, "..", 2, parent_ino, DT_DIR))
				goto out;
			ctx->pos = dotdot_size;
			continue;
		}

		de = (struct ext4_dir_entry_2 *)
			(dir_buf + ctx->pos - extra_offset);
		if (ext4_check_dir_entry(inode, file, de, iloc.bh, dir_buf,
					 extra_size, ctx->pos))
			goto out;
		if (le32_to_cpu(de->inode)) {
			if (!dir_emit(ctx, de->name, de->name_len,
				      le32_to_cpu(de->inode),
				      get_dtype(sb, de->file_type)))
				goto out;
		}
		ctx->pos += ext4_rec_len_from_disk(de->rec_len, extra_size);
	}
out:
	kfree(dir_buf);
	brelse(iloc.bh);
	return ret;
}
Beispiel #8
0
static int 
read_directory_recursive(struct dir_struct *dir,
                         const char *base, int baselen,
                         int check_only,
                         struct index_state *index,
                         const char *worktree,
                         IgnoreFunc ignore_func,
                         void *data)
{
    char *realpath = g_build_path (PATH_SEPERATOR, worktree, base, NULL);
    GDir *fdir = g_dir_open (realpath, 0, NULL);
    const char *dname;
    char *nfc_dname;
    int contents = 0;
    int dtype;

    if (fdir) {
        char path[SEAF_PATH_MAX + 1];
        memcpy(path, base, baselen);
        while ((dname = g_dir_read_name(fdir)) != NULL) {
            int len = 0;

#ifdef __APPLE__
            nfc_dname = g_utf8_normalize (dname, -1, G_NORMALIZE_NFC);
#else
            nfc_dname = g_strdup(dname);
#endif

            if (is_dot_or_dotdot(nfc_dname)) {
                g_free (nfc_dname);
                continue;
            }

            if (ignore_func (realpath, nfc_dname, data)) {
                g_free (nfc_dname);
                continue;
            }

            dtype = get_dtype(nfc_dname, realpath);
            switch (dtype) {
            case DT_REG:
                len = strlen(nfc_dname);
                memcpy(path + baselen, nfc_dname, len + 1);
                len = strlen(path);
                break;
            case DT_DIR:
                len = strlen(nfc_dname);
                memcpy(path + baselen, nfc_dname, len + 1);
                memcpy(path + baselen + len, "/", 2);
                len = strlen(path);
                read_directory_recursive(dir, path, len, 0,
                                         index, worktree, ignore_func, data);
                g_free (nfc_dname);
                continue;
            default: /* DT_UNKNOWN */
                len = 0;
                break;
            }
            if(len > 0)
                dir_add_name(dir, path, len, index);
            g_free (nfc_dname);
        }
        g_dir_close(fdir);
    }

    g_free(realpath);
    return contents;
}
Beispiel #9
0
Datei: dir.c Projekt: sirnot/git
/*
 * Read a directory tree. We currently ignore anything but
 * directories, regular files and symlinks. That's because git
 * doesn't handle them at all yet. Maybe that will change some
 * day.
 *
 * Also, we ignore the name ".git" (even if it is not a directory).
 * That likely will not change.
 */
static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
{
	DIR *fdir = opendir(path);
	int contents = 0;

	if (fdir) {
		struct dirent *de;
		char fullname[PATH_MAX + 1];
		memcpy(fullname, base, baselen);

		while ((de = readdir(fdir)) != NULL) {
			int len, dtype;
			int exclude;

			if (is_dot_or_dotdot(de->d_name) ||
			     !strcmp(de->d_name, ".git"))
				continue;
			len = strlen(de->d_name);
			/* Ignore overly long pathnames! */
			if (len + baselen + 8 > sizeof(fullname))
				continue;
			memcpy(fullname + baselen, de->d_name, len+1);
			if (simplify_away(fullname, baselen + len, simplify))
				continue;

			dtype = DTYPE(de);
			exclude = excluded(dir, fullname, &dtype);
			if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
			    && in_pathspec(fullname, baselen + len, simplify))
				dir_add_ignored(dir, fullname, baselen + len);

			/*
			 * Excluded? If we don't explicitly want to show
			 * ignored files, ignore it
			 */
			if (exclude && !(dir->flags & DIR_SHOW_IGNORED))
				continue;

			if (dtype == DT_UNKNOWN)
				dtype = get_dtype(de, fullname);

			/*
			 * Do we want to see just the ignored files?
			 * We still need to recurse into directories,
			 * even if we don't ignore them, since the
			 * directory may contain files that we do..
			 */
			if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) {
				if (dtype != DT_DIR)
					continue;
			}

			switch (dtype) {
			default:
				continue;
			case DT_DIR:
				memcpy(fullname + baselen + len, "/", 2);
				len++;
				switch (treat_directory(dir, fullname, baselen + len, simplify)) {
				case show_directory:
					if (exclude != !!(dir->flags
							& DIR_SHOW_IGNORED))
						continue;
					break;
				case recurse_into_directory:
					contents += read_directory_recursive(dir,
						fullname, fullname, baselen + len, 0, simplify);
					continue;
				case ignore_directory:
					continue;
				}
				break;
			case DT_REG:
			case DT_LNK:
				break;
			}
			contents++;
			if (check_only)
				goto exit_early;
			else
				dir_add_name(dir, fullname, baselen + len);
		}
exit_early:
		closedir(fdir);
	}

	return contents;
}
Beispiel #10
0
int ext4_read_inline_dir(struct file *filp,
			 void *dirent, filldir_t filldir,
			 int *has_inline_data)
{
	int error = 0;
	unsigned int offset, parent_ino;
	int i, stored;
	struct ext4_dir_entry_2 *de;
	struct super_block *sb;
	struct inode *inode = filp->f_path.dentry->d_inode;
	int ret, inline_size = 0;
	struct ext4_iloc iloc;
	void *dir_buf = NULL;

	ret = ext4_get_inode_loc(inode, &iloc);
	if (ret)
		return ret;

	down_read(&EXT4_I(inode)->xattr_sem);
	if (!ext4_has_inline_data(inode)) {
		up_read(&EXT4_I(inode)->xattr_sem);
		*has_inline_data = 0;
		goto out;
	}

	inline_size = ext4_get_inline_size(inode);
	dir_buf = kmalloc(inline_size, GFP_NOFS);
	if (!dir_buf) {
		ret = -ENOMEM;
		up_read(&EXT4_I(inode)->xattr_sem);
		goto out;
	}

	ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc);
	up_read(&EXT4_I(inode)->xattr_sem);
	if (ret < 0)
		goto out;

	sb = inode->i_sb;
	stored = 0;
	parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode);

	while (!error && !stored && filp->f_pos < inode->i_size) {
revalidate:
		/*
		 * If the version has changed since the last call to
		 * readdir(2), then we might be pointing to an invalid
		 * dirent right now.  Scan from the start of the inline
		 * dir to make sure.
		 */
		if (filp->f_version != inode->i_version) {
			for (i = 0;
			     i < inode->i_size && i < offset;) {
				if (!i) {
					/* skip "." and ".." if needed. */
					i += EXT4_INLINE_DOTDOT_SIZE;
					continue;
				}
				de = (struct ext4_dir_entry_2 *)
					(dir_buf + i);
				/* It's too expensive to do a full
				 * dirent test each time round this
				 * loop, but we do have to test at
				 * least that it is non-zero.  A
				 * failure will be detected in the
				 * dirent test below. */
				if (ext4_rec_len_from_disk(de->rec_len,
					inline_size) < EXT4_DIR_REC_LEN(1))
					break;
				i += ext4_rec_len_from_disk(de->rec_len,
							    inline_size);
			}
			offset = i;
			filp->f_pos = offset;
			filp->f_version = inode->i_version;
		}

		while (!error && filp->f_pos < inode->i_size) {
			if (filp->f_pos == 0) {
				error = filldir(dirent, ".", 1, 0, inode->i_ino,
						DT_DIR);
				if (error)
					break;
				stored++;

				error = filldir(dirent, "..", 2, 0, parent_ino,
						DT_DIR);
				if (error)
					break;
				stored++;

				filp->f_pos = offset = EXT4_INLINE_DOTDOT_SIZE;
				continue;
			}

			de = (struct ext4_dir_entry_2 *)(dir_buf + offset);
			if (ext4_check_dir_entry(inode, filp, de,
						 iloc.bh, dir_buf,
						 inline_size, offset)) {
				ret = stored;
				goto out;
			}
			offset += ext4_rec_len_from_disk(de->rec_len,
							 inline_size);
			if (le32_to_cpu(de->inode)) {
				/* We might block in the next section
				 * if the data destination is
				 * currently swapped out.  So, use a
				 * version stamp to detect whether or
				 * not the directory has been modified
				 * during the copy operation.
				 */
				u64 version = filp->f_version;

				error = filldir(dirent, de->name,
						de->name_len,
						filp->f_pos,
						le32_to_cpu(de->inode),
						get_dtype(sb, de->file_type));
				if (error)
					break;
				if (version != filp->f_version)
					goto revalidate;
				stored++;
			}
			filp->f_pos += ext4_rec_len_from_disk(de->rec_len,
							      inline_size);
		}
		offset = 0;
	}
out:
	kfree(dir_buf);
	brelse(iloc.bh);
	return ret;
}
Beispiel #11
0
    
    // Check that set offset works
    im2.set_offset(2.3);
    CHECK(im2.get_offset() == 2.3);
    
    // Check that scaling is correct
    CHECK(im.get_scaling() == 1.0);
    CHECK(im2.get_scaling() == 1.0);
    
    // Check that set scaling works
    im2.set_scaling(1.1);
    CHECK(im2.get_scaling() == 1.1);

    // CHECK that image dtype is correct
    CHECK(im.get_dtype() == mapnik::image_dtype_gray16);
    CHECK(im2.get_dtype() == mapnik::image_dtype_gray16);

    using pixel_type = mapnik::image_view_gray16::pixel_type;
    pixel_type expected_val;
    // Check that all data in the view is correct
    // IM
    expected_val = 0;
    pixel_type const* data_im = im.data();
    CHECK(*data_im == expected_val);
    unsigned char const* data_b = im.bytes();
    CHECK(*data_b == 0);
    for (std::size_t y = 0; y < im.height(); ++y)
    {
        std::size_t width = im.width();
        pixel_type const* data_1  = im.get_row(y);
        pixel_type const* data_2  = im.get_row(y, 1);
Beispiel #12
0
int ext4_read_inline_dir(struct file *filp,
			 void *dirent, filldir_t filldir)
{
	int error = 0;
	unsigned int offset;
	int i, stored;
	void *inline_pos;
	struct ext4_dir_entry_2 *de;
	struct super_block *sb;
	struct inode *inode = filp->f_path.dentry->d_inode;
	int ret, inline_size = 0;
	struct ext4_iloc iloc;

	ret = ext4_get_inode_loc(inode, &iloc);
	if (ret)
		return ret;

	down_read(&EXT4_I(inode)->xattr_sem);
	if (!ext4_has_inline_data(inode))
		goto out;

	sb = inode->i_sb;
	stored = 0;
	offset = filp->f_pos & (sb->s_blocksize - 1);

	while (!error && !stored && filp->f_pos < inode->i_size) {
revalidate:
		/* If the version has changed since the last call to
		 * readdir(2), then we might be pointing to an invalid
		 * dirent right now.  Scan from the start of the block
		 * to make sure. */
		if (filp->f_version != inode->i_version) {
			for (i = 0; i < inode->i_size && i < offset; ) {
				de = ext4_get_inline_entry(inode, &iloc, i,
							   NULL, &inline_size);
				/* It's too expensive to do a full
				 * dirent test each time round this
				 * loop, but we do have to test at
				 * least that it is non-zero.  A
				 * failure will be detected in the
				 * dirent test below. */
				if (ext4_rec_len_from_disk(de->rec_len,
					inline_size) < EXT4_DIR_REC_LEN(1))
					break;
				i += ext4_rec_len_from_disk(de->rec_len,
							    inline_size);
			}
			offset = i;
			filp->f_pos = offset;
			filp->f_version = inode->i_version;
		}

		while (!error && filp->f_pos < inode->i_size) {
			de = ext4_get_inline_entry(inode, &iloc, offset,
						   &inline_pos, &inline_size);
			if (ext4_check_dir_entry(__func__, inode, de,
						 iloc.bh, inline_pos,
						 inline_size, offset)) {
				ret = stored;
				goto out;
			}
			offset += ext4_rec_len_from_disk(de->rec_len,
							 inline_size);
			if (le32_to_cpu(de->inode)) {
				/* We might block in the next section
				 * if the data destination is
				 * currently swapped out.  So, use a
				 * version stamp to detect whether or
				 * not the directory has been modified
				 * during the copy operation.
				 */
				u64 version = filp->f_version;

				error = filldir(dirent, de->name,
						de->name_len,
						filp->f_pos,
						le32_to_cpu(de->inode),
						get_dtype(sb, de->file_type));
				if (error)
					break;
				if (version != filp->f_version)
					goto revalidate;
				stored++;
			}
			filp->f_pos += ext4_rec_len_from_disk(de->rec_len,
							      inline_size);
		}
		offset = 0;
	}
out:
	up_read(&EXT4_I(inode)->xattr_sem);
	brelse(iloc.bh);
	return ret;
}