コード例 #1
0
ファイル: onefs_dir.c プロジェクト: gojdic/samba
/**
 * Set the location of the next direntry to be read via onefs_readdir().
 *
 * This function should only pass in locations retrieved from onefs_telldir().
 *
 * Ideally the seek point will still be in the readdirplus cache, and we'll
 * just update our cursors.  If the seek location is outside of the current
 * cache we must do an expensive re-enumeration of the entire directory up
 * to the offset.
 *
 * @param[in] handle vfs handle given in most VFS calls
 * @param[in] dirp system DIR handle to set offset on
 * @param[in] offset from the start of the directory where the next read
 *	      will take place
 *
 * @return no return value
 */
void
onefs_seekdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, long offset)
{
	struct rdp_dir_state *dsp = NULL;
	bool same_as_last;
	bool outside_cache = false;
	int ret = -1, i;

	/* Fallback to default system routines if readdirplus is disabled */
	if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
	    PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
	{
		return sys_seekdir(dirp, offset);
	}

	/* Validate inputs */
	if (offset < 0) {
		DEBUG(1, ("Invalid offset %ld passed.\n", offset));
		return;
	}

	/* Retrieve state based off DIR handle */
	ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last);
	if (ret) {
		DEBUG(1, ("Could not retrieve dir_state struct for "
			 "SMB_STRUCT_DIR pointer.\n"));
		/* XXX: we can't return an error, should we ABORT rather than
		 * return without actually seeking? */
		return;
	}

	/* Short cut if no work needs to be done */
	if (offset == dsp->location)
		return;

	/* If DIR is different from last call, reset all buffers and cursors,
	 * and refill the global cache from the new DIR */
	if (!same_as_last) {
		ret = rdp_fill_cache(dsp);
		if (ret <= 0)
			goto out;
		DEBUG(8, ("Switched global rdp cache to new DIR entry.\n"));
	}

	/* Check if location is outside the currently cached entries */
	if (offset < dsp->location - dsp->stat_cursor) {
		/* offset is before the current cache */
		/* reset to the beginning of the directory */
		ret = rdp_init(dsp);
		if (ret) {
			DEBUG(0, ("Error initializing readdirplus() buffers: "
				 "%s\n", strerror(ret)));
			goto out;
		}
		outside_cache = true;
	} else if (offset >
	    dsp->location + (dsp->stat_count - 1 - dsp->stat_cursor))
	{
		/* offset is after the current cache
		 * advance the cookie to the end of the cache */
		dsp->resume_cookie = rdp_cookies[dsp->stat_count - 1];
		outside_cache = true;
	}

	if (outside_cache) {
		/* start reading from the directory, until we have the
		 * specified offset in our cache */
		do {
			dsp->location += dsp->stat_count - dsp->stat_cursor;
			ret = rdp_fill_cache(dsp);
			if (ret <= 0) {
				DEBUG(1, ("Error seeking to offset outside the "
					 "cached directory entries. Offset "
					 "%ld \n", dsp->location));
				goto out;
			}
			dsp->resume_cookie = rdp_cookies[dsp->stat_count - 1];
		} while (offset >= dsp->location + dsp->stat_count);
	}

	/* Location should be within the currently cached entries */
	if (offset < dsp->location &&
	    offset >= dsp->location - dsp->stat_cursor)
	{
		/* offset is within the current cache, before the cursor.
		 * update cursors to the new location */
		int new_cursor = dsp->stat_cursor - (dsp->location - offset);

		dsp->direntries_cursor = rdp_direntries;
		for (i=0; i < new_cursor; i++) {
			dsp->direntries_cursor +=
			    ((SMB_STRUCT_DIRENT *)
			     dsp->direntries_cursor)->d_reclen;
		}
		dsp->stat_cursor = new_cursor;
		dsp->resume_cookie = rdp_cookies[dsp->stat_cursor];
		dsp->location = offset;
	} else if (offset >= dsp->location &&
	   offset <= dsp->location + (dsp->stat_count - 1 - dsp->stat_cursor))
	{
		/* offset is within the current cache, at or after the cursor.
		 * update cursors to the new location */
		int add_to_cursor = offset - dsp->location - 1;

		for (i=0; i < add_to_cursor; i++) {
			dsp->direntries_cursor +=
			    ((SMB_STRUCT_DIRENT *)
			     dsp->direntries_cursor)->d_reclen;
		}
		dsp->stat_cursor += add_to_cursor;
		dsp->resume_cookie = rdp_cookies[dsp->stat_cursor];
		dsp->location = offset;
	}

	DEBUG(9, ("Seek DIR %p, location: %ld, cache cursor: %zu\n",
		 dsp->dirp, dsp->location, dsp->stat_cursor));

	/* FALLTHROUGH */
out:
	/* Set rdp_last_dirp at the end of every VFS call where the cache was
	 * reloaded */
	rdp_last_dirp = dirp;
	return;
}
コード例 #2
0
void vfswrap_seekdir(vfs_handle_struct *handle, connection_struct *conn, SMB_STRUCT_DIR *dirp, long offset)
{
	START_PROFILE(syscall_seekdir);
	sys_seekdir(dirp, offset);
	END_PROFILE(syscall_seekdir);
}
コード例 #3
0
ファイル: dir.c プロジェクト: WareX97/K2
int sys_rewinddir(DIR* d) {
	sys_seekdir(d, 0);
}