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_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";
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
183
daemon/getattr.c
183
daemon/getattr.c
|
|
@ -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
|
||||||
|
};
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue