fresh git tree for public release
we regretfully had to remove our git history for licensing reasons Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
commit
0ad4db4fad
271 changed files with 71255 additions and 0 deletions
627
daemon/readdir.c
Normal file
627
daemon/readdir.c
Normal file
|
|
@ -0,0 +1,627 @@
|
|||
/* Copyright (c) 2010
|
||||
* The Regents of the University of Michigan
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Permission is granted to use, copy and redistribute this software
|
||||
* for noncommercial education and research purposes, so long as no
|
||||
* fee is charged, and so long as the name of the University of Michigan
|
||||
* is not used in any advertising or publicity pertaining to the use
|
||||
* or distribution of this software without specific, written prior
|
||||
* authorization. Permission to modify or otherwise create derivative
|
||||
* works of this software is not granted.
|
||||
*
|
||||
* This software is provided as is, without representation or warranty
|
||||
* of any kind either express or implied, including without limitation
|
||||
* the implied warranties of merchantability, fitness for a particular
|
||||
* purpose, or noninfringement. The Regents of the University of
|
||||
* Michigan shall not be liable for any damages, including special,
|
||||
* indirect, incidental, or consequential damages, with respect to any
|
||||
* claim arising out of or in connection with the use of the software,
|
||||
* even if it has been or is hereafter advised of the possibility of
|
||||
* such damages.
|
||||
*/
|
||||
|
||||
#include <Windows.h>
|
||||
#include <strsafe.h>
|
||||
#include <stdlib.h>
|
||||
#include "from_kernel.h"
|
||||
#include "nfs41_ops.h"
|
||||
#include "daemon_debug.h"
|
||||
#include "upcall.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
typedef union _FILE_DIR_INFO_UNION {
|
||||
ULONG NextEntryOffset;
|
||||
FILE_NAMES_INFORMATION fni;
|
||||
FILE_DIRECTORY_INFO fdi;
|
||||
FILE_FULL_DIR_INFO ffdi;
|
||||
FILE_ID_FULL_DIR_INFO fifdi;
|
||||
FILE_BOTH_DIR_INFORMATION fbdi;
|
||||
FILE_ID_BOTH_DIR_INFO fibdi;
|
||||
} FILE_DIR_INFO_UNION, *PFILE_DIR_INFO_UNION;
|
||||
|
||||
|
||||
/* NFS41_DIR_QUERY */
|
||||
int parse_readdir(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
|
||||
{
|
||||
int status;
|
||||
readdir_upcall_args *args = &upcall->args.readdir;
|
||||
|
||||
status = safe_read(&buffer, &length, &args->query_class, sizeof(args->query_class));
|
||||
if (status) goto out;
|
||||
status = safe_read(&buffer, &length, &args->buf_len, sizeof(args->buf_len));
|
||||
if (status) goto out;
|
||||
status = get_name(&buffer, &length, args->filter);
|
||||
if (status) goto out;
|
||||
status = safe_read(&buffer, &length, &args->initial, sizeof(args->initial));
|
||||
if (status) goto out;
|
||||
status = safe_read(&buffer, &length, &args->restart, sizeof(args->restart));
|
||||
if (status) goto out;
|
||||
status = safe_read(&buffer, &length, &args->single, sizeof(args->single));
|
||||
if (status) goto out;
|
||||
status = safe_read(&buffer, &length, &args->root, sizeof(args->root));
|
||||
if (status) goto out;
|
||||
status = safe_read(&buffer, &length, &args->state, sizeof(args->state));
|
||||
if (status) goto out;
|
||||
status = safe_read(&buffer, &length, &args->cookie, sizeof(args->cookie));
|
||||
if (status) goto out;
|
||||
if (args->cookie == INVALID_HANDLE_VALUE) {
|
||||
dprintf(1, "upcall passing empty cookie\n");
|
||||
args->cookie = NULL;
|
||||
}
|
||||
out:
|
||||
if (status)
|
||||
eprintf("parsing NFS41_DIR_QUERY failed with %d\n", status);
|
||||
else
|
||||
dprintf(1, "parsing NFS41_DIR_QUERY: info_class=%d buf_len=%d "
|
||||
"filter='%s'\n\tInitial\\Restart\\Single %d\\%d\\%d "
|
||||
"root=0x%p state=0x%p cookie=0x%p\n",
|
||||
args->query_class, args->buf_len, args->filter,
|
||||
args->initial, args->restart, args->single,
|
||||
args->root, args->state, args->cookie);
|
||||
return status;
|
||||
}
|
||||
|
||||
#define FILTER_STAR '*'
|
||||
#define FILTER_QM '>'
|
||||
|
||||
static __inline int readdir_has_wildcards(
|
||||
const char *filter)
|
||||
{
|
||||
return strchr(filter, FILTER_STAR) || strchr(filter, FILTER_QM);
|
||||
}
|
||||
|
||||
static __inline const char* skip_stars(
|
||||
const char *filter)
|
||||
{
|
||||
while (*filter == FILTER_STAR)
|
||||
filter++;
|
||||
return filter;
|
||||
}
|
||||
|
||||
static int readdir_filter(
|
||||
const char *filter,
|
||||
const char *name)
|
||||
{
|
||||
const char *f = filter, *n = name;
|
||||
|
||||
while (*f && *n) {
|
||||
if (*f == FILTER_STAR) {
|
||||
f = skip_stars(f);
|
||||
if (*f == '\0')
|
||||
return 1;
|
||||
while (*n && !readdir_filter(f, n))
|
||||
n++;
|
||||
} else if (*f == FILTER_QM || *f == *n) {
|
||||
f++;
|
||||
n++;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
return *f == *n || *skip_stars(f) == '\0';
|
||||
}
|
||||
|
||||
static uint32_t readdir_size_for_entry(
|
||||
IN int query_class,
|
||||
IN uint32_t wname_size)
|
||||
{
|
||||
uint32_t needed = wname_size;
|
||||
switch (query_class)
|
||||
{
|
||||
case FileDirectoryInformation:
|
||||
needed += FIELD_OFFSET(FILE_DIRECTORY_INFO, FileName);
|
||||
break;
|
||||
case FileIdFullDirectoryInformation:
|
||||
needed += FIELD_OFFSET(FILE_ID_FULL_DIR_INFO, FileName);
|
||||
break;
|
||||
case FileFullDirectoryInformation:
|
||||
needed += FIELD_OFFSET(FILE_FULL_DIR_INFO, FileName);
|
||||
break;
|
||||
case FileIdBothDirectoryInformation:
|
||||
needed += FIELD_OFFSET(FILE_ID_BOTH_DIR_INFO, FileName);
|
||||
break;
|
||||
case FileBothDirectoryInformation:
|
||||
needed += FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName);
|
||||
break;
|
||||
case FileNamesInformation:
|
||||
needed += FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName);
|
||||
break;
|
||||
default:
|
||||
eprintf("unhandled dir query class %d\n", query_class);
|
||||
return 0;
|
||||
}
|
||||
return needed;
|
||||
}
|
||||
|
||||
static void readdir_copy_dir_info(
|
||||
IN nfs41_readdir_entry *entry,
|
||||
IN PFILE_DIR_INFO_UNION info)
|
||||
{
|
||||
info->fdi.FileIndex = 0;
|
||||
nfs_time_to_file_time(&entry->attr_info.time_create,
|
||||
&info->fdi.CreationTime);
|
||||
nfs_time_to_file_time(&entry->attr_info.time_access,
|
||||
&info->fdi.LastAccessTime);
|
||||
nfs_time_to_file_time(&entry->attr_info.time_modify,
|
||||
&info->fdi.LastWriteTime);
|
||||
/* XXX: was using 'change' attr, but that wasn't giving a time */
|
||||
nfs_time_to_file_time(&entry->attr_info.time_modify,
|
||||
&info->fdi.ChangeTime);
|
||||
info->fdi.EndOfFile.QuadPart =
|
||||
info->fdi.AllocationSize.QuadPart =
|
||||
entry->attr_info.size;
|
||||
info->fdi.FileAttributes = nfs_file_info_to_attributes(
|
||||
&entry->attr_info);
|
||||
}
|
||||
|
||||
static void readdir_copy_shortname(
|
||||
IN LPCWSTR name,
|
||||
OUT LPWSTR name_out,
|
||||
OUT CCHAR *name_size_out)
|
||||
{
|
||||
/* GetShortPathName returns number of characters, not including \0 */
|
||||
*name_size_out = (CCHAR)GetShortPathNameW(name, name_out, 12);
|
||||
if (*name_size_out) {
|
||||
*name_size_out++;
|
||||
*name_size_out *= sizeof(WCHAR);
|
||||
}
|
||||
}
|
||||
|
||||
static void readdir_copy_full_dir_info(
|
||||
IN nfs41_readdir_entry *entry,
|
||||
IN PFILE_DIR_INFO_UNION info)
|
||||
{
|
||||
readdir_copy_dir_info(entry, info);
|
||||
info->fifdi.EaSize = 0;
|
||||
}
|
||||
|
||||
static void readdir_copy_both_dir_info(
|
||||
IN nfs41_readdir_entry *entry,
|
||||
IN LPWSTR wname,
|
||||
IN PFILE_DIR_INFO_UNION info)
|
||||
{
|
||||
readdir_copy_full_dir_info(entry, info);
|
||||
readdir_copy_shortname(wname, info->fbdi.ShortName,
|
||||
&info->fbdi.ShortNameLength);
|
||||
}
|
||||
|
||||
static void readdir_copy_filename(
|
||||
IN LPCWSTR name,
|
||||
IN uint32_t name_size,
|
||||
OUT LPWSTR name_out,
|
||||
OUT ULONG *name_size_out)
|
||||
{
|
||||
*name_size_out = name_size;
|
||||
memcpy(name_out, name, name_size);
|
||||
}
|
||||
|
||||
static int readdir_copy_entry(
|
||||
IN readdir_upcall_args *args,
|
||||
IN nfs41_readdir_entry *entry,
|
||||
IN OUT unsigned char **dst_pos,
|
||||
IN OUT uint32_t *dst_len)
|
||||
{
|
||||
int status = 0;
|
||||
WCHAR wname[NFS4_OPAQUE_LIMIT];
|
||||
uint32_t wname_len, wname_size, needed;
|
||||
PFILE_DIR_INFO_UNION info;
|
||||
|
||||
wname_len = MultiByteToWideChar(CP_UTF8, 0,
|
||||
entry->name, entry->name_len, wname, NFS4_OPAQUE_LIMIT);
|
||||
wname_size = (wname_len - 1) * sizeof(WCHAR);
|
||||
|
||||
needed = readdir_size_for_entry(args->query_class, wname_size);
|
||||
if (!needed || needed > *dst_len) {
|
||||
status = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
info = (PFILE_DIR_INFO_UNION)*dst_pos;
|
||||
info->NextEntryOffset = align8(needed);
|
||||
*dst_pos += info->NextEntryOffset;
|
||||
*dst_len -= info->NextEntryOffset;
|
||||
|
||||
switch (args->query_class)
|
||||
{
|
||||
case FileNamesInformation:
|
||||
info->fni.FileIndex = 0;
|
||||
readdir_copy_filename(wname, wname_size,
|
||||
info->fni.FileName, &info->fni.FileNameLength);
|
||||
break;
|
||||
case FileDirectoryInformation:
|
||||
readdir_copy_dir_info(entry, info);
|
||||
readdir_copy_filename(wname, wname_size,
|
||||
info->fdi.FileName, &info->fdi.FileNameLength);
|
||||
break;
|
||||
case FileFullDirectoryInformation:
|
||||
readdir_copy_full_dir_info(entry, info);
|
||||
readdir_copy_filename(wname, wname_size,
|
||||
info->ffdi.FileName, &info->ffdi.FileNameLength);
|
||||
break;
|
||||
case FileIdFullDirectoryInformation:
|
||||
readdir_copy_full_dir_info(entry, info);
|
||||
info->fibdi.FileId.QuadPart = (LONGLONG)entry->attr_info.fileid;
|
||||
readdir_copy_filename(wname, wname_size,
|
||||
info->fifdi.FileName, &info->fifdi.FileNameLength);
|
||||
break;
|
||||
case FileBothDirectoryInformation:
|
||||
readdir_copy_both_dir_info(entry, wname, info);
|
||||
readdir_copy_filename(wname, wname_size,
|
||||
info->fbdi.FileName, &info->fbdi.FileNameLength);
|
||||
break;
|
||||
case FileIdBothDirectoryInformation:
|
||||
readdir_copy_both_dir_info(entry, wname, info);
|
||||
info->fibdi.FileId.QuadPart = (LONGLONG)entry->attr_info.fileid;
|
||||
readdir_copy_filename(wname, wname_size,
|
||||
info->fibdi.FileName, &info->fibdi.FileNameLength);
|
||||
break;
|
||||
default:
|
||||
eprintf("unhandled dir query class %d\n", args->query_class);
|
||||
status = -1;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
#define COOKIE_DOT ((uint64_t)-2)
|
||||
#define COOKIE_DOTDOT ((uint64_t)-1)
|
||||
|
||||
int readdir_add_dots(
|
||||
IN readdir_upcall_args *args,
|
||||
IN OUT unsigned char *entry_buf,
|
||||
IN uint32_t entry_buf_len,
|
||||
OUT uint32_t *len_out,
|
||||
OUT uint32_t **last_offset)
|
||||
{
|
||||
int status = 0;
|
||||
const uint32_t entry_len = (uint32_t)FIELD_OFFSET(nfs41_readdir_entry, name);
|
||||
nfs41_readdir_entry *entry;
|
||||
nfs41_open_state *state = args->state;
|
||||
|
||||
*len_out = 0;
|
||||
*last_offset = NULL;
|
||||
switch (args->cookie->cookie) {
|
||||
case 0:
|
||||
if (entry_buf_len < entry_len + 2) {
|
||||
status = ERROR_BUFFER_OVERFLOW;
|
||||
dprintf(1, "not enough room for '.' entry.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
entry = (nfs41_readdir_entry*)entry_buf;
|
||||
ZeroMemory(&entry->attr_info, sizeof(nfs41_file_info));
|
||||
|
||||
status = nfs41_cached_getattr(state->session,
|
||||
&state->file, &entry->attr_info);
|
||||
if (status) {
|
||||
dprintf(1, "failed to add '.' entry.\n");
|
||||
goto out;
|
||||
}
|
||||
entry->cookie = COOKIE_DOT;
|
||||
entry->name_len = 2;
|
||||
StringCbCopyA(entry->name, entry->name_len, ".");
|
||||
entry->next_entry_offset = entry_len + entry->name_len;
|
||||
|
||||
entry_buf += entry->next_entry_offset;
|
||||
entry_buf_len -= entry->next_entry_offset;
|
||||
*len_out += entry->next_entry_offset;
|
||||
*last_offset = &entry->next_entry_offset;
|
||||
if (args->single)
|
||||
break;
|
||||
/* else no break! */
|
||||
case COOKIE_DOT:
|
||||
if (entry_buf_len < entry_len + 3) {
|
||||
status = ERROR_BUFFER_OVERFLOW;
|
||||
dprintf(1, "not enough room for '..' entry.\n");
|
||||
goto out;
|
||||
}
|
||||
/* XXX: this skips '..' when listing root fh */
|
||||
if (state->file.name.len == 0)
|
||||
break;
|
||||
|
||||
entry = (nfs41_readdir_entry*)entry_buf;
|
||||
ZeroMemory(&entry->attr_info, sizeof(nfs41_file_info));
|
||||
|
||||
status = nfs41_cached_getattr(state->session,
|
||||
&state->parent, &entry->attr_info);
|
||||
if (status) {
|
||||
status = ERROR_FILE_NOT_FOUND;
|
||||
dprintf(1, "failed to add '..' entry.\n");
|
||||
goto out;
|
||||
}
|
||||
entry->cookie = COOKIE_DOTDOT;
|
||||
entry->name_len = 3;
|
||||
StringCbCopyA(entry->name, entry->name_len, "..");
|
||||
entry->next_entry_offset = entry_len + entry->name_len;
|
||||
|
||||
entry_buf += entry->next_entry_offset;
|
||||
entry_buf_len -= entry->next_entry_offset;
|
||||
*len_out += entry->next_entry_offset;
|
||||
*last_offset = &entry->next_entry_offset;
|
||||
break;
|
||||
}
|
||||
if (args->cookie->cookie == COOKIE_DOTDOT ||
|
||||
args->cookie->cookie == COOKIE_DOT)
|
||||
ZeroMemory(args->cookie, sizeof(nfs41_readdir_cookie));
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int single_lookup(
|
||||
IN nfs41_root *root,
|
||||
IN nfs41_session *session,
|
||||
IN nfs41_path_fh *parent,
|
||||
IN const char *filter,
|
||||
IN bitmap4 *attr_request,
|
||||
OUT nfs41_readdir_entry *entry)
|
||||
{
|
||||
nfs41_abs_path path;
|
||||
nfs41_path_fh file;
|
||||
int status;
|
||||
|
||||
entry->cookie = 0;
|
||||
entry->name_len = (uint32_t)strlen(filter) + 1;
|
||||
StringCbCopyA(entry->name, entry->name_len, filter);
|
||||
entry->next_entry_offset = 0;
|
||||
|
||||
/* format an absolute path 'parent\filter' */
|
||||
InitializeSRWLock(&path.lock);
|
||||
abs_path_copy(&path, parent->path);
|
||||
if (path.len + entry->name_len >= NFS41_MAX_PATH_LEN) {
|
||||
status = ERROR_BUFFER_OVERFLOW;
|
||||
goto out;
|
||||
}
|
||||
StringCchPrintfA(path.path + path.len,
|
||||
NFS41_MAX_PATH_LEN - path.len, "\\%s", entry->name);
|
||||
path.len += (unsigned short)entry->name_len;
|
||||
|
||||
path_fh_init(&file, &path);
|
||||
|
||||
status = nfs41_lookup(root, session, &path,
|
||||
NULL, &file, &entry->attr_info, NULL);
|
||||
if (status) {
|
||||
dprintf(1, "nfs41_lookup failed with %s\n", nfs_error_string(status));
|
||||
status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
int handle_readdir(nfs41_upcall *upcall)
|
||||
{
|
||||
int status;
|
||||
readdir_upcall_args *args = &upcall->args.readdir;
|
||||
nfs41_open_state *state = args->state;
|
||||
unsigned char *entry_buf = NULL;
|
||||
uint32_t entry_buf_len;
|
||||
bitmap4 attr_request;
|
||||
bool_t eof;
|
||||
|
||||
dprintf(1, "-> handle_nfs41_dirquery(%s,%d,%d,%d)\n",
|
||||
args->filter, args->initial, args->restart, args->single);
|
||||
|
||||
args->buf = NULL;
|
||||
args->query_reply_len = 0;
|
||||
|
||||
if (args->cookie) { /* cookie exists */
|
||||
if (args->restart) {
|
||||
dprintf(1, "restarting; clearing previous cookie (%d %p)\n",
|
||||
args->cookie->cookie, args->cookie);
|
||||
ZeroMemory(args->cookie, sizeof(nfs41_readdir_cookie));
|
||||
} else if (args->initial) { /* shouldn't happen */
|
||||
dprintf(1, "*** initial; clearing previous cookie (%d %p)!\n",
|
||||
args->cookie->cookie, args->cookie);
|
||||
ZeroMemory(args->cookie, sizeof(nfs41_readdir_cookie));
|
||||
} else
|
||||
dprintf(1, "resuming enumeration with cookie %d.\n",
|
||||
args->cookie->cookie);
|
||||
} else { /* cookie is null */
|
||||
if (args->initial || args->restart) {
|
||||
dprintf(1, "allocating memory for the 1st readdir cookie\n");
|
||||
args->cookie = calloc(1, sizeof(nfs41_readdir_cookie));
|
||||
if (args->cookie == NULL) {
|
||||
status = GetLastError();
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
dprintf(1, "handle_nfs41_readdir: EOF\n");
|
||||
status = ERROR_NO_MORE_FILES;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
entry_buf = malloc(args->buf_len);
|
||||
if (entry_buf == NULL) {
|
||||
status = GetLastError();
|
||||
goto out_free_cookie;
|
||||
}
|
||||
fetch_entries:
|
||||
entry_buf_len = args->buf_len;
|
||||
|
||||
init_getattr_request(&attr_request);
|
||||
attr_request.arr[0] |= FATTR4_WORD0_RDATTR_ERROR;
|
||||
|
||||
if (readdir_has_wildcards((const char*)args->filter)) {
|
||||
/* use READDIR for wildcards */
|
||||
|
||||
uint32_t dots_len = 0;
|
||||
uint32_t *dots_next_offset = NULL;
|
||||
|
||||
if (args->filter[0] == '*' && args->filter[1] == '\0') {
|
||||
status = readdir_add_dots(args, entry_buf,
|
||||
entry_buf_len, &dots_len, &dots_next_offset);
|
||||
if (status)
|
||||
goto out_free_cookie;
|
||||
entry_buf_len -= dots_len;
|
||||
}
|
||||
|
||||
if (dots_len && args->single) {
|
||||
dprintf(2, "skipping nfs41_readdir because the single query "
|
||||
"will use . or ..\n");
|
||||
entry_buf_len = 0;
|
||||
eof = 0;
|
||||
} else {
|
||||
dprintf(2, "calling nfs41_readdir with cookie %d %p \n",
|
||||
args->cookie->cookie, args->cookie);
|
||||
status = nfs41_readdir(state->session, &state->file,
|
||||
&attr_request, args->cookie, entry_buf + dots_len,
|
||||
&entry_buf_len, &eof);
|
||||
if (status) {
|
||||
dprintf(1, "nfs41_readdir failed with %s\n",
|
||||
nfs_error_string(status));
|
||||
status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
|
||||
goto out_free_cookie;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry_buf_len && dots_next_offset)
|
||||
*dots_next_offset = 0;
|
||||
entry_buf_len += dots_len;
|
||||
} else {
|
||||
/* use LOOKUP for single files */
|
||||
nfs41_readdir_entry *entry = (nfs41_readdir_entry*)entry_buf;
|
||||
entry->cookie = 0;
|
||||
entry->name_len = (uint32_t)strlen(args->filter) + 1;
|
||||
StringCbCopyA(entry->name, entry->name_len, args->filter);
|
||||
entry->next_entry_offset = 0;
|
||||
|
||||
status = single_lookup(args->root, state->session,
|
||||
&state->file, args->filter, &attr_request, entry);
|
||||
if (status) {
|
||||
dprintf(1, "single_lookup failed with %d\n", status);
|
||||
goto out_free_cookie;
|
||||
}
|
||||
entry_buf_len = entry->name_len +
|
||||
FIELD_OFFSET(nfs41_readdir_entry, name);
|
||||
|
||||
eof = 1;
|
||||
}
|
||||
|
||||
status = args->initial ? ERROR_FILE_NOT_FOUND : ERROR_NO_MORE_FILES;
|
||||
|
||||
if (entry_buf_len) {
|
||||
unsigned char *entry_pos = entry_buf;
|
||||
unsigned char *dst_pos;
|
||||
uint32_t dst_len = args->buf_len;
|
||||
nfs41_readdir_entry *entry;
|
||||
PULONG offset, last_offset = NULL;
|
||||
|
||||
if (args->buf == NULL) {
|
||||
args->buf = malloc(args->buf_len);
|
||||
if (args->buf == NULL) {
|
||||
status = GetLastError();
|
||||
goto out_free_cookie;
|
||||
}
|
||||
}
|
||||
dst_pos = args->buf;
|
||||
|
||||
for (;;) {
|
||||
entry = (nfs41_readdir_entry*)entry_pos;
|
||||
offset = (PULONG)dst_pos; /* ULONG NextEntryOffset */
|
||||
|
||||
dprintf(2, "filter %s looking at %s with cookie %d\n",
|
||||
args->filter, entry->name, entry->cookie);
|
||||
if (readdir_filter((const char*)args->filter, entry->name)) {
|
||||
if (readdir_copy_entry(args, entry, &dst_pos, &dst_len)) {
|
||||
eof = 0;
|
||||
dprintf(2, "not enough space to copy entry %s (cookie %d)\n",
|
||||
entry->name, entry->cookie);
|
||||
break;
|
||||
}
|
||||
last_offset = offset;
|
||||
status = NO_ERROR;
|
||||
}
|
||||
args->cookie->cookie = entry->cookie;
|
||||
|
||||
/* last entry we got from the server */
|
||||
if (!entry->next_entry_offset)
|
||||
break;
|
||||
|
||||
/* we found our single entry, but the server has more */
|
||||
if (args->single && last_offset) {
|
||||
eof = 0;
|
||||
break;
|
||||
}
|
||||
entry_pos += entry->next_entry_offset;
|
||||
}
|
||||
args->query_reply_len = args->buf_len - dst_len;
|
||||
if (last_offset) {
|
||||
*last_offset = 0;
|
||||
} else if (!eof) {
|
||||
dprintf(1, "no entries matched; fetch more\n");
|
||||
goto fetch_entries;
|
||||
}
|
||||
}
|
||||
|
||||
if (eof) {
|
||||
dprintf(1, "we don't need to save a cookie\n");
|
||||
goto out_free_cookie;
|
||||
} else
|
||||
dprintf(1, "saving cookie %d %p\n", args->cookie->cookie, args->cookie);
|
||||
|
||||
out_free_entry:
|
||||
free(entry_buf);
|
||||
out:
|
||||
dprintf(1, "<- handle_nfs41_dirquery(%s,%d,%d,%d) returning ",
|
||||
args->filter, args->initial, args->restart, args->single);
|
||||
if (status) {
|
||||
switch (status) {
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
dprintf(1, "ERROR_FILE_NOT_FOUND.\n");
|
||||
break;
|
||||
case ERROR_NO_MORE_FILES:
|
||||
dprintf(1, "ERROR_NO_MORE_FILES.\n");
|
||||
break;
|
||||
default:
|
||||
dprintf(1, "error code %d.\n", status);
|
||||
break;
|
||||
}
|
||||
free(args->buf);
|
||||
args->buf = NULL;
|
||||
} else {
|
||||
dprintf(1, "success!\n");
|
||||
}
|
||||
return status;
|
||||
out_free_cookie:
|
||||
free(args->cookie);
|
||||
args->cookie = NULL;
|
||||
goto out_free_entry;
|
||||
}
|
||||
|
||||
int marshall_readdir(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall)
|
||||
{
|
||||
int status;
|
||||
readdir_upcall_args *args = &upcall->args.readdir;
|
||||
|
||||
status = safe_write(&buffer, length, &args->query_reply_len, sizeof(args->query_reply_len));
|
||||
if (status) goto out;
|
||||
status = safe_write(&buffer, length, args->buf, args->query_reply_len);
|
||||
if (status) goto out;
|
||||
status = safe_write(&buffer, length, &args->cookie, sizeof(args->cookie));
|
||||
out:
|
||||
free(args->buf);
|
||||
return status;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue