first draft of named attributes
This commit is contained in:
parent
1c5935865b
commit
6eea9faa2e
11 changed files with 572 additions and 89 deletions
|
|
@ -298,6 +298,7 @@ const char* opcode2string(DWORD opcode)
|
|||
case NFS41_FILE_QUERY: return "NFS41_FILE_QUERY";
|
||||
case NFS41_FILE_SET: return "NFS41_FILE_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_VOLUME_QUERY: return "NFS41_VOLUME_QUERY";
|
||||
case NFS41_ACL_QUERY: return "NFS41_ACL_QUERY";
|
||||
|
|
|
|||
|
|
@ -195,6 +195,20 @@ typedef struct _FILE_LINK_INFORMATION {
|
|||
WCHAR FileName[1];
|
||||
} 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 */
|
||||
typedef enum _FSINFOCLASS {
|
||||
FileFsVolumeInformation = 1,
|
||||
|
|
|
|||
183
daemon/getattr.c
183
daemon/getattr.c
|
|
@ -26,7 +26,9 @@
|
|||
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
#include <strsafe.h>
|
||||
#include "from_kernel.h"
|
||||
#include "delegation.h"
|
||||
#include "daemon_debug.h"
|
||||
#include "nfs41_ops.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 = {
|
||||
parse_getattr,
|
||||
handle_getattr,
|
||||
marshall_getattr
|
||||
};
|
||||
|
||||
const nfs41_upcall_op nfs41_op_getexattr = {
|
||||
parse_getexattr,
|
||||
handle_getexattr,
|
||||
marshall_getexattr
|
||||
};
|
||||
|
|
@ -36,6 +36,9 @@
|
|||
#define NFS4_OPAQUE_LIMIT 1024
|
||||
#define NFS4_SESSIONID_SIZE 16
|
||||
#define NFS4_STATEID_OTHER 12
|
||||
#define NFS4_EASIZE 256
|
||||
#define NFS4_EANAME_SIZE 128
|
||||
|
||||
|
||||
#define NFS41_MAX_FILEIO_SIZE (1024 * 1024)
|
||||
#define NFS41_MAX_SERVER_CACHE 1024
|
||||
|
|
|
|||
|
|
@ -507,6 +507,10 @@ int nfs41_open(
|
|||
if (compound_error(status = compound.res.status))
|
||||
goto out;
|
||||
|
||||
if (dir_info.type == NF4ATTRDIR)
|
||||
goto out;
|
||||
|
||||
|
||||
/* fill in the file handle's fileid and superblock */
|
||||
file->fh.fileid = info->fileid;
|
||||
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",
|
||||
nfs_error_string(status));
|
||||
}
|
||||
|
||||
if (info.type == NF4NAMEDATTR)
|
||||
goto out;
|
||||
|
||||
nfs41_superblock_space_changed(file->fh.superblock);
|
||||
out:
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -497,8 +497,13 @@ static int parse_setexattr(unsigned char *buffer, uint32_t length, nfs41_upcall
|
|||
int status;
|
||||
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));
|
||||
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);
|
||||
out:
|
||||
|
|
@ -512,24 +517,97 @@ static int handle_setexattr(nfs41_upcall *upcall)
|
|||
nfs41_open_state *state = upcall->state_ref;
|
||||
stateid_arg stateid;
|
||||
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 */
|
||||
nfs41_delegation_return(state->session, &state->file,
|
||||
OPEN_DELEGATE_READ, FALSE);
|
||||
|
||||
nfs41_open_stateid_arg(state, &stateid);
|
||||
|
||||
if ((strncmp("NfsV3Attributes", eainfo->EaName, eainfo->EaNameLength) == 0 &&
|
||||
strlen("NfsV3Attributes") == eainfo->EaNameLength) ||
|
||||
(strncmp("NfsActOnLink", eainfo->EaName, eainfo->EaNameLength)== 0 &&
|
||||
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);
|
||||
}
|
||||
|
||||
/* mode */
|
||||
info.mode = args->mode;
|
||||
info.attrmask.arr[1] |= FATTR4_WORD1_MODE;
|
||||
info.attrmask.count = 2;
|
||||
while (eainfo != prev) {
|
||||
/* we don't allow for extended attribute values to be larger than NFS4_EASIZE.
|
||||
* thus, let's not allow setting such.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
status = nfs41_setattr(state->session, &state->file, &stateid, &info);
|
||||
if (status)
|
||||
dprintf(1, "nfs41_setattr() failed with error %s.\n",
|
||||
nfs_error_string(status));
|
||||
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;
|
||||
}
|
||||
|
||||
return nfs_to_windows_error(status, ERROR_NOT_SUPPORTED);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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_getattr;
|
||||
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_symlink;
|
||||
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_getattr,
|
||||
&nfs41_op_setattr,
|
||||
&nfs41_op_getexattr,
|
||||
&nfs41_op_setexattr,
|
||||
&nfs41_op_symlink,
|
||||
&nfs41_op_volume,
|
||||
|
|
|
|||
|
|
@ -102,7 +102,22 @@ typedef struct __setattr_upcall_args {
|
|||
int set_class;
|
||||
} 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 {
|
||||
const char *path;
|
||||
unsigned char *buf;
|
||||
uint32_t buf_len;
|
||||
uint32_t mode;
|
||||
} setexattr_upcall_args;
|
||||
|
||||
|
|
@ -155,6 +170,7 @@ typedef union __upcall_args {
|
|||
lock_upcall_args lock;
|
||||
unlock_upcall_args unlock;
|
||||
getattr_upcall_args getattr;
|
||||
getexattr_upcall_args getexattr;
|
||||
setattr_upcall_args setattr;
|
||||
setexattr_upcall_args setexattr;
|
||||
readdir_upcall_args readdir;
|
||||
|
|
|
|||
|
|
@ -609,6 +609,7 @@ const char *opcode2string(int opcode)
|
|||
case NFS41_FILE_QUERY: return "NFS41_FILE_QUERY";
|
||||
case NFS41_FILE_SET: return "NFS41_FILE_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_VOLUME_QUERY: return "NFS41_VOLUME_QUERY";
|
||||
case NFS41_ACL_QUERY: return "NFS41_ACL_QUERY";
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ typedef struct __nfs41_timings {
|
|||
} nfs41_timings;
|
||||
|
||||
nfs41_timings lookup, readdir, open, close, getattr, setattr, getacl, setacl, volume,
|
||||
read, write, lock, unlock;
|
||||
read, write, lock, unlock, setexattr, getexattr;
|
||||
#endif
|
||||
DRIVER_INITIALIZE DriverEntry;
|
||||
DRIVER_UNLOAD nfs41_driver_unload;
|
||||
|
|
@ -194,8 +194,21 @@ typedef struct _updowncall_entry {
|
|||
FILE_INFORMATION_CLASS InfoClass;
|
||||
} SetFile;
|
||||
struct {
|
||||
PUNICODE_STRING filename;
|
||||
PVOID buf;
|
||||
ULONG buf_len;
|
||||
DWORD mode;
|
||||
} SetEa;
|
||||
struct {
|
||||
PUNICODE_STRING filename;
|
||||
PVOID buf;
|
||||
ULONG buf_len;
|
||||
PVOID EaList;
|
||||
ULONG EaListLength;
|
||||
ULONG EaIndex;
|
||||
BOOLEAN ReturnSingleEntry;
|
||||
BOOLEAN RestartScan;
|
||||
} QueryEa;
|
||||
struct {
|
||||
PUNICODE_STRING filename;
|
||||
PUNICODE_STRING target;
|
||||
|
|
@ -940,22 +953,77 @@ NTSTATUS marshal_nfs41_easet(nfs41_updowncall_entry *entry,
|
|||
goto out;
|
||||
else
|
||||
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) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = marshall_unicode_as_ansi(&tmp, entry->u.SetEa.filename);
|
||||
if (status) goto out;
|
||||
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;
|
||||
|
||||
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:
|
||||
DbgEx();
|
||||
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,
|
||||
unsigned char *buf,
|
||||
ULONG buf_len,
|
||||
|
|
@ -1178,6 +1246,9 @@ handle_upcall(
|
|||
case NFS41_EA_SET:
|
||||
status = marshal_nfs41_easet(entry, pbOut, cbOut, len);
|
||||
break;
|
||||
case NFS41_EA_GET:
|
||||
status = marshal_nfs41_eaget(entry, pbOut, cbOut, len);
|
||||
break;
|
||||
case NFS41_SYMLINK:
|
||||
status = marshal_nfs41_symlink(entry, pbOut, cbOut, len);
|
||||
break;
|
||||
|
|
@ -1508,6 +1579,17 @@ nfs41_downcall (
|
|||
cur->u.QueryFile.buf_len = tmp->u.QueryFile.buf_len;
|
||||
RtlCopyMemory(cur->u.QueryFile.buf, buf, tmp->u.QueryFile.buf_len);
|
||||
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:
|
||||
if (cur->u.Symlink.set)
|
||||
break;
|
||||
|
|
@ -1826,7 +1908,7 @@ out:
|
|||
#ifdef ENABLE_TIMINGS
|
||||
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->sops ? time->size/time->sops : 0);
|
||||
if (clear) {
|
||||
|
|
@ -1862,6 +1944,8 @@ out:
|
|||
print_op_stat("volume", &volume, 1);
|
||||
print_op_stat("getattr", &getattr, 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("getacl", &getacl, 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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -3708,42 +3726,200 @@ NTSTATUS nfs41_SetEaInformation (
|
|||
PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
|
||||
NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
|
||||
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)RxContext->Info.Buffer;
|
||||
nfs3_attrs *attrs = NULL;
|
||||
PNFS41_NETROOT_EXTENSION pNetRootContext =
|
||||
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();
|
||||
print_debug_header(RxContext);
|
||||
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,
|
||||
pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
|
||||
pNetRootContext->nfs41d_version, &entry);
|
||||
if (status)
|
||||
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) {
|
||||
status = STATUS_INTERNAL_ERROR;
|
||||
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);
|
||||
RxFreePool(entry);
|
||||
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();
|
||||
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)
|
||||
{
|
||||
DbgP("Security query: %s %s %s\n",
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ typedef enum _nfs41_opcodes {
|
|||
NFS41_DIR_QUERY,
|
||||
NFS41_FILE_QUERY,
|
||||
NFS41_FILE_SET,
|
||||
NFS41_EA_GET,
|
||||
NFS41_EA_SET,
|
||||
NFS41_SYMLINK,
|
||||
NFS41_VOLUME_QUERY,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue