first draft of named attributes

This commit is contained in:
Olga Kornievskaia 2011-09-22 14:56:11 -04:00
parent 1c5935865b
commit 6eea9faa2e
11 changed files with 572 additions and 89 deletions

View file

@ -298,6 +298,7 @@ const char* opcode2string(DWORD opcode)
case NFS41_FILE_QUERY: return "NFS41_FILE_QUERY"; case NFS41_FILE_QUERY: return "NFS41_FILE_QUERY";
case NFS41_FILE_SET: return "NFS41_FILE_SET"; case NFS41_FILE_SET: return "NFS41_FILE_SET";
case NFS41_EA_SET: return "NFS41_EA_SET"; case NFS41_EA_SET: return "NFS41_EA_SET";
case NFS41_EA_GET: return "NFS41_EA_GET";
case NFS41_SYMLINK: return "NFS41_SYMLINK"; case NFS41_SYMLINK: return "NFS41_SYMLINK";
case NFS41_VOLUME_QUERY: return "NFS41_VOLUME_QUERY"; case NFS41_VOLUME_QUERY: return "NFS41_VOLUME_QUERY";
case NFS41_ACL_QUERY: return "NFS41_ACL_QUERY"; case NFS41_ACL_QUERY: return "NFS41_ACL_QUERY";

View file

@ -195,6 +195,20 @@ typedef struct _FILE_LINK_INFORMATION {
WCHAR FileName[1]; WCHAR FileName[1];
} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION; } FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;
typedef struct _FILE_FULL_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR Flags;
UCHAR EaNameLength;
USHORT EaValueLength;
CHAR EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
typedef struct _FILE_GET_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR EaNameLength;
CHAR EaName[1];
} FILE_GET_EA_INFORMATION, *PFILE_GET_EA_INFORMATION;
/* wdm.h */ /* wdm.h */
typedef enum _FSINFOCLASS { typedef enum _FSINFOCLASS {
FileFsVolumeInformation = 1, FileFsVolumeInformation = 1,

View file

@ -26,7 +26,9 @@
#include <Windows.h> #include <Windows.h>
#include <stdio.h> #include <stdio.h>
#include <strsafe.h>
#include "from_kernel.h" #include "from_kernel.h"
#include "delegation.h"
#include "daemon_debug.h" #include "daemon_debug.h"
#include "nfs41_ops.h" #include "nfs41_ops.h"
#include "name_cache.h" #include "name_cache.h"
@ -167,8 +169,189 @@ out:
} }
static int parse_getexattr(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
{
int status;
getexattr_upcall_args *args = &upcall->args.getexattr;
status = get_name(&buffer, &length, &args->path);
if (status) goto out;
status = safe_read(&buffer, &length, &args->eaindex, sizeof(args->eaindex));
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->ealist_len, sizeof(args->ealist_len));
if (status) goto out;
args->ealist = buffer;
dprintf(1, "parsing NFS41_EA_QUERY: buf_len=%d Initial %d Restart %d "
"Single %d\n", args->buf_len,args->eaindex, args->restart, args->single);
out:
return status;
}
static int marshall_getexattr(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall)
{
int status = NO_ERROR;
getexattr_upcall_args *args = &upcall->args.getexattr;
uint32_t len = args->buf_len;
status = safe_write(&buffer, length, &len, sizeof(len));
if (status) goto out;
status = safe_write(&buffer, length, args->buf, len);
if (status) goto out;
out:
free(args->buf);
return status;
}
static int handle_getexattr(nfs41_upcall *upcall)
{
int status = 0;
getexattr_upcall_args *args = &upcall->args.getexattr;
PFILE_GET_EA_INFORMATION gea =
(PFILE_GET_EA_INFORMATION)args->ealist, prev = NULL;
PFILE_FULL_EA_INFORMATION eainfo, entry_pos;
unsigned char *entry_buf, buf[NFS4_EASIZE] = { 0 };
nfs41_open_state *state = upcall->state_ref;
nfs41_path_fh parent, file;
open_claim4 claim;
stateid4 open_stateid;
stateid_arg stateid;
nfs41_component dst_name;
open_delegation4 delegation = { 0 };
bool_t eof;
uint32_t bytes_read = 0;
ULONG buflen = 0, needed = 0;
status = nfs41_rpc_openattr(state->session, &state->file, FALSE, &parent.fh);
if (status){
dprintf(1, "nfs41_rpc_openattr() failed with error %s.\n",
nfs_error_string(status));
status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED);
goto out;
}
entry_buf = malloc(UPCALL_BUF_SIZE);
if (entry_buf == NULL) {
status = GetLastError();
goto out;
}
entry_pos = eainfo = (PFILE_FULL_EA_INFORMATION)entry_buf;
while (gea != prev) {
dst_name.name = gea->EaName;
dst_name.len = gea->EaNameLength;
claim.claim = CLAIM_NULL;
claim.u.null.filename = &dst_name;
status = nfs41_open(state->session, &parent, &file, &state->owner,
&claim, OPEN4_SHARE_ACCESS_READ, OPEN4_SHARE_DENY_BOTH,
OPEN4_NOCREATE, UNCHECKED4, 0, TRUE, &open_stateid,
&delegation, NULL);
if (status) {
dprintf(1, "nfs41_open() failed with error %s.\n",
nfs_error_string(status));
status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED);
goto out_free;
}
stateid.stateid = open_stateid;
stateid.stateid.seqid = 0;
status = nfs41_read(state->session, &file, &stateid, 0, NFS4_EASIZE,
buf, &bytes_read, &eof);
if (status) {
dprintf(2, "nfs41_rpc_read EA attribute failed\n");
status = nfs_to_windows_error(status, ERROR_NET_WRITE_FAULT);
nfs41_close(state->session, &file, &stateid);
goto out_free;
}
if (eof) {
dprintf(1, "read thread reached eof: bytes_read %d\n", bytes_read);
eainfo->EaNameLength = gea->EaNameLength;
if (FAILED(StringCchCopy((LPSTR)eainfo->EaName, gea->EaNameLength + 1,
(LPCSTR)gea->EaName))) {
status = ERROR_BUFFER_OVERFLOW;
nfs41_close(state->session, &file, &stateid);
goto out_free;
}
if (FAILED(StringCchCopy((LPSTR)eainfo->EaName +
eainfo->EaNameLength + 1, bytes_read + 1, (LPCSTR)buf))) {
status = ERROR_BUFFER_OVERFLOW;
nfs41_close(state->session, &file, &stateid);
goto out_free;
}
memset(buf, 0, NFS4_EASIZE);
eainfo->EaValueLength = (USHORT) bytes_read;
needed = (eainfo->EaNameLength + eainfo->EaValueLength) +
FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName);
if (needed % 4)
needed = needed + (4 - (needed % 4));
eainfo->NextEntryOffset = needed;
eainfo->Flags = 0;
buflen = buflen + needed;
prev = gea;
if (gea->NextEntryOffset != 0) {
gea = (PFILE_GET_EA_INFORMATION)
((PBYTE) gea + gea->NextEntryOffset);
eainfo = (PFILE_FULL_EA_INFORMATION)
((PBYTE) eainfo + eainfo->NextEntryOffset);
}
status = nfs41_close(state->session, &file, &stateid);
if (status) {
dprintf(1, "nfs41_close() failed with error %s.\n",
nfs_error_string(status));
status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED);
goto out_free;
}
} else {
dprintf(2, "Size of the EA value is greater than %d\n", NFS4_EASIZE);
status = nfs41_close(state->session, &file, &stateid);
if (status) {
dprintf(1, "nfs41_rpc_openattr() failed with error %s.\n",
nfs_error_string(status));
status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED);
}
/* treating extended attribute values larger than NFS4_EASIZE as failure */
status = ERROR_INVALID_DATA;
goto out_free;
}
}
eainfo->NextEntryOffset = 0;
args->buf = (unsigned char *)entry_pos;
args->buf_len = buflen;
goto out;
out_free:
free(entry_buf);
out:
return status;
}
const nfs41_upcall_op nfs41_op_getattr = { const nfs41_upcall_op nfs41_op_getattr = {
parse_getattr, parse_getattr,
handle_getattr, handle_getattr,
marshall_getattr marshall_getattr
}; };
const nfs41_upcall_op nfs41_op_getexattr = {
parse_getexattr,
handle_getexattr,
marshall_getexattr
};

