446 lines
21 KiB
C
446 lines
21 KiB
C
// Native resource-service client. Resource naming policy stays in rssrv; this file only speaks its Port protocol.
|
|
|
|
#include <ntlite/resource.h>
|
|
#include <ntlite/service.h>
|
|
#include <ntlite/syscall.h>
|
|
#include <string.h>
|
|
|
|
// Validates canonical global resource-path syntax. The namespace root is represented by exactly "/".
|
|
static KSTATUS NtlValidateResourcePath(SYS_STRING_VIEW path) {
|
|
if (!path.Data || path.Length == 0 || path.Length > NTL_RESOURCE_PATH_MAX || path.Data[0] != '/')
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
if (path.Length == 1)
|
|
return NTLSTATUS_SUCCESS;
|
|
if (path.Data[path.Length - 1] == '/')
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
size_t componentStart = 1;
|
|
for (size_t i = 1; i <= path.Length; ++i) {
|
|
if (i < path.Length) {
|
|
char c = path.Data[i];
|
|
if (c == '\\' || c == '\0')
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
if (c != '/')
|
|
continue;
|
|
}
|
|
|
|
size_t componentLength = i - componentStart;
|
|
if (componentLength == 0 || componentLength > NTL_RESOURCE_NAME_MAX ||
|
|
(componentLength == 1 && path.Data[componentStart] == '.') ||
|
|
(componentLength == 2 && path.Data[componentStart] == '.' && path.Data[componentStart + 1] == '.'))
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
componentStart = i + 1;
|
|
}
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Builds one inline request header with a path and optional operation-specific payload.
|
|
static KSTATUS NtlBuildResourceRequest(uint8_t* buffer,
|
|
size_t bufferSize,
|
|
uint32_t operation,
|
|
SYS_STRING_VIEW path,
|
|
SYS_STRING_VIEW aux,
|
|
SYS_RIGHTS rights,
|
|
SYS_RIGHTS exportRights,
|
|
uint32_t kind,
|
|
uint32_t* lengthOut) {
|
|
KSTATUS status = NtlValidateResourcePath(path);
|
|
if (!KSUCCESS(status) || !buffer || !lengthOut || !SysSvIsValid(aux))
|
|
return KSUCCESS(status) ? NTLSTATUS_INVALID_PARAMETER : status;
|
|
size_t total = sizeof(NTL_RESOURCE_REQUEST) + path.Length + aux.Length;
|
|
if (total > bufferSize || total > SYS_PORT_MAX_INLINE_BYTES || aux.Length > UINT32_MAX)
|
|
return NTLSTATUS_BUFFER_TOO_SMALL;
|
|
|
|
NTL_RESOURCE_REQUEST header;
|
|
memset(&header, 0, sizeof(header));
|
|
header.Size = sizeof(header);
|
|
header.Version = NTL_RESOURCE_PROTOCOL_VERSION;
|
|
header.Operation = operation;
|
|
header.Flags = NTL_RESOURCE_FLAG_NONE;
|
|
header.Rights = rights;
|
|
header.ExportRights = exportRights;
|
|
header.Kind = kind;
|
|
header.PathLength = (uint32_t)path.Length;
|
|
header.AuxLength = (uint32_t)aux.Length;
|
|
memcpy(buffer, &header, sizeof(header));
|
|
memcpy(buffer + sizeof(header), path.Data, path.Length);
|
|
if (aux.Length)
|
|
memcpy(buffer + sizeof(header) + path.Length, aux.Data, aux.Length);
|
|
*lengthOut = (uint32_t)total;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Executes one resource request and validates its fixed protocol reply.
|
|
static KSTATUS NtlCallResource(SYS_HANDLE session,
|
|
const void* requestPayload,
|
|
uint32_t requestLength,
|
|
const SYS_PORT_HANDLE_TRANSFER* requestHandles,
|
|
uint32_t requestHandleCount,
|
|
NTL_RESOURCE_REPLY* replyOut,
|
|
SYS_HANDLE* replyHandleOut) {
|
|
if (session == SYS_HANDLE_INVALID || !requestPayload || !requestLength || !replyOut)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
NTL_RESOURCE_REPLY reply;
|
|
memset(&reply, 0, sizeof(reply));
|
|
SYS_PORT_MESSAGE_INFO info;
|
|
memset(&info, 0, sizeof(info));
|
|
info.Size = sizeof(info);
|
|
SYS_HANDLE replyHandle = SYS_HANDLE_INVALID;
|
|
|
|
SYS_CALL_PORT_REQUEST call;
|
|
memset(&call, 0, sizeof(call));
|
|
call.Size = sizeof(call);
|
|
call.EndpointHandle = session;
|
|
call.Flags = SYS_PORT_FLAG_NONE;
|
|
call.RequestPayload = requestPayload;
|
|
call.RequestLength = requestLength;
|
|
call.RequestHandles = requestHandles;
|
|
call.RequestHandleCount = requestHandleCount;
|
|
call.ReplyPayload = &reply;
|
|
call.ReplyCapacity = sizeof(reply);
|
|
call.ReplyHandlesOut = replyHandleOut ? &replyHandle : (SYS_HANDLE*)0;
|
|
call.ReplyHandleCapacity = replyHandleOut ? 1u : 0u;
|
|
call.ReplyInfoOut = &info;
|
|
call.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
|
KSTATUS status = SysCallPort(&call);
|
|
if (!KSUCCESS(status))
|
|
return status;
|
|
|
|
if (info.Type != SYS_PORT_MESSAGE_REPLY || info.PayloadLength != sizeof(reply) ||
|
|
reply.Size != sizeof(reply) || reply.Version != NTL_RESOURCE_PROTOCOL_VERSION || reply.NameLength != 0) {
|
|
if (replyHandle != SYS_HANDLE_INVALID) (void)SysCloseHandle(replyHandle);
|
|
return NTLSTATUS_FAILURE;
|
|
}
|
|
if ((!replyHandleOut && info.HandleCount != 0) || (replyHandleOut && info.HandleCount > 1)) {
|
|
if (replyHandle != SYS_HANDLE_INVALID) (void)SysCloseHandle(replyHandle);
|
|
return NTLSTATUS_FAILURE;
|
|
}
|
|
|
|
*replyOut = reply;
|
|
if (replyHandleOut) *replyHandleOut = replyHandle;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Connects to the registered resource listener.
|
|
KSTATUS NtlResourceConnect(SYS_HANDLE* sessionOut) {
|
|
if (!sessionOut) return NTLSTATUS_INVALID_PARAMETER;
|
|
*sessionOut = SYS_HANDLE_INVALID;
|
|
SYS_CONNECT_SYSTEM_SERVICE_REQUEST request;
|
|
memset(&request, 0, sizeof(request));
|
|
request.Size = sizeof(request);
|
|
request.ServiceId = SYS_SERVICE_RESOURCE;
|
|
request.EndpointHandleOut = sessionOut;
|
|
return SysConnectSystemService(&request);
|
|
}
|
|
|
|
// Resolves the canonical /SystemRoot resource and closes the transient resource session.
|
|
KSTATUS NtlResourceOpenSystemRoot(SYS_RIGHTS desiredRights, SYS_HANDLE* handleOut) {
|
|
if (!desiredRights || !handleOut) return NTLSTATUS_INVALID_PARAMETER;
|
|
*handleOut = SYS_HANDLE_INVALID;
|
|
SYS_HANDLE session = SYS_HANDLE_INVALID;
|
|
KSTATUS status = NtlResourceConnect(&session);
|
|
if (!KSUCCESS(status)) return status;
|
|
status = NtlResourceLookup(session, SysSvFromCstr("/SystemRoot"), desiredRights, handleOut);
|
|
(void)NtlResourceClose(session);
|
|
return status;
|
|
}
|
|
|
|
// Connects through one delegated resource-listener capability.
|
|
KSTATUS NtlResourceConnectListener(SYS_HANDLE listenerHandle, SYS_HANDLE* sessionOut) {
|
|
if (listenerHandle == SYS_HANDLE_INVALID || !sessionOut)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
*sessionOut = SYS_HANDLE_INVALID;
|
|
SYS_CONNECT_PORT_REQUEST request;
|
|
memset(&request, 0, sizeof(request));
|
|
request.Size = sizeof(request);
|
|
request.ListenerHandle = listenerHandle;
|
|
request.Flags = SYS_PORT_CONNECT_FLAG_NONE;
|
|
request.EndpointHandleOut = sessionOut;
|
|
return SysConnectPort(&request);
|
|
}
|
|
|
|
// Delegates the authority to bind or unbind exactly one resource path.
|
|
KSTATUS NtlResourceCreatePublisher(SYS_HANDLE adminSession, SYS_STRING_VIEW path,
|
|
SYS_HANDLE* listenerOut) {
|
|
if (!listenerOut) return NTLSTATUS_INVALID_PARAMETER;
|
|
*listenerOut = SYS_HANDLE_INVALID;
|
|
uint8_t payload[sizeof(NTL_RESOURCE_REQUEST) + NTL_RESOURCE_PATH_MAX];
|
|
uint32_t length = 0;
|
|
KSTATUS status = NtlBuildResourceRequest(payload, sizeof(payload),
|
|
NTL_RESOURCE_OP_CREATE_PUBLISHER, path,
|
|
SysSvFromParts((const char*)0, 0), 0, 0,
|
|
NTL_RESOURCE_KIND_INVALID, &length);
|
|
if (!KSUCCESS(status)) return status;
|
|
NTL_RESOURCE_REPLY reply;
|
|
SYS_HANDLE handle = SYS_HANDLE_INVALID;
|
|
status = NtlCallResource(adminSession, payload, length, (const SYS_PORT_HANDLE_TRANSFER*)0,
|
|
0, &reply, &handle);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (reply.Operation != NTL_RESOURCE_OP_CREATE_PUBLISHER ||
|
|
!KSUCCESS(reply.Status) || handle == SYS_HANDLE_INVALID) {
|
|
if (handle != SYS_HANDLE_INVALID) (void)SysCloseHandle(handle);
|
|
return reply.Operation == NTL_RESOURCE_OP_CREATE_PUBLISHER && !KSUCCESS(reply.Status)
|
|
? reply.Status : NTLSTATUS_FAILURE;
|
|
}
|
|
*listenerOut = handle;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Looks up one resource and requests an attenuated alias of its bound capability.
|
|
KSTATUS NtlResourceLookup(SYS_HANDLE session,
|
|
SYS_STRING_VIEW path,
|
|
SYS_RIGHTS desiredRights,
|
|
SYS_HANDLE* handleOut) {
|
|
if (!desiredRights || !handleOut) return NTLSTATUS_INVALID_PARAMETER;
|
|
*handleOut = SYS_HANDLE_INVALID;
|
|
uint8_t payload[sizeof(NTL_RESOURCE_REQUEST) + NTL_RESOURCE_PATH_MAX];
|
|
uint32_t payloadLength = 0;
|
|
KSTATUS status = NtlBuildResourceRequest(payload, sizeof(payload), NTL_RESOURCE_OP_LOOKUP,
|
|
path, SysSvFromParts((const char*)0, 0),
|
|
desiredRights, 0, NTL_RESOURCE_KIND_INVALID,
|
|
&payloadLength);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
NTL_RESOURCE_REPLY reply;
|
|
SYS_HANDLE handle = SYS_HANDLE_INVALID;
|
|
status = NtlCallResource(session, payload, payloadLength, (const SYS_PORT_HANDLE_TRANSFER*)0, 0,
|
|
&reply, &handle);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (reply.Operation != NTL_RESOURCE_OP_LOOKUP) {
|
|
if (handle != SYS_HANDLE_INVALID) (void)SysCloseHandle(handle);
|
|
return NTLSTATUS_FAILURE;
|
|
}
|
|
if (!KSUCCESS(reply.Status)) {
|
|
if (handle != SYS_HANDLE_INVALID) (void)SysCloseHandle(handle);
|
|
return reply.Status;
|
|
}
|
|
if (handle == SYS_HANDLE_INVALID) return NTLSTATUS_FAILURE;
|
|
*handleOut = handle;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Queries one exact namespace node kind without transferring authority.
|
|
KSTATUS NtlResourceQuery(SYS_HANDLE session, SYS_STRING_VIEW path, uint32_t* kindOut) {
|
|
if (!kindOut) return NTLSTATUS_INVALID_PARAMETER;
|
|
*kindOut = NTL_RESOURCE_KIND_INVALID;
|
|
uint8_t payload[sizeof(NTL_RESOURCE_REQUEST) + NTL_RESOURCE_PATH_MAX];
|
|
uint32_t payloadLength = 0;
|
|
KSTATUS status = NtlBuildResourceRequest(payload, sizeof(payload), NTL_RESOURCE_OP_QUERY,
|
|
path, SysSvFromParts((const char*)0, 0),
|
|
0, 0, NTL_RESOURCE_KIND_INVALID, &payloadLength);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
NTL_RESOURCE_REPLY reply;
|
|
status = NtlCallResource(session, payload, payloadLength, (const SYS_PORT_HANDLE_TRANSFER*)0, 0,
|
|
&reply, (SYS_HANDLE*)0);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (reply.Operation != NTL_RESOURCE_OP_QUERY) return NTLSTATUS_FAILURE;
|
|
if (!KSUCCESS(reply.Status)) return reply.Status;
|
|
*kindOut = reply.Kind;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Resolves the longest bound resource prefix into one traversal capability.
|
|
KSTATUS NtlResourceResolve(SYS_HANDLE session,
|
|
SYS_STRING_VIEW path,
|
|
uint32_t flags,
|
|
SYS_HANDLE* rootHandleOut,
|
|
uint32_t* kindOut,
|
|
uint32_t* resolvedLengthOut) {
|
|
if (!rootHandleOut || !kindOut || !resolvedLengthOut || path.Length < 2 ||
|
|
(flags & ~NTL_RESOURCE_RESOLVE_FLAG_MODIFY) != 0)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
*rootHandleOut = SYS_HANDLE_INVALID;
|
|
*kindOut = NTL_RESOURCE_KIND_INVALID;
|
|
*resolvedLengthOut = 0;
|
|
|
|
uint8_t payload[sizeof(NTL_RESOURCE_REQUEST) + NTL_RESOURCE_PATH_MAX];
|
|
uint32_t payloadLength = 0;
|
|
KSTATUS status = NtlBuildResourceRequest(payload, sizeof(payload), NTL_RESOURCE_OP_RESOLVE,
|
|
path, SysSvFromParts((const char*)0, 0),
|
|
0, 0, NTL_RESOURCE_KIND_INVALID, &payloadLength);
|
|
if (!KSUCCESS(status)) return status;
|
|
((NTL_RESOURCE_REQUEST*)payload)->Flags = flags;
|
|
|
|
NTL_RESOURCE_REPLY reply;
|
|
SYS_HANDLE handle = SYS_HANDLE_INVALID;
|
|
status = NtlCallResource(session, payload, payloadLength, (const SYS_PORT_HANDLE_TRANSFER*)0, 0,
|
|
&reply, &handle);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (reply.Operation != NTL_RESOURCE_OP_RESOLVE || reply.Flags != flags) {
|
|
if (handle != SYS_HANDLE_INVALID) (void)SysCloseHandle(handle);
|
|
return NTLSTATUS_FAILURE;
|
|
}
|
|
if (!KSUCCESS(reply.Status)) {
|
|
if (handle != SYS_HANDLE_INVALID) (void)SysCloseHandle(handle);
|
|
return reply.Status;
|
|
}
|
|
if (handle == SYS_HANDLE_INVALID || reply.Kind == NTL_RESOURCE_KIND_INVALID ||
|
|
reply.ResolvedLength < 2 || reply.ResolvedLength > path.Length ||
|
|
(reply.ResolvedLength != path.Length && path.Data[reply.ResolvedLength] != '/')) {
|
|
if (handle != SYS_HANDLE_INVALID) (void)SysCloseHandle(handle);
|
|
return NTLSTATUS_FAILURE;
|
|
}
|
|
|
|
*rootHandleOut = handle;
|
|
*kindOut = reply.Kind;
|
|
*resolvedLengthOut = reply.ResolvedLength;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Enumerates one immediate namespace child after the cursor's last returned bytewise name.
|
|
KSTATUS NtlResourceEnumerate(SYS_HANDLE session,
|
|
SYS_STRING_VIEW directoryPath,
|
|
NTL_RESOURCE_ENUM_CURSOR* cursor,
|
|
NTL_RESOURCE_ENUM_ENTRY* entryOut) {
|
|
if (session == SYS_HANDLE_INVALID || !cursor || !entryOut ||
|
|
cursor->NameLength > NTL_RESOURCE_NAME_MAX || cursor->Name[cursor->NameLength] != '\0')
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
memset(entryOut, 0, sizeof(*entryOut));
|
|
|
|
SYS_STRING_VIEW after = SysSvFromParts(cursor->Name, cursor->NameLength);
|
|
uint8_t requestPayload[sizeof(NTL_RESOURCE_REQUEST) + NTL_RESOURCE_PATH_MAX + NTL_RESOURCE_NAME_MAX];
|
|
uint32_t requestLength = 0;
|
|
KSTATUS status = NtlBuildResourceRequest(requestPayload, sizeof(requestPayload), NTL_RESOURCE_OP_ENUMERATE,
|
|
directoryPath, after, 0, 0, NTL_RESOURCE_KIND_INVALID,
|
|
&requestLength);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
uint8_t replyPayload[sizeof(NTL_RESOURCE_REPLY) + NTL_RESOURCE_NAME_MAX];
|
|
memset(replyPayload, 0, sizeof(replyPayload));
|
|
SYS_PORT_MESSAGE_INFO info;
|
|
memset(&info, 0, sizeof(info));
|
|
info.Size = sizeof(info);
|
|
|
|
SYS_CALL_PORT_REQUEST call;
|
|
memset(&call, 0, sizeof(call));
|
|
call.Size = sizeof(call);
|
|
call.EndpointHandle = session;
|
|
call.Flags = SYS_PORT_FLAG_NONE;
|
|
call.RequestPayload = requestPayload;
|
|
call.RequestLength = requestLength;
|
|
call.ReplyPayload = replyPayload;
|
|
call.ReplyCapacity = sizeof(replyPayload);
|
|
call.ReplyInfoOut = &info;
|
|
call.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
|
status = SysCallPort(&call);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (info.Type != SYS_PORT_MESSAGE_REPLY || info.HandleCount != 0 || info.PayloadLength < sizeof(NTL_RESOURCE_REPLY))
|
|
return NTLSTATUS_FAILURE;
|
|
|
|
NTL_RESOURCE_REPLY reply;
|
|
memcpy(&reply, replyPayload, sizeof(reply));
|
|
if (reply.Size != sizeof(reply) || reply.Version != NTL_RESOURCE_PROTOCOL_VERSION ||
|
|
reply.Operation != NTL_RESOURCE_OP_ENUMERATE || reply.Flags != NTL_RESOURCE_FLAG_NONE ||
|
|
reply.ResolvedLength != 0 || reply.NameLength > NTL_RESOURCE_NAME_MAX ||
|
|
info.PayloadLength != sizeof(reply) + reply.NameLength)
|
|
return NTLSTATUS_FAILURE;
|
|
if (!KSUCCESS(reply.Status)) {
|
|
if (reply.NameLength != 0)
|
|
return NTLSTATUS_FAILURE;
|
|
return reply.Status;
|
|
}
|
|
if (reply.NameLength == 0 || reply.Kind == NTL_RESOURCE_KIND_INVALID)
|
|
return NTLSTATUS_FAILURE;
|
|
|
|
memcpy(entryOut->Name, replyPayload + sizeof(reply), reply.NameLength);
|
|
entryOut->Name[reply.NameLength] = '\0';
|
|
entryOut->Kind = reply.Kind;
|
|
memcpy(cursor->Name, entryOut->Name, reply.NameLength + 1u);
|
|
cursor->NameLength = reply.NameLength;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Creates one namespace directory through an administrative resource session.
|
|
KSTATUS NtlResourceCreateDirectory(SYS_HANDLE session, SYS_STRING_VIEW path) {
|
|
uint8_t payload[sizeof(NTL_RESOURCE_REQUEST) + NTL_RESOURCE_PATH_MAX];
|
|
uint32_t payloadLength = 0;
|
|
KSTATUS status = NtlBuildResourceRequest(payload, sizeof(payload), NTL_RESOURCE_OP_CREATE_DIRECTORY,
|
|
path, SysSvFromParts((const char*)0, 0),
|
|
0, 0, NTL_RESOURCE_KIND_INVALID, &payloadLength);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
NTL_RESOURCE_REPLY reply;
|
|
status = NtlCallResource(session, payload, payloadLength, (const SYS_PORT_HANDLE_TRANSFER*)0, 0,
|
|
&reply, (SYS_HANDLE*)0);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (reply.Operation != NTL_RESOURCE_OP_CREATE_DIRECTORY) return NTLSTATUS_FAILURE;
|
|
return reply.Status;
|
|
}
|
|
|
|
// Creates one absolute namespace symbolic link through an administrative resource session.
|
|
KSTATUS NtlResourceCreateSymbolicLink(SYS_HANDLE session, SYS_STRING_VIEW path, SYS_STRING_VIEW target) {
|
|
KSTATUS status = NtlValidateResourcePath(target);
|
|
if (!KSUCCESS(status)) return status;
|
|
uint8_t payload[sizeof(NTL_RESOURCE_REQUEST) + NTL_RESOURCE_PATH_MAX * 2u];
|
|
uint32_t payloadLength = 0;
|
|
status = NtlBuildResourceRequest(payload, sizeof(payload), NTL_RESOURCE_OP_CREATE_SYMBOLIC_LINK,
|
|
path, target, 0, 0, NTL_RESOURCE_KIND_INVALID, &payloadLength);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
NTL_RESOURCE_REPLY reply;
|
|
status = NtlCallResource(session, payload, payloadLength, (const SYS_PORT_HANDLE_TRANSFER*)0, 0,
|
|
&reply, (SYS_HANDLE*)0);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (reply.Operation != NTL_RESOURCE_OP_CREATE_SYMBOLIC_LINK) return NTLSTATUS_FAILURE;
|
|
return reply.Status;
|
|
}
|
|
|
|
// Binds an explicitly attenuated capability into an administrative resource session.
|
|
KSTATUS NtlResourceBind(SYS_HANDLE session,
|
|
SYS_STRING_VIEW path,
|
|
uint32_t kind,
|
|
SYS_HANDLE resourceHandle,
|
|
SYS_RIGHTS namespaceRights,
|
|
SYS_RIGHTS exportRights) {
|
|
if (kind == NTL_RESOURCE_KIND_INVALID || kind == NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY ||
|
|
kind == NTL_RESOURCE_KIND_SYMBOLIC_LINK || resourceHandle == SYS_HANDLE_INVALID ||
|
|
!(namespaceRights & SYS_RIGHT_TRANSFER) || !exportRights ||
|
|
(exportRights & ~namespaceRights) != 0)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
uint8_t payload[sizeof(NTL_RESOURCE_REQUEST) + NTL_RESOURCE_PATH_MAX];
|
|
uint32_t payloadLength = 0;
|
|
KSTATUS status = NtlBuildResourceRequest(payload, sizeof(payload), NTL_RESOURCE_OP_BIND,
|
|
path, SysSvFromParts((const char*)0, 0),
|
|
namespaceRights, exportRights, kind, &payloadLength);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
SYS_PORT_HANDLE_TRANSFER transfer;
|
|
transfer.Handle = resourceHandle;
|
|
transfer.DesiredRights = namespaceRights;
|
|
transfer.Flags = SYS_PORT_TRANSFER_FLAG_NONE;
|
|
NTL_RESOURCE_REPLY reply;
|
|
status = NtlCallResource(session, payload, payloadLength, &transfer, 1, &reply, (SYS_HANDLE*)0);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (reply.Operation != NTL_RESOURCE_OP_BIND) return NTLSTATUS_FAILURE;
|
|
return reply.Status;
|
|
}
|
|
|
|
// Removes one non-root namespace node through an administrative session.
|
|
KSTATUS NtlResourceUnbind(SYS_HANDLE session, SYS_STRING_VIEW path) {
|
|
uint8_t payload[sizeof(NTL_RESOURCE_REQUEST) + NTL_RESOURCE_PATH_MAX];
|
|
uint32_t payloadLength = 0;
|
|
KSTATUS status = NtlBuildResourceRequest(payload, sizeof(payload), NTL_RESOURCE_OP_UNBIND,
|
|
path, SysSvFromParts((const char*)0, 0),
|
|
0, 0, NTL_RESOURCE_KIND_INVALID, &payloadLength);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
NTL_RESOURCE_REPLY reply;
|
|
status = NtlCallResource(session, payload, payloadLength, (const SYS_PORT_HANDLE_TRANSFER*)0, 0,
|
|
&reply, (SYS_HANDLE*)0);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (reply.Operation != NTL_RESOURCE_OP_UNBIND) return NTLSTATUS_FAILURE;
|
|
return reply.Status;
|
|
}
|
|
|
|
// Disconnects and closes one resource session.
|
|
KSTATUS NtlResourceClose(SYS_HANDLE session) {
|
|
if (session == SYS_HANDLE_INVALID) return NTLSTATUS_INVALID_HANDLE;
|
|
KSTATUS disconnect = SysDisconnectPort(session);
|
|
KSTATUS close = SysCloseHandle(session);
|
|
if (!KSUCCESS(disconnect) && disconnect != NTLSTATUS_PORT_DISCONNECTED)
|
|
return disconnect;
|
|
return close;
|
|
}
|