View file

@ -36,6 +36,9 @@
#define NFS4_OPAQUE_LIMIT 1024 #define NFS4_OPAQUE_LIMIT 1024
#define NFS4_SESSIONID_SIZE 16 #define NFS4_SESSIONID_SIZE 16
#define NFS4_STATEID_OTHER 12 #define NFS4_STATEID_OTHER 12
#define NFS4_EASIZE 256
#define NFS4_EANAME_SIZE 128
#define NFS41_MAX_FILEIO_SIZE (1024 * 1024) #define NFS41_MAX_FILEIO_SIZE (1024 * 1024)
#define NFS41_MAX_SERVER_CACHE 1024 #define NFS41_MAX_SERVER_CACHE 1024

View file

@ -507,6 +507,10 @@ int nfs41_open(
if (compound_error(status = compound.res.status)) if (compound_error(status = compound.res.status))
goto out; goto out;
if (dir_info.type == NF4ATTRDIR)
goto out;
/* fill in the file handle's fileid and superblock */ /* fill in the file handle's fileid and superblock */
file->fh.fileid = info->fileid; file->fh.fileid = info->fileid;
status = nfs41_superblock_for_fh(session, &info->fsid, &parent->fh, file); status = nfs41_superblock_for_fh(session, &info->fsid, &parent->fh, file);
@ -761,6 +765,10 @@ int nfs41_write(
eprintf("WRITE succeeded with count=0; returning %s\n", eprintf("WRITE succeeded with count=0; returning %s\n",
nfs_error_string(status)); nfs_error_string(status));
} }
if (info.type == NF4NAMEDATTR)
goto out;
nfs41_superblock_space_changed(file->fh.superblock); nfs41_superblock_space_changed(file->fh.superblock);
out: out:
return status; return status;

View file

@ -497,8 +497,13 @@ static int parse_setexattr(unsigned char *buffer, uint32_t length, nfs41_upcall
int status; int status;
setexattr_upcall_args *args = &upcall->args.setexattr; setexattr_upcall_args *args = &upcall->args.setexattr;
status = get_name(&buffer, &length, &args->path);
if (status) goto out;
status = safe_read(&buffer, &length, &args->mode, sizeof(args->mode)); status = safe_read(&buffer, &length, &args->mode, sizeof(args->mode));
if (status) goto out; if (status) goto out;
status = safe_read(&buffer, &length, &args->buf_len, sizeof(args->buf_len));
if (status) goto out;
args->buf = buffer;
dprintf(1, "parsing NFS41_EA_SET: mode=%o\n", args->mode); dprintf(1, "parsing NFS41_EA_SET: mode=%o\n", args->mode);
out: out:
@ -512,6 +517,16 @@ static int handle_setexattr(nfs41_upcall *upcall)
nfs41_open_state *state = upcall->state_ref; nfs41_open_state *state = upcall->state_ref;
stateid_arg stateid; stateid_arg stateid;
nfs41_file_info info = { 0 }; nfs41_file_info info = { 0 };
PFILE_FULL_EA_INFORMATION eainfo =
(PFILE_FULL_EA_INFORMATION)args->buf, prev = NULL;
nfs41_path_fh parent, file;
open_claim4 claim;
stateid4 open_stateid;
nfs41_component dst_name;
nfs41_write_verf verf;
uint32_t bytes_written;
UCHAR *buf;
open_delegation4 delegation = { 0 };
/* break read delegations before SETATTR */ /* break read delegations before SETATTR */
nfs41_delegation_return(state->session, &state->file, nfs41_delegation_return(state->session, &state->file,
@ -519,17 +534,80 @@ static int handle_setexattr(nfs41_upcall *upcall)
nfs41_open_stateid_arg(state, &stateid); nfs41_open_stateid_arg(state, &stateid);
/* mode */ if ((strncmp("NfsV3Attributes", eainfo->EaName, eainfo->EaNameLength) == 0 &&
info.mode = args->mode; strlen("NfsV3Attributes") == eainfo->EaNameLength) ||
info.attrmask.arr[1] |= FATTR4_WORD1_MODE; (strncmp("NfsActOnLink", eainfo->EaName, eainfo->EaNameLength)== 0 &&
info.attrmask.count = 2; strlen("NfsActOnLink") == eainfo->EaNameLength)) {
info.mode = args->mode;
info.attrmask.arr[1] |= FATTR4_WORD1_MODE;
info.attrmask.count = 2;
status = nfs41_setattr(state->session, &state->file, &stateid, &info);
if (status) {
dprintf(1, "nfs41_setattr() failed with error %s.\n",
nfs_error_string(status));
return nfs_to_windows_error(status, ERROR_NOT_SUPPORTED);
}
} else {
status = nfs41_rpc_openattr(state->session, &state->file, TRUE, &parent.fh);
if (status) {
dprintf(1, "handle_setexattr: nfs41_rpc_openattr() failed with error %s.\n",
nfs_error_string(status));
return nfs_to_windows_error(status, ERROR_NOT_SUPPORTED);
}
status = nfs41_setattr(state->session, &state->file, &stateid, &info); while (eainfo != prev) {
if (status) /* we don't allow for extended attribute values to be larger than NFS4_EASIZE.
dprintf(1, "nfs41_setattr() failed with error %s.\n", * thus, let's not allow setting such.
nfs_error_string(status)); */
if (eainfo->EaValueLength > NFS4_EASIZE) {
dprintf(1, "trying to write extended attribute value of size %d"
"max allowed %d\n", eainfo->EaValueLength, NFS4_EASIZE);
status = ERROR_INVALID_DATA;
goto out;
}
dst_name.name = eainfo->EaName;
dst_name.len = eainfo->EaNameLength;
claim.claim = CLAIM_NULL;
claim.u.null.filename = &dst_name;
status = nfs41_open(state->session, &parent, &file, &state->owner, &claim,
OPEN4_SHARE_ACCESS_WRITE, OPEN4_SHARE_DENY_BOTH, OPEN4_CREATE,
UNCHECKED4, 0664, TRUE, &open_stateid, &delegation, NULL);
if (status) {
dprintf(1, "handle_setexattr: nfs41_rpc_open() failed with error %s.\n",
nfs_error_string(status));
status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED);
goto out;
}
return nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); stateid.stateid = open_stateid;
stateid.stateid.seqid = 0;
buf = (UCHAR *) eainfo->EaName + eainfo->EaNameLength + 1;
status = nfs41_write(state->session, &file, &stateid, buf,
eainfo->EaValueLength, 0, FILE_SYNC4, &bytes_written, &verf);
if (status) {
dprintf(1, "handle_setexattr: nfs41_write() failed w/error %s.\n",
nfs_error_string(status));
status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED);
nfs41_close(state->session, &file, &stateid);
goto out;
}
status = nfs41_close(state->session, &file, &stateid);
if (status) {
dprintf(1, "handle_setexattr: nfs41_close() failed w/error %s.\n",
nfs_error_string(status));
status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED);
goto out;
}
bytes_written = 0;
prev = eainfo;
eainfo = (FILE_FULL_EA_INFORMATION *) ((ULONG_PTR) eainfo +
eainfo->NextEntryOffset);
}
}
out:
return status;
} }

View file

@ -42,6 +42,7 @@ extern const nfs41_upcall_op nfs41_op_unlock;
extern const nfs41_upcall_op nfs41_op_readdir; extern const nfs41_upcall_op nfs41_op_readdir;
extern const nfs41_upcall_op nfs41_op_getattr; extern const nfs41_upcall_op nfs41_op_getattr;
extern const nfs41_upcall_op nfs41_op_setattr; extern const nfs41_upcall_op nfs41_op_setattr;
extern const nfs41_upcall_op nfs41_op_getexattr;
extern const nfs41_upcall_op nfs41_op_setexattr; extern const nfs41_upcall_op nfs41_op_setexattr;
extern const nfs41_upcall_op nfs41_op_symlink; extern const nfs41_upcall_op nfs41_op_symlink;
extern const nfs41_upcall_op nfs41_op_volume; extern const nfs41_upcall_op nfs41_op_volume;
@ -60,6 +61,7 @@ static const nfs41_upcall_op *g_upcall_op_table[] = {
&nfs41_op_readdir, &nfs41_op_readdir,
&nfs41_op_getattr, &nfs41_op_getattr,
&nfs41_op_setattr, &nfs41_op_setattr,
&nfs41_op_getexattr,
&nfs41_op_setexattr, &nfs41_op_setexattr,
&nfs41_op_symlink, &nfs41_op_symlink,
&nfs41_op_volume, &nfs41_op_volume,

View file

@ -102,7 +102,22 @@ typedef struct __setattr_upcall_args {
int set_class; int set_class;
} setattr_upcall_args; } setattr_upcall_args;
typedef struct __getexattr_upcall_args {
const char *path;
unsigned char *buf;
uint32_t buf_len;
ULONG eaindex;
unsigned char *ealist;
uint32_t ealist_len;
BOOLEAN single;
BOOLEAN restart;
} getexattr_upcall_args;
typedef struct __setexattr_upcall_args { typedef struct __setexattr_upcall_args {
const char *path;
unsigned char *buf;
uint32_t buf_len;
uint32_t mode; uint32_t mode;
} setexattr_upcall_args; } setexattr_upcall_args;
@ -155,6 +170,7 @@ typedef union __upcall_args {
lock_upcall_args lock; lock_upcall_args lock;
unlock_upcall_args unlock; unlock_upcall_args unlock;
getattr_upcall_args getattr; getattr_upcall_args getattr;
getexattr_upcall_args getexattr;
setattr_upcall_args setattr; setattr_upcall_args setattr;
setexattr_upcall_args setexattr; setexattr_upcall_args setexattr;
readdir_upcall_args readdir; readdir_upcall_args readdir;

View file

@ -609,6 +609,7 @@ const char *opcode2string(int opcode)
case NFS41_FILE_QUERY: return "NFS41_FILE_QUERY"; case NFS41_FILE_QUERY: return "NFS41_FILE_QUERY";
case NFS41_FILE_SET: return "NFS41_FILE_SET"; case NFS41_FILE_SET: return "NFS41_FILE_SET";
case NFS41_EA_SET: return "NFS41_EA_SET"; case NFS41_EA_SET: return "NFS41_EA_SET";
case NFS41_EA_GET: return "NFS41_EA_GET";
case NFS41_SYMLINK: return "NFS41_SYMLINK"; case NFS41_SYMLINK: return "NFS41_SYMLINK";
case NFS41_VOLUME_QUERY: return "NFS41_VOLUME_QUERY"; case NFS41_VOLUME_QUERY: return "NFS41_VOLUME_QUERY";
case NFS41_ACL_QUERY: return "NFS41_ACL_QUERY"; case NFS41_ACL_QUERY: return "NFS41_ACL_QUERY";

View file

@ -45,7 +45,7 @@ typedef struct __nfs41_timings {
} nfs41_timings; } nfs41_timings;
nfs41_timings lookup, readdir, open, close, getattr, setattr, getacl, setacl, volume, nfs41_timings lookup, readdir, open, close, getattr, setattr, getacl, setacl, volume,
read, write, lock, unlock; read, write, lock, unlock, setexattr, getexattr;
#endif #endif
DRIVER_INITIALIZE DriverEntry; DRIVER_INITIALIZE DriverEntry;
DRIVER_UNLOAD nfs41_driver_unload; DRIVER_UNLOAD nfs41_driver_unload;
@ -194,8 +194,21 @@ typedef struct _updowncall_entry {
FILE_INFORMATION_CLASS InfoClass; FILE_INFORMATION_CLASS InfoClass;
} SetFile; } SetFile;
struct { struct {
PUNICODE_STRING filename;
PVOID buf;
ULONG buf_len;
DWORD mode; DWORD mode;
} SetEa; } SetEa;
struct {
PUNICODE_STRING filename;
PVOID buf;
ULONG buf_len;
PVOID EaList;
ULONG EaListLength;
ULONG EaIndex;
BOOLEAN ReturnSingleEntry;
BOOLEAN RestartScan;
} QueryEa;
struct { struct {
PUNICODE_STRING filename; PUNICODE_STRING filename;
PUNICODE_STRING target; PUNICODE_STRING target;
@ -940,22 +953,77 @@ NTSTATUS marshal_nfs41_easet(nfs41_updowncall_entry *entry,
goto out; goto out;
else else
tmp += *len; tmp += *len;
header_len = *len + sizeof(DWORD); header_len = *len + length_as_ansi(entry->u.SetEa.filename) +
sizeof(ULONG) + entry->u.SetEa.buf_len + sizeof(DWORD);
if (header_len > buf_len) { if (header_len > buf_len) {
status = STATUS_INSUFFICIENT_RESOURCES; status = STATUS_INSUFFICIENT_RESOURCES;
goto out; goto out;
} }
status = marshall_unicode_as_ansi(&tmp, entry->u.SetEa.filename);
if (status) goto out;
RtlCopyMemory(tmp, &entry->u.SetEa.mode, sizeof(DWORD)); RtlCopyMemory(tmp, &entry->u.SetEa.mode, sizeof(DWORD));
tmp += sizeof(DWORD);
RtlCopyMemory(tmp, &entry->u.SetEa.buf_len, sizeof(ULONG));
tmp += sizeof(ULONG);
RtlCopyMemory(tmp, entry->u.SetEa.buf, entry->u.SetEa.buf_len);
*len = header_len; *len = header_len;
DbgP("marshal_nfs41_easet: mode=0x%x\n", entry->u.SetEa.mode); DbgP("marshal_nfs41_easet: filename=%wZ, buflen=%d mode=0x%x\n",
entry->u.SetEa.filename, entry->u.SetEa.buf_len, entry->u.SetEa.mode);
out: out:
DbgEx(); DbgEx();
return status; return status;
} }
NTSTATUS marshal_nfs41_eaget(nfs41_updowncall_entry *entry,
unsigned char *buf,
ULONG buf_len,
ULONG *len)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG header_len = 0;
unsigned char *tmp = buf;
DbgEn();
status = marshal_nfs41_header(entry, tmp, buf_len, len);
if (status == STATUS_INSUFFICIENT_RESOURCES)
goto out;
else
tmp += *len;
header_len = *len + length_as_ansi(entry->u.QueryEa.filename) +
2 * sizeof(ULONG) + entry->u.QueryEa.EaListLength + 2 * sizeof(BOOLEAN);
if (header_len > buf_len) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto out;
}
status = marshall_unicode_as_ansi(&tmp, entry->u.QueryEa.filename);
if (status) goto out;
RtlCopyMemory(tmp, &entry->u.QueryEa.EaIndex, sizeof(ULONG));
tmp += sizeof(ULONG);
RtlCopyMemory(tmp, &entry->u.QueryEa.RestartScan, sizeof(BOOLEAN));
tmp += sizeof(BOOLEAN);
RtlCopyMemory(tmp, &entry->u.QueryEa.ReturnSingleEntry, sizeof(BOOLEAN));
tmp += sizeof(BOOLEAN);
RtlCopyMemory(tmp, &entry->u.QueryEa.EaListLength, sizeof(ULONG));
tmp += sizeof(ULONG);
RtlCopyMemory(tmp, entry->u.QueryEa.EaList, entry->u.QueryEa.EaListLength);
*len = header_len;
DbgP("marshal_nfs41_eaget: filename=%wZ, index=%d list_len=%d "
"rescan=%d single=%d\n", entry->u.QueryEa.filename,
entry->u.QueryEa.EaIndex, entry->u.QueryEa.EaListLength,
entry->u.QueryEa.RestartScan, entry->u.QueryEa.ReturnSingleEntry);
out:
DbgEx();
return status;
}
NTSTATUS marshal_nfs41_symlink(nfs41_updowncall_entry *entry, NTSTATUS marshal_nfs41_symlink(nfs41_updowncall_entry *entry,
unsigned char *buf, unsigned char *buf,
ULONG buf_len, ULONG buf_len,
@ -1178,6 +1246,9 @@ handle_upcall(
case NFS41_EA_SET: case NFS41_EA_SET:
status = marshal_nfs41_easet(entry, pbOut, cbOut, len); status = marshal_nfs41_easet(entry, pbOut, cbOut, len);
break; break;
case NFS41_EA_GET:
status = marshal_nfs41_eaget(entry, pbOut, cbOut, len);
break;
case NFS41_SYMLINK: case NFS41_SYMLINK:
status = marshal_nfs41_symlink(entry, pbOut, cbOut, len); status = marshal_nfs41_symlink(entry, pbOut, cbOut, len);
break; break;
@ -1508,6 +1579,17 @@ nfs41_downcall (
cur->u.QueryFile.buf_len = tmp->u.QueryFile.buf_len; cur->u.QueryFile.buf_len = tmp->u.QueryFile.buf_len;
RtlCopyMemory(cur->u.QueryFile.buf, buf, tmp->u.QueryFile.buf_len); RtlCopyMemory(cur->u.QueryFile.buf, buf, tmp->u.QueryFile.buf_len);
break; break;
case NFS41_EA_GET:
RtlCopyMemory(&tmp->u.QueryEa.buf_len, buf, sizeof(ULONG));
buf += sizeof(ULONG);
if (tmp->u.QueryEa.buf_len > cur->u.QueryEa.buf_len) {
cur->status = STATUS_BUFFER_TOO_SMALL;
cur->u.QueryEa.buf_len = tmp->u.QueryEa.buf_len;
break;
}
cur->u.QueryEa.buf_len = tmp->u.QueryEa.buf_len;
RtlCopyMemory(cur->u.QueryEa.buf, buf, tmp->u.QueryEa.buf_len);
break;
case NFS41_SYMLINK: case NFS41_SYMLINK:
if (cur->u.Symlink.set) if (cur->u.Symlink.set)
break; break;
@ -1826,7 +1908,7 @@ out:
#ifdef ENABLE_TIMINGS #ifdef ENABLE_TIMINGS
static void print_op_stat(const char *op_str, nfs41_timings *time, BOOLEAN clear) static void print_op_stat(const char *op_str, nfs41_timings *time, BOOLEAN clear)
{ {
DbgP("%-7s: num_ops=%-10d delta_ticks=%-10d size=%-10d\n", op_str, DbgP("%-9s: num_ops=%-10d delta_ticks=%-10d size=%-10d\n", op_str,
time->tops, time->tops ? time->ticks/time->tops : 0, time->tops, time->tops ? time->ticks/time->tops : 0,
time->sops ? time->size/time->sops : 0); time->sops ? time->size/time->sops : 0);
if (clear) { if (clear) {
@ -1862,6 +1944,8 @@ out:
print_op_stat("volume", &volume, 1); print_op_stat("volume", &volume, 1);
print_op_stat("getattr", &getattr, 1); print_op_stat("getattr", &getattr, 1);
print_op_stat("setattr", &setattr, 1); print_op_stat("setattr", &setattr, 1);
print_op_stat("getexattr", &getexattr, 1);
print_op_stat("setexattr", &setexattr, 1);
print_op_stat("readdir", &readdir, 1); print_op_stat("readdir", &readdir, 1);
print_op_stat("getacl", &getacl, 1); print_op_stat("getacl", &getacl, 1);
print_op_stat("setacl", &setacl, 1); print_op_stat("setacl", &setacl, 1);
@ -3611,72 +3695,6 @@ void create_nfs3_attrs(nfs3_attrs *attrs, PNFS41_FCB nfs41_fcb)
file_time_to_nfs_time(&nfs41_fcb->BasicInfo.CreationTime, &attrs->ctime); file_time_to_nfs_time(&nfs41_fcb->BasicInfo.CreationTime, &attrs->ctime);
} }
NTSTATUS nfs41_QueryEaInformation (
IN OUT PRX_CONTEXT RxContext)
{
NTSTATUS status = STATUS_EAS_NOT_SUPPORTED;
PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context;
PFILE_GET_EA_INFORMATION query = (PFILE_GET_EA_INFORMATION)
RxContext->CurrentIrpSp->Parameters.QueryEa.EaList;
PFILE_FULL_EA_INFORMATION info;
DbgEn();
print_debug_header(RxContext);
if (RxContext->CurrentIrpSp->Parameters.QueryEa.EaList) {
DbgP("Looking for a specific EA?\n");
print_get_ea(1, query);
if (AnsiStrEq(&NfsV3Attributes, query->EaName, query->EaNameLength)) {
nfs3_attrs attrs;
const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) +
NfsV3Attributes.Length + sizeof(nfs3_attrs) - sizeof(CHAR);
if (LengthRequired > RxContext->Info.LengthRemaining) {
status = STATUS_BUFFER_TOO_SMALL;
RxContext->InformationToReturn = LengthRequired;
goto out;
}
create_nfs3_attrs(&attrs, nfs41_fcb);
DbgP("returning fake v3attrs EA\n");
print_nfs3_attrs(&attrs);
info = RxContext->Info.Buffer;
info->NextEntryOffset = 0;
info->Flags = 0;
info->EaNameLength = (UCHAR)NfsV3Attributes.Length;
info->EaValueLength = sizeof(nfs3_attrs);
RtlCopyMemory(info->EaName, NfsV3Attributes.Buffer, NfsV3Attributes.Length);
RtlCopyMemory(info->EaName + info->EaNameLength + 1, &attrs,
sizeof(nfs3_attrs));
RxContext->Info.LengthRemaining = LengthRequired;
status = STATUS_SUCCESS;
} else if (AnsiStrEq(&NfsActOnLink, query->EaName, query->EaNameLength)
|| AnsiStrEq(&NfsSymlinkTargetName, query->EaName, query->EaNameLength)) {
const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) +
NfsActOnLink.Length - sizeof(CHAR);
if (LengthRequired > RxContext->Info.LengthRemaining) {
status = STATUS_BUFFER_TOO_SMALL;
RxContext->InformationToReturn = LengthRequired;
goto out;
}
DbgP("returning fake link EA\n");
info = RxContext->Info.Buffer;
info->NextEntryOffset = 0;
info->Flags = 0;
info->EaNameLength = (UCHAR)NfsActOnLink.Length;
info->EaValueLength = 0;
RtlCopyMemory(info->EaName, NfsActOnLink.Buffer, NfsActOnLink.Length);
RxContext->Info.LengthRemaining = LengthRequired;
status = STATUS_SUCCESS;
} else
print_error("Couldn't match %s\n", query->EaName);
}
out:
DbgEx();
return status;
}
static NTSTATUS map_setea_error(DWORD error) static NTSTATUS map_setea_error(DWORD error)
{ {
@ -3708,42 +3726,200 @@ NTSTATUS nfs41_SetEaInformation (
PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context; PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context;
PUNICODE_STRING FileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
PFILE_FULL_EA_INFORMATION eainfo = PFILE_FULL_EA_INFORMATION eainfo =
(PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer; (PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer;
nfs3_attrs *attrs = NULL; nfs3_attrs *attrs = NULL;
PNFS41_NETROOT_EXTENSION pNetRootContext = PNFS41_NETROOT_EXTENSION pNetRootContext =
NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot); NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
ULONG buflen = RxContext->CurrentIrpSp->Parameters.SetEa.Length, error_offset;
#ifdef ENABLE_TIMINGS
LARGE_INTEGER t1, t2;
t1 = KeQueryPerformanceCounter(NULL);
#endif
DbgEn(); DbgEn();
print_debug_header(RxContext); print_debug_header(RxContext);
print_ea_info(1, eainfo); print_ea_info(1, eainfo);
if (AnsiStrEq(&NfsV3Attributes, eainfo->EaName, eainfo->EaNameLength)) {
attrs = (nfs3_attrs *)(eainfo->EaName + eainfo->EaNameLength + 1);
print_nfs3_attrs(attrs);
DbgP("old mode is %x new mode is %x\n", nfs41_fcb->mode, attrs->mode);
nfs41_fcb->mode = attrs->mode;
} else
goto out;
status = nfs41_UpcallCreate(NFS41_EA_SET, &nfs41_fobx->sec_ctx, status = nfs41_UpcallCreate(NFS41_EA_SET, &nfs41_fobx->sec_ctx,
pVNetRootContext->session, nfs41_fobx->nfs41_open_state, pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
pNetRootContext->nfs41d_version, &entry); pNetRootContext->nfs41d_version, &entry);
if (status) if (status)
goto out; goto out;
entry->u.SetEa.mode = attrs->mode;
if (AnsiStrEq(&NfsV3Attributes, eainfo->EaName, eainfo->EaNameLength)) {
attrs = (nfs3_attrs *)(eainfo->EaName + eainfo->EaNameLength + 1);
print_nfs3_attrs(attrs);
DbgP("old mode is %o new mode is %o\n", nfs41_fcb->mode, attrs->mode);
entry->u.SetEa.mode = nfs41_fcb->mode = attrs->mode;
} else {
entry->u.SetEa.mode = 0;
status = IoCheckEaBufferValidity(eainfo, buflen, &error_offset);
if (status) {
RxFreePool(entry);
goto out;
}
}
entry->u.SetEa.buf = eainfo;
entry->u.SetEa.buf_len = buflen;
entry->u.SetEa.filename = FileName;
DbgP("FULL_EA_INFO: FileName=%wZ total_EA_len=%d EaNameLen=%d ExValueLen=%d\n",
entry->u.SetEa.filename, buflen, eainfo->EaNameLength,
eainfo->EaValueLength);
if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) {
status = STATUS_INTERNAL_ERROR; status = STATUS_INTERNAL_ERROR;
goto out; goto out;
} }
#ifdef ENABLE_TIMINGS
if (entry->status == STATUS_SUCCESS) {
InterlockedIncrement(&setexattr.sops);
InterlockedAdd64(&setexattr.size, entry->u.SetEa.buf_len);
}
#endif
status = map_setea_error(entry->status); status = map_setea_error(entry->status);
RxFreePool(entry); RxFreePool(entry);
out: out:
#ifdef ENABLE_TIMINGS
t2 = KeQueryPerformanceCounter(NULL);
InterlockedIncrement(&setexattr.tops);
InterlockedAdd64(&setexattr.ticks, t2.QuadPart - t1.QuadPart);
#ifdef ENABLE_INDV_TIMINGS
DbgP("nfs41_SetEaInformation delta = %d op=%d sum=%d\n",
t2.QuadPart - t1.QuadPart, setexattr.tops, setexattr.ticks);
#endif
#endif
DbgEx(); DbgEx();
return status; return status;
} }
NTSTATUS nfs41_QueryEaInformation (
IN OUT PRX_CONTEXT RxContext)
{
NTSTATUS status = STATUS_EAS_NOT_SUPPORTED;
PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context;
PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context;
__notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
PNFS41_NETROOT_EXTENSION pNetRootContext =
NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
PFILE_GET_EA_INFORMATION query = (PFILE_GET_EA_INFORMATION)
RxContext->CurrentIrpSp->Parameters.QueryEa.EaList;
PFILE_FULL_EA_INFORMATION info;
PUNICODE_STRING FileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
nfs41_updowncall_entry *entry;
ULONG buflen = RxContext->CurrentIrpSp->Parameters.QueryEa.Length;
#ifdef ENABLE_TIMINGS
LARGE_INTEGER t1, t2;
t1 = KeQueryPerformanceCounter(NULL);
#endif
DbgEn();
print_debug_header(RxContext);
if (RxContext->CurrentIrpSp->Parameters.QueryEa.EaList) {
DbgP("Looking for a specific EA?\n");
print_get_ea(1, query);
if (AnsiStrEq(&NfsV3Attributes, query->EaName, query->EaNameLength)) {
nfs3_attrs attrs;
const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) +
NfsV3Attributes.Length + sizeof(nfs3_attrs) - sizeof(CHAR);
if (LengthRequired > RxContext->Info.LengthRemaining) {
status = STATUS_BUFFER_TOO_SMALL;
RxContext->InformationToReturn = LengthRequired;
goto out;
}
create_nfs3_attrs(&attrs, nfs41_fcb);
DbgP("returning fake v3attrs EA\n");
print_nfs3_attrs(&attrs);
info = RxContext->Info.Buffer;
info->NextEntryOffset = 0;
info->Flags = 0;
info->EaNameLength = (UCHAR)NfsV3Attributes.Length;
info->EaValueLength = sizeof(nfs3_attrs);
RtlCopyMemory(info->EaName, NfsV3Attributes.Buffer, NfsV3Attributes.Length);
RtlCopyMemory(info->EaName + info->EaNameLength + 1, &attrs,
sizeof(nfs3_attrs));
RxContext->Info.LengthRemaining = LengthRequired;
status = STATUS_SUCCESS;
goto out;
}
if (AnsiStrEq(&NfsActOnLink, query->EaName, query->EaNameLength) ||
AnsiStrEq(&NfsSymlinkTargetName, query->EaName, query->EaNameLength)) {
const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) +
NfsActOnLink.Length - sizeof(CHAR);
if (LengthRequired > RxContext->Info.LengthRemaining) {
status = STATUS_BUFFER_TOO_SMALL;
RxContext->InformationToReturn = LengthRequired;
goto out;
}
DbgP("returning fake link EA\n");
info = RxContext->Info.Buffer;
info->NextEntryOffset = 0;
info->Flags = 0;
info->EaNameLength = (UCHAR)NfsActOnLink.Length;
info->EaValueLength = 0;
RtlCopyMemory(info->EaName, NfsActOnLink.Buffer, NfsActOnLink.Length);
RxContext->Info.LengthRemaining = LengthRequired;
status = STATUS_SUCCESS;
goto out;
}
status = nfs41_UpcallCreate(NFS41_EA_GET, &nfs41_fobx->sec_ctx,
pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
pNetRootContext->nfs41d_version, &entry);
if (status)
goto out;
entry->u.QueryEa.filename = FileName;
entry->u.QueryEa.buf_len = buflen;
entry->u.QueryEa.buf = RxContext->Info.Buffer;
entry->u.QueryEa.EaList = query;
entry->u.QueryEa.EaListLength = RxContext->QueryEa.UserEaListLength;
entry->u.QueryEa.EaIndex = RxContext->QueryEa.UserEaIndex;
entry->u.QueryEa.RestartScan = RxContext->QueryEa.RestartScan;
entry->u.QueryEa.ReturnSingleEntry = RxContext->QueryEa.ReturnSingleEntry;
if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) {
status = STATUS_INTERNAL_ERROR;
goto out;
}
if (entry->status == STATUS_BUFFER_TOO_SMALL) {
RxContext->InformationToReturn = entry->u.QueryEa.buf_len;
status = STATUS_BUFFER_TOO_SMALL;
} else if (entry->status == STATUS_SUCCESS) {
RxContext->Info.LengthRemaining = entry->u.QueryEa.buf_len;
RxContext->IoStatusBlock.Status = STATUS_SUCCESS;
#ifdef ENABLE_TIMINGS
InterlockedIncrement(&getexattr.sops);
InterlockedAdd64(&getexattr.size, entry->u.QueryEa.buf_len);
#endif
} else {
status = map_setea_error(entry->status);
}
RxFreePool(entry);
}
out:
#ifdef ENABLE_TIMINGS
t2 = KeQueryPerformanceCounter(NULL);
InterlockedIncrement(&getexattr.tops);
InterlockedAdd64(&getexattr.ticks, t2.QuadPart - t1.QuadPart);
#ifdef ENABLE_INDV_TIMINGS
DbgP("nfs41_QueryEaInformation delta = %d op=%d sum=%d\n",
t2.QuadPart - t1.QuadPart, getexattr.tops, getexattr.ticks);
#endif
#endif
DbgEx();
return status;
}
static void print_acl_args(SECURITY_INFORMATION info) static void print_acl_args(SECURITY_INFORMATION info)
{ {
DbgP("Security query: %s %s %s\n", DbgP("Security query: %s %s %s\n",

View file

@ -66,6 +66,7 @@ typedef enum _nfs41_opcodes {
NFS41_DIR_QUERY, NFS41_DIR_QUERY,
NFS41_FILE_QUERY, NFS41_FILE_QUERY,
NFS41_FILE_SET, NFS41_FILE_SET,
NFS41_EA_GET,
NFS41_EA_SET, NFS41_EA_SET,
NFS41_SYMLINK, NFS41_SYMLINK,
NFS41_VOLUME_QUERY, NFS41_VOLUME_QUERY,