1. Implementing handlers for creating and destroying sessions in server.
2. Implementing sending create/destroy session requests in the Windows client.
Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
return HGFS_STATUS_INVALID_PARAMETER;
case ERROR_NOT_SAME_DEVICE:
return HGFS_STATUS_NOT_SAME_DEVICE;
+ case ERROR_INTERNAL_ERROR:
case HGFS_INTERNAL_STATUS_ERROR:
default:
return HGFS_STATUS_GENERIC_ERROR;
return HGFS_STATUS_INVALID_PARAMETER;
case EXDEV:
return HGFS_STATUS_NOT_SAME_DEVICE;
+ case EINTERNAL:
case HGFS_INTERNAL_STATUS_ERROR:
default:
return HGFS_STATUS_GENERIC_ERROR;
libHgfsServer_la_SOURCES += hgfsServerLinux.c
libHgfsServer_la_SOURCES += hgfsServerPacketUtil.c
libHgfsServer_la_SOURCES += hgfsDirNotifyStub.c
+libHgfsServer_la_SOURCES += hgfsServerParameters.c
AM_CFLAGS =
AM_CFLAGS += -DVMTOOLS_USE_GLIB
#include "cpNameLite.h"
#include "hgfsServerInt.h"
#include "hgfsServerPolicy.h"
+#include "hgfsUtil.h"
+#include "hgfsVirtualDir.h"
+#include "hgfsEscape.h"
#include "codeset.h"
#include "config.h"
#include "file.h"
#include "userlock.h"
#include "poll.h"
#include "libMutexRank.h"
+#include "vm_basic_asm.h"
#if defined(_WIN32)
#include <io.h>
#define HGFS_ASSERT_CLIENT(op)
#endif
+#define HGFS_ASSERT_INPUT(input) ASSERT(input && input->packet && input->metaPacket && \
+ input->session && \
+ (!input->payloadSize || input->payload))
/*
* Define this to enable an ASSERT if server gets an op lower than
static Bool hgfsChangeNotificationSupported = FALSE;
+/*
+ * Limit payload to 16M + header.
+ * This limit ensures that list of shared pages fits into VMCI datagram.
+ * Client may impose a lower limit in create session request.
+ */
+#define MAX_SERVER_PACKET_SIZE_V4 (0x1000000 + sizeof(HgfsHeader))
/* Local functions. */
static HgfsFileNode *HgfsHandle2FileNode(HgfsHandle handle,
HgfsSessionInfo *session);
static void HgfsServerExitSessionInternal(HgfsSessionInfo *session);
-static Bool HgfsValidatePacket(char const *packetIn, size_t packetSize, Bool v4header);
-static void HgfsPackReplyHeaderV4(HgfsInternalStatus status,
- uint32 payloadSize,
- HgfsHeader const *packetIn,
- HgfsHeader *header);
-static void HgfsServer_ProcessRequest(void *data);
-void HgfsServer_ReplyWithError(HgfsPacket *packet,
- const char *metaPacket,
- HgfsStatus status,
- Bool v4header,
- HgfsSessionInfo *session);
+static Bool HgfsIsShareRoot(char const *cpName, size_t cpNameSize);
+static void HgfsServerCompleteRequest(HgfsInternalStatus status,
+ size_t replyPayloadSize,
+ HgfsInputParam *input);
+
+/*
+ * Opcode handlers
+ */
+
+static void HgfsServerOpen(HgfsInputParam *input);
+static void HgfsServerRead(HgfsInputParam *input);
+static void HgfsServerWrite(HgfsInputParam *input);
+static void HgfsServerSearchOpen(HgfsInputParam *input);
+static void HgfsServerSearchRead(HgfsInputParam *input);
+static void HgfsServerGetattr(HgfsInputParam *input);
+static void HgfsServerSetattr(HgfsInputParam *input);
+static void HgfsServerCreateDir(HgfsInputParam *input);
+static void HgfsServerDeleteFile(HgfsInputParam *input);
+static void HgfsServerDeleteDir(HgfsInputParam *input);
+static void HgfsServerRename(HgfsInputParam *input);
+static void HgfsServerQueryVolume(HgfsInputParam *input);
+static void HgfsServerSymlinkCreate(HgfsInputParam *input);
+static void HgfsServerServerLockChange(HgfsInputParam *input);
+static void HgfsServerWriteWin32Stream(HgfsInputParam *input);
+static void HgfsServerCreateSession(HgfsInputParam *input);
+static void HgfsServerDestroySession(HgfsInputParam *input);
+static void HgfsServerClose(HgfsInputParam *input);
+static void HgfsServerSearchClose(HgfsInputParam *input);
/*
*----------------------------------------------------------------------------
*/
-static void
+void
HgfsServerSessionGet(HgfsSessionInfo *session) // IN: session context
{
ASSERT(session);
*-----------------------------------------------------------------------------
*/
-static HgfsInternalStatus
+static void
HgfsServerClose(HgfsInputParam *input) // IN: Input params
{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
HgfsHandle file;
- char *packetOut = NULL;
- size_t replySize;
- HgfsInternalStatus status = 0;
- HgfsOp op;
+ HgfsInternalStatus status = HGFS_ERROR_SUCCESS;
+ size_t replyPayloadSize = 0;
- ASSERT(packetIn);
- ASSERT(session);
+ HGFS_ASSERT_INPUT(input);
- if (!HgfsUnpackCloseRequest(packetIn, packetSize, &op, &file)) {
- status = HGFS_INTERNAL_STATUS_ERROR;
- goto error;
- }
+ if (HgfsUnpackCloseRequest(input->payload, input->payloadSize, input->op, &file)) {
- LOG(4, ("%s: close fh %u\n", __FUNCTION__, file));
+ LOG(4, ("%s: close fh %u\n", __FUNCTION__, file));
- if (!HgfsRemoveFromCache(file, session)) {
- LOG(4, ("%s: Could not remove the node from cache.\n", __FUNCTION__));
- status = HGFS_INTERNAL_STATUS_ERROR;
+ if (!HgfsRemoveFromCache(file, input->session)) {
+ LOG(4, ("%s: Could not remove the node from cache.\n", __FUNCTION__));
+ status = HGFS_ERROR_INTERNAL;
+ } else {
+ HgfsFreeFileNode(file, input->session);
+ if (!HgfsPackCloseReply(input->packet, input->metaPacket, input->op,
+ &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ }
} else {
- HgfsFreeFileNode(file, session);
- }
-
- if (!HgfsPackCloseReply(input->packet, packetIn, status, op,
- &packetOut, &replySize, session) ||
- !HgfsPacketSend(input->packet, packetOut, replySize, session, 0)) {
- status = HGFS_INTERNAL_STATUS_ERROR;
- goto error;
+ status = HGFS_ERROR_INTERNAL;
}
- return 0;
-
-error:
- HSPU_PutReplyPacket(input->packet, session);
- return status;
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
*-----------------------------------------------------------------------------
*/
-static HgfsInternalStatus
+static void
HgfsServerSearchClose(HgfsInputParam *input) // IN: Input params
{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
HgfsHandle search;
- char *packetOut = NULL;
- size_t replySize;
- HgfsInternalStatus status = 0;
- HgfsOp op;
-
- ASSERT(packetIn);
- ASSERT(session);
+ HgfsInternalStatus status;
+ size_t replyPayloadSize = 0;
- if (!HgfsUnpackSearchCloseRequest(packetIn, packetSize, &op, &search)) {
- status = HGFS_INTERNAL_STATUS_ERROR;
- goto error;
- }
+ HGFS_ASSERT_INPUT(input);
- LOG(4, ("%s: close search #%u\n", __FUNCTION__, search));
+ if (HgfsUnpackSearchCloseRequest(input->payload, input->payloadSize, input->op,
+ &search)) {
- if (!HgfsRemoveSearch(search, session)) {
- /* Invalid handle */
- LOG(4, ("%s: invalid handle %u\n", __FUNCTION__, search));
- status = HGFS_INTERNAL_STATUS_ERROR;
- goto error;
- }
+ LOG(4, ("%s: close search #%u\n", __FUNCTION__, search));
- if (!HgfsPackSearchCloseReply(input->packet, packetIn, status, op,
- &packetOut, &replySize, session) ||
- !HgfsPacketSend(input->packet, packetOut, replySize, session, 0)) {
- status = HGFS_INTERNAL_STATUS_ERROR;
- goto error;
+ if (HgfsRemoveSearch(search, input->session)) {
+ if (HgfsPackSearchCloseReply(input->packet, input->metaPacket, input->op,
+ &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_SUCCESS;
+ } else {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ } else {
+ /* Invalid handle */
+ LOG(4, ("%s: invalid handle %u\n", __FUNCTION__, search));
+ status = HGFS_ERROR_INTERNAL;
+ }
+ } else {
+ status = HGFS_ERROR_INTERNAL;
}
- return 0;
-
-error:
- HSPU_PutReplyPacket(input->packet, session);
- return status;
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/* Opcode handlers, indexed by opcode */
static struct {
- HgfsInternalStatus
- (*handler)(HgfsInputParam *input);
-
+ void (*handler)(HgfsInputParam *input);
/* Minimal size of the request packet */
unsigned int minReqSize;
{ HgfsServerServerLockChange, sizeof (HgfsRequestServerLockChange), REQ_SYNC },
{ HgfsServerWriteWin32Stream, HGFS_SIZEOF_OP(HgfsRequestWriteWin32StreamV3), REQ_SYNC },
/*
- * XXX
- * Will be replaced with the real thing when during merge with another outstanding
- * change.
- * For now just set min size big enough so request gets rejected when
- * such request comes from the client.
+ * Starting from HGFS_OP_CREATE_SESSION_V4 (all V4 commands and above) the
+ * second field is the minimum size for actual HGFS operational request
+ * and not the minimum size of operational request with a header.
*/
- { NULL, 0xffffff, REQ_ASYNC }, // Implemented in another change
- { NULL, 0xffffff, REQ_ASYNC }, // Implemented in another change
- { HgfsServerRead, HGFS_SIZEOF_OP(HgfsRequestReadV3), REQ_SYNC },
- { HgfsServerWrite, HGFS_SIZEOF_OP(HgfsRequestWriteV3), REQ_SYNC },
+ { HgfsServerCreateSession, offsetof(HgfsRequestCreateSessionV4, reserved), REQ_SYNC},
+ { HgfsServerDestroySession, offsetof(HgfsRequestDestroySessionV4, reserved), REQ_SYNC},
+ { HgfsServerRead, sizeof (HgfsRequestReadV3), REQ_SYNC},
+ { HgfsServerWrite, sizeof (HgfsRequestWriteV3), REQ_SYNC},
+
};
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsServerCompleteRequest --
+ *
+ * Performs all necessary action which needed for completing HGFS request:
+ * 1. Sends reply to the guest.
+ * 2. Release allocated objects, mapped guest memory.
+ * 3. Dereference objects that were referenced.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Reference to Session is dropped.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HgfsServerCompleteRequest(HgfsInternalStatus status, // IN: Status of the request
+ size_t replyPayloadSize, // IN: sizeof the reply payload
+ HgfsInputParam *input) // INOUT: request context
+{
+ char *packetOut;
+ size_t replyPacketSize;
+ size_t replySize;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (input->v4header) {
+ HgfsHeader *header;
+ replySize = sizeof *header + replyPayloadSize;
+ replyPacketSize = replySize;
+ header = HSPU_GetReplyPacket(input->packet, &replyPacketSize, input->session);
+ packetOut = (char *)header;
+
+ ASSERT_DEVEL(header && (replySize <= replyPacketSize));
+ if (header && (sizeof *header <= replyPacketSize)) {
+ HgfsPackReplyHeaderV4(status, replyPayloadSize, input->op,
+ input->session->sessionId, input->id, header);
+ }
+ } else {
+ HgfsReply *reply;
+ replySize = sizeof *reply + replyPayloadSize;
+ replyPacketSize = replySize;
+ reply = HSPU_GetReplyPacket(input->packet, &replyPacketSize, input->session);
+ packetOut = (char *)reply;
+
+ ASSERT_DEVEL(reply && (replySize <= replyPacketSize));
+ if (reply && (sizeof *reply <= replyPacketSize)) {
+ reply->id = input->id;
+ reply->status = HgfsConvertFromInternalStatus(status);
+ }
+ }
+ if (!HgfsPacketSend(input->packet, packetOut, replySize, input->session, 0)) {
+ /* Send failed. Drop the reply. */
+ LOG(4, ("Error sending reply\n"));
+ }
+
+ HgfsServerSessionPut(input->session);
+ free(input);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsServerProcessRequest --
+ *
+ * Dispatch an incoming packet (in packetIn) to a handler function.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HgfsServerProcessRequest(void *context)
+{
+ HgfsInputParam *input = (HgfsInputParam *)context;
+ if (!input->metaPacket) {
+ input->metaPacket = HSPU_GetMetaPacket(input->packet,
+ &input->metaPacketSize,
+ input->session);
+ }
+ (*handlers[input->op].handler)(input);
+}
+
+
/*
*-----------------------------------------------------------------------------
*
* a packet containing only a reply header with error code.
*
* The handler function can send the reply packet either using HgfsPacketSend
- * or HgfsPackAndSendPacket helper functions. This function would return error
- * as a reply if the op handler do not return HGFS_STATUS_SUCCESS.
+ * helper functions. This function would return error
+ * as a reply if the op handler do not return HGFS_ERROR_SUCCESS.
*
* NOTE: If any op handler needs to keep packetIn around for sending replies
* at a later point (possibly in a different thread context), it should
void *clientData) // IN: session info
{
HgfsSessionInfo *session = (HgfsSessionInfo *)clientData;
- HgfsRequest *request;
- HgfsHandle id;
- HgfsOp op;
- HgfsStatus status;
- Bool v4header = FALSE;
- HgfsInputParam *input;
- size_t metaPacketSize;
- char *metaPacket;
+ HgfsInternalStatus status;
+ HgfsInputParam *input = NULL;
ASSERT(session);
return;
}
- metaPacket = HSPU_GetMetaPacket(packet, &metaPacketSize, session);
- request = (HgfsRequest *)metaPacket;
- ASSERT_DEVEL(request);
- if (!request) {
- /*
- * How can I return error back to the client, clearly the client is either broken or
- * malicious ? We cannot continue from here.
- */
- return;
- }
-
- /*
- * Error out if less than HgfsRequest size.
- */
- if (metaPacketSize < sizeof *request) {
- if (metaPacketSize >= sizeof id) {
- id = request->id;
- } else {
- id = 0;
- }
- status = HGFS_STATUS_PROTOCOL_ERROR;
- ASSERT_DEVEL(0);
- goto err;
- }
-
- /* Increment the session's reference count until we send the reply. */
HgfsServerSessionGet(session);
- packet->id = id = request->id;
- op = request->op;
-
- /* If it is a V4 packet then handle it appropriately. */
- if (HGFS_V4_LEGACY_OPCODE == op) {
- HgfsHeader *header = (HgfsHeader *)metaPacket;
- if (metaPacketSize < sizeof *header) {
- status = HGFS_STATUS_PROTOCOL_ERROR;
- ASSERT_DEVEL(0);
- goto err;
- }
- op = header->op;
- v4header = TRUE;
- }
-
- if (!HgfsValidatePacket(metaPacket, metaPacketSize, v4header)) {
- status = HGFS_STATUS_PROTOCOL_ERROR;
- LOG(4, ("%s: %d: Possible BUG! malformed packet.\n", __FUNCTION__,
- __LINE__));
- goto err;
+ if (!HgfsParseRequest(packet, session, &input, &status)) {
+ LOG(4, ("%s: %d: Can't generate any response for the guest, just exit.\n ",
+ __FUNCTION__, __LINE__));
+ HgfsServerSessionPut(session);
+ return;
}
- HGFS_ASSERT_MINIMUM_OP(op);
- if (op < sizeof handlers / sizeof handlers[0]) {
- if (metaPacketSize >= handlers[op].minReqSize) {
- input = Util_SafeMalloc(sizeof *input);
- input->metaPacket = NULL;
- input->metaPacketSize = 0;
- input->session = session;
- input->packet = packet;
- input->v4header = v4header;
- input->op = op;
-
- /*
- * Do the decision making here, whether we want to process request
- * synchronously or asynchronously. Various factors to consider:
- *
- * - Use hints from the client, for instance, windows OS explicitly
- * tells the file system whether request is async or not.
- * - Determine statically - Simple to reason out, Simple to code
- */
- if (packet->supportsAsync &&
- ((handlers[op].reqType == REQ_ASYNC) || HGFS_DEBUG_ASYNC)) {
+ HGFS_ASSERT_MINIMUM_OP(input->op);
+ if (HGFS_ERROR_SUCCESS == status) {
+ HGFS_ASSERT_INPUT(input);
+ if (HgfsValidatePacket(input->metaPacket, input->metaPacketSize, input->v4header) &&
+ (input->op < ARRAYSIZE(handlers)) &&
+ (input->metaPacketSize >= handlers[input->op].minReqSize)) {
+ /* Initial validation passed, process the client request now. */
+ packet->processedAsync = packet->supportsAsync &&
+ (handlers[input->op].reqType == REQ_ASYNC);
+ if (packet->processedAsync) {
+ LOG(4, ("%s: %d: @@Async\n", __FUNCTION__, __LINE__));
+#ifndef VMX86_TOOLS
/*
* Asynchronous processing is supported by the transport.
* We can release mappings here and reacquire when needed.
*/
HSPU_PutMetaPacket(packet, session);
- packet->processedAsync = TRUE;
- LOG(4, ("%s: %d: @@Async\n", __FUNCTION__, __LINE__));
-#ifndef VMX86_TOOLS
- /* Remove pending requests during poweroff */
+ input->metaPacket = NULL;
+
+ /* Remove pending requests during poweroff. */
Poll_Callback(POLL_CS_MAIN,
POLL_FLAG_REMOVE_AT_POWEROFF,
- HgfsServer_ProcessRequest,
+ HgfsServerProcessRequest,
input,
POLL_REALTIME,
1000,
NULL);
#else
- /* Tools code should never process request async */
+ /* Tools code should never process request async. */
ASSERT(0);
#endif
- /* free(input) in HgfsServer_ProcessRequest */
} else {
LOG(4, ("%s: %d: ##Sync\n", __FUNCTION__, __LINE__));
- packet->processedAsync = FALSE;
- input->metaPacket = metaPacket;
- input->metaPacketSize = metaPacketSize;
-
- HgfsServer_ProcessRequest(input);
- /* free(input) in HgfsServer_ProcessRequest */
+ HgfsServerProcessRequest(input);
}
- return;
} else {
/*
* The input packet is smaller than the minimal size needed for the
* operation.
*/
-
- status = HGFS_STATUS_PROTOCOL_ERROR;
- LOG(4, ("%s: %d: Possible BUG! Smaller packet.\n", __FUNCTION__,
- __LINE__));
+ status = HGFS_ERROR_PROTOCOL;
+ LOG(4, ("%s: %d: Possible BUG! Malformed packet.\n", __FUNCTION__, __LINE__));
}
- } else {
- /* Unknown opcode */
- status = HGFS_STATUS_PROTOCOL_ERROR;
- LOG(4, ("%s: %d: Possible BUG! Invalid opcode.\n", __FUNCTION__,
- __LINE__));
}
- HGFS_ASSERT_CLIENT(op);
+ HGFS_ASSERT_CLIENT(input->op);
-err:
/* Send error if we fail to process the op. */
- if (status != HGFS_STATUS_SUCCESS) {
- HgfsServer_ReplyWithError(packet, metaPacket, status, v4header, session);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsServer_ProcessRequest --
- *
- * Reply with an error packet
- *
- * Results:
- * None.
- *
- * Side effects:
- * Guest memory mappings may be established.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-HgfsServer_ProcessRequest(void *data)
-{
- HgfsStatus status;
- HgfsInternalStatus internalStatus;
- HgfsInputParam *input = (HgfsInputParam *)data;
-
- if (!input->metaPacket) {
- input->metaPacket = HSPU_GetMetaPacket(input->packet,
- &input->metaPacketSize,
- input->session);
- }
- ASSERT(input->metaPacket);
-
- internalStatus = (*handlers[input->op].handler)(input);
- status = HgfsConvertFromInternalStatus(internalStatus);
- if (status != HGFS_STATUS_SUCCESS) {
- HgfsServer_ReplyWithError(input->packet, input->metaPacket,
- status, input->v4header, input->session);
- }
- free(input);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsServer_ReplyWithError --
- *
- * Reply with an error packet
- *
- * Results:
- * TRUE if succeeded, FALSE if failed.
- *
- * Side effects:
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-HgfsServer_ReplyWithError(HgfsPacket *packet,
- const char *metaPacket,
- HgfsStatus status,
- Bool v4header,
- HgfsSessionInfo *session)
-{
- char *packetOut;
- uint32 replySize;
- size_t replyPacketSize;
-
- if (v4header) {
- HgfsHeader *header;
- replyPacketSize = sizeof *header;
- header = HSPU_GetReplyPacket(packet, &replyPacketSize, session);
- if (!header || sizeof *header > replyPacketSize) {
- /*
- * Transport should probably check for minimum hgfs packet size.
- * How should we send an error back if there is no meta packet ?
- */
- return;
- }
-
- HgfsPackReplyHeaderV4(status, 0, (HgfsHeader *)metaPacket, header);
- packetOut = (char *)header;
- replySize = sizeof *header;
- } else {
- HgfsReply *reply;
- replyPacketSize = sizeof *reply;
- reply = HSPU_GetReplyPacket(packet, &replyPacketSize, session);
- if (!reply || sizeof *reply > replyPacketSize) {
- /*
- * Transport should probably check for minimum hgfs packet size.
- * How should we send an error back if there is no meta packet ?
- */
- return;
- }
- reply->id = packet->id;
- reply->status = status;
- packetOut = (char *)reply;
- replySize = sizeof *reply;
- }
- LOG(0, ("Error occured for id = %u %d status\n", (uint32)packet->id, status));
- if (!HgfsPacketSend(packet, packetOut, replySize, session, 0)) {
- /* Send failed. Drop the reply. */
- HSPU_PutReplyPacket(packet, session);
+ if (HGFS_ERROR_SUCCESS != status) {
+ LOG(4, ("Error %d occured parsing the packet\n", (uint32)status));
+ HgfsServerCompleteRequest(status, 0, input);
}
}
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsGenerateSessionId --
+ *
+ * Generates unique session id.
+ *
+ * Results:
+ * Unique 64-bit value.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static uint64
+HgfsGenerateSessionId(void)
+{
+ return RDTSC();
+}
+
+
/*
*-----------------------------------------------------------------------------
*
return FALSE;
}
+ session->sessionId = HgfsGenerateSessionId();
+ session->maxPacketSize = MAX_SERVER_PACKET_SIZE_V4;
/*
* Initialize the node handling components.
*/
HgfsSessionInfo *session = (HgfsSessionInfo *)clientData;
HSPU_PutMetaPacket(packet, session);
HSPU_PutReplyPacket(packet, session);
+ HSPU_PutDataPacketBuf(packet, session);
}
#endif
}
- HgfsServerSessionPut(session);
-
return result;
}
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackAndSendPacket --
- *
- * Packs up the reply with id and status and sends the packet.
- *
- * Results:
- * TRUE on success, FALSE otherwise.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsPackAndSendPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char *packetOut, // IN: Output packet to send
- size_t packetOutLen, // IN: Output packet size
- HgfsInternalStatus status, // IN: status
- HgfsHandle id, // IN: id of the request packet
- HgfsSessionInfo *session, // IN: session info
- HgfsSendFlags flags) // IN: flags how to send
-{
- HgfsReply *reply = (HgfsReply *)packetOut;
-
- ASSERT(packet);
- ASSERT(packetOut);
- ASSERT(session);
- ASSERT(packetOutLen <= HGFS_LARGE_PACKET_MAX);
-
- reply->id = id;
- reply->status = HgfsConvertFromInternalStatus(status);
-
- return HgfsPacketSend(packet, packetOut, packetOutLen, session, flags);
-}
-
-
/*
*-----------------------------------------------------------------------------
*
rootDir, session);
if (!search) {
LOG(4, ("%s: failed to get new search\n", __FUNCTION__));
- status = HGFS_INTERNAL_STATUS_ERROR;
+ status = HGFS_ERROR_INTERNAL;
goto out;
}
&configOptions);
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, shareName));
- status = HGFS_INTERNAL_STATUS_ERROR;
+ status = HGFS_ERROR_INTERNAL;
HgfsRemoveSearchInternal(search, session);
goto out;
}
search = HgfsAddNewSearch("", type, "", "", session);
if (!search) {
LOG(4, ("%s: failed to get new search\n", __FUNCTION__));
- status = HGFS_INTERNAL_STATUS_ERROR;
+ status = HGFS_ERROR_INTERNAL;
goto out;
}
if (result < 0) {
LOG(4, ("%s: couldn't get dents\n", __FUNCTION__));
HgfsRemoveSearchInternal(search, session);
- status = HGFS_INTERNAL_STATUS_ERROR;
+ status = HGFS_ERROR_INTERNAL;
goto out;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsValidatePacket --
+ * HgfsAllocInitReply --
*
- * Validates that packet is not malformed. Checks consistency of various
- * fields and sizes.
+ * Allocates hgfs reply packet and calculates pointer to HGFS payload.
*
* Results:
- * TRUE if the packet is correct.
- * FALSE if the packet is malformed.
+ * TRUE on success, FALSE on failure.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-static Bool
-HgfsValidatePacket(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- Bool v4header) // IN: header version
-{
- HgfsRequest *request = (HgfsRequest *)packetIn;
- Bool result = TRUE;
-
- if (packetSize < sizeof *request) {
- return FALSE;
+Bool
+HgfsAllocInitReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ size_t payloadSize, // IN: payload size
+ void **payload, // OUT: pointer to the reply payload
+ HgfsSessionInfo *session) // IN: Session Info
+{
+ HgfsRequest *request = (HgfsRequest *)packetHeader;
+ size_t replyPacketSize;
+ size_t headerSize = 0; /* Replies prior to V3 do not have a header. */
+ Bool result = FALSE;
+ char *reply;
+
+ if (HGFS_V4_LEGACY_OPCODE == request->op) {
+ headerSize = sizeof(HgfsHeader);
+ } else if (request->op < HGFS_OP_CREATE_SESSION_V4 &&
+ request->op > HGFS_OP_RENAME_V2) {
+ headerSize = sizeof(HgfsReply);
}
- if (v4header) {
- HgfsHeader *header = (HgfsHeader *)packetIn;
- ASSERT(packetSize >= header->packetSize);
- ASSERT(header->packetSize >= header->headerSize);
- result = packetSize >= offsetof(HgfsHeader, requestId) &&
- header->headerSize >= offsetof(HgfsHeader, reserved) &&
- header->packetSize >= header->headerSize &&
- packetSize >= header->packetSize;
- } else {
- result = packetSize >= sizeof *request;
+ replyPacketSize = headerSize + payloadSize;
+ reply = HSPU_GetReplyPacket(packet, &replyPacketSize, session);
+
+ if (reply && (replyPacketSize >= headerSize + payloadSize)) {
+ result = TRUE;
+ if (payloadSize > 0) {
+ *payload = reply + headerSize;
+ } else {
+ *payload = NULL;
+ }
}
+
return result;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsGetPayloadSize --
+ * HgfsServerRead --
*
- * Returns size of the payload based on incoming packet and total
- * packet size.
+ * Handle a Read request.
*
* Results:
- * Size of the payload in bytes.
+ * HGFS_ERROR_SUCCESS on success.
+ * HGFS error code on failure.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-size_t
-HgfsGetPayloadSize(char const *packetIn, // IN: request packet
- size_t packetSize) // IN: request packet size
+static void
+HgfsServerRead(HgfsInputParam *input) // IN: Input params
{
- HgfsRequest *request = (HgfsRequest *)packetIn;
- size_t result;
- ASSERT(packetSize >= sizeof *request);
- if (request->op < HGFS_OP_CREATE_SESSION_V4) {
- result = packetSize - sizeof *request;
+ HgfsInternalStatus status;
+ HgfsHandle file;
+ uint64 offset;
+ uint32 requiredSize;
+ size_t replyPayloadSize = 0;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (!HgfsUnpackReadRequest(input->payload, input->payloadSize, input->op, &file,
+ &offset, &requiredSize)) {
+ status = HGFS_ERROR_PROTOCOL;
} else {
- HgfsHeader *header = (HgfsHeader *)packetIn;
- ASSERT(packetSize >= header->packetSize);
- ASSERT(header->packetSize >= header->headerSize);
- result = header->packetSize - header->headerSize;
+ switch(input->op) {
+ case HGFS_OP_READ_FAST_V4:
+ case HGFS_OP_READ_V3: {
+ HgfsReplyReadV3 *reply;
+ void *payload;
+ uint32 inlineDataSize =
+ (HGFS_OP_READ_FAST_V4 == input->op) ? 0 : requiredSize;
+
+ if (!HgfsAllocInitReply(input->packet, input->metaPacket,
+ sizeof *reply + inlineDataSize, (void **)&reply,
+ input->session)) {
+ status = HGFS_ERROR_PROTOCOL;
+ } else {
+ if (inlineDataSize > 0) {
+ payload = reply->payload;
+ } else {
+ payload = HSPU_GetDataPacketBuf(input->packet, BUF_WRITEABLE,
+ input->session);
+ }
+ if (payload) {
+ status = HgfsPlatformReadFile(file, input->session, offset,
+ requiredSize, payload,
+ &reply->actualSize);
+ if (HGFS_ERROR_SUCCESS == status) {
+ replyPayloadSize = sizeof *reply +
+ ((inlineDataSize > 0) ? reply->actualSize : 0);
+ }
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
+ }
+ }
+ break;
+ }
+ case HGFS_OP_READ: {
+ HgfsReplyRead *reply;
+
+ if (HgfsAllocInitReply(input->packet, input->metaPacket,
+ sizeof *reply + requiredSize, (void **)&reply,
+ input->session)) {
+ status = HgfsPlatformReadFile(file, input->session, offset, requiredSize,
+ reply->payload, &reply->actualSize);
+ if (HGFS_ERROR_SUCCESS == status) {
+ replyPayloadSize = sizeof *reply + reply->actualSize;
+ }
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
+ }
+ break;
+ }
+ default:
+ NOT_IMPLEMENTED();
+ status = HGFS_ERROR_PROTOCOL;
+ }
}
- return result;
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsParseRequest --
+ * HgfsServerWrite --
*
- * Returns requested operation and pointer to the payload based on
- * incoming packet and total packet size.
+ * Handle a Write request.
*
* Results:
- * TRUE if the packet has been successfully processed.
- * FALSE if the incoming request is malformed.
+ * None.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsParseRequest(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- void const **payload, // OUT: payload
- size_t *payloadSize, // OUT: payloadSize
- HgfsOp *op) // OUT: operation
-{
- HgfsRequest *request = (HgfsRequest *)packetIn;
- Bool result = FALSE;
- ASSERT(packetSize >= sizeof *request);
- *payload = NULL;
- *payloadSize = 0;
- if (request->op < HGFS_OP_OPEN_V3) {
- /* Legacy requests do not have a separate header. */
- *payload = packetIn;
- *op = request->op;
- *payloadSize = packetSize;
- result = TRUE;
- } else if (request->op < HGFS_OP_CREATE_SESSION_V4) {
- /* V3 header. */
- if (packetSize > sizeof *request) {
- *payload = HGFS_REQ_GET_PAYLOAD_V3(packetIn);
- *payloadSize = packetSize - ((char *)*payload - packetIn);
+static void
+HgfsServerWrite(HgfsInputParam *input) // IN: Input params
+{
+ uint32 numberBytesToWrite;
+ HgfsInternalStatus status;
+ HgfsWriteFlags flags;
+ uint64 offset;
+ char *dataToWrite;
+ uint32 replyActualSize;
+ size_t replyPayloadSize = 0;
+ HgfsHandle file;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (HgfsUnpackWriteRequest(input, &file, &offset, &numberBytesToWrite,
+ &flags, &dataToWrite)) {
+
+ status = HgfsPlatformWriteFile(file, input->session, offset, numberBytesToWrite,
+ flags, dataToWrite, &replyActualSize);
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (!HgfsPackWriteReply(input->packet, input->metaPacket, input->op,
+ replyActualSize, &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
}
- *op = request->op;
- result = TRUE;
} else {
- /* V4 header. */
- if (request->op == HGFS_V4_LEGACY_OPCODE) {
- HgfsHeader *header = (HgfsHeader *)packetIn;
- if (packetSize >= header->packetSize &&
- header->packetSize >= header->headerSize) {
- *op = header->op;
- result = TRUE;
- if (header->packetSize > header->headerSize) {
- *payload = packetIn + header->headerSize;
- *payloadSize = header->packetSize - header->headerSize;
- }
- }
- }
+ status = HGFS_ERROR_PROTOCOL;
}
- return result;
+
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsUnpackOpenPayloadV1 --
+ * HgfsQueryVolume --
*
- * Unpack and validate payload for hgfs open request V1 to the HgfsFileOpenInfo
- * structure that is used to pass around open request information.
+ * Performs actual work to get free space and capacity for a volume or
+ * a group of volumes.
*
* Results:
- * TRUE on success.
- * FALSE on failure.
+ * Zero on success.
+ * Non-zero on failure.
*
* Side effects:
* None
*
+ *
*-----------------------------------------------------------------------------
*/
+HgfsInternalStatus
+HgfsQueryVolume(HgfsSessionInfo *session, // IN: session info
+ char *fileName, // IN: cpName for the volume
+ size_t fileNameLength, // IN: cpName length
+ uint32 caseFlags, // IN: case sensitive/insensitive name
+ uint64 *freeBytes, // OUT: free space in bytes
+ uint64 *totalBytes) // OUT: capacity in bytes
+{
+ HgfsInternalStatus status = HGFS_ERROR_SUCCESS;
+ uint64 outFreeBytes;
+ uint64 outTotalBytes;
+ char *utf8Name = NULL;
+ size_t utf8NameLen;
+ HgfsNameStatus nameStatus;
+ Bool firstShare = TRUE;
+ HgfsShareInfo shareInfo;
+ HgfsHandle handle;
+ VolumeInfoType infoType;
+ DirectoryEntry *dent;
+ size_t failed = 0;
+ size_t shares = 0;
+ int offset = 0;
+ HgfsInternalStatus firstErr = HGFS_ERROR_SUCCESS;
+ Bool success;
+
+ /* It is now safe to read the file name field. */
+ nameStatus = HgfsServerGetShareInfo(fileName,
+ fileNameLength,
+ caseFlags,
+ &shareInfo,
+ &utf8Name,
+ &utf8NameLen);
+
+ switch (nameStatus) {
+ case HGFS_NAME_STATUS_INCOMPLETE_BASE:
+ /*
+ * This is the base of our namespace. Clients can request a
+ * QueryVolumeInfo on it, on individual shares, or on just about
+ * any pathname.
+ */
-Bool
-HgfsUnpackOpenPayloadV1(HgfsRequestOpen *requestV1, // IN: request payload
- size_t payloadSize, // IN: request payload size
- HgfsFileOpenInfo *openInfo) // IN/OUT: open info struct
-{
- size_t extra;
+ LOG(4,("%s: opened search on base\n", __FUNCTION__));
+ status = HgfsServerSearchVirtualDir(HgfsServerPolicy_GetShares,
+ HgfsServerPolicy_GetSharesInit,
+ HgfsServerPolicy_GetSharesCleanup,
+ DIRECTORY_SEARCH_TYPE_BASE,
+ session,
+ &handle);
+ if (status != 0) {
+ return status;
+ }
- /* Enforced by the dispatch function. */
- if (payloadSize < sizeof *requestV1) {
- return FALSE;
- }
+ /*
+ * If we're outside the Tools, find out if we're to compute the minimum
+ * values across all shares, or the maximum values.
+ */
+ infoType = VOLUME_INFO_TYPE_MIN;
+#ifndef VMX86_TOOLS
+ {
+ char *volumeInfoType = Config_GetString("min",
+ "tools.hgfs.volumeInfoType");
+ if (!Str_Strcasecmp(volumeInfoType, "max")) {
+ infoType = VOLUME_INFO_TYPE_MAX;
+ }
+ free(volumeInfoType);
+ }
+#endif
- extra = payloadSize - sizeof *requestV1;
+ /*
+ * Now go through all shares and get share paths on the server.
+ * Then retrieve space info for each share's volume.
+ */
+ offset = 0;
+ while ((dent = HgfsGetSearchResult(handle, session, offset,
+ TRUE)) != NULL) {
+ char const *sharePath;
+ size_t sharePathLen;
+ uint64 currentFreeBytes = 0;
+ uint64 currentTotalBytes = 0;
+ size_t length;
- /*
- * The request file name length is user-provided, so this test must be
- * carefully written to prevent wraparounds.
- */
- if (requestV1->fileName.length > extra) {
- /* The input packet is smaller than the request. */
- return FALSE;
- }
+ length = strlen(dent->d_name);
- /* For OpenV1 requests, we know exactly what fields we expect. */
- openInfo->mask = HGFS_OPEN_VALID_MODE |
- HGFS_OPEN_VALID_FLAGS |
- HGFS_OPEN_VALID_OWNER_PERMS |
- HGFS_OPEN_VALID_FILE_NAME;
- openInfo->mode = requestV1->mode;
- openInfo->cpName = requestV1->fileName.name;
- openInfo->cpNameSize = requestV1->fileName.length;
- openInfo->flags = requestV1->flags;
- openInfo->ownerPerms = requestV1->permissions;
- return TRUE;
-}
+ /*
+ * Now that the server is passing '.' and ".." around as dents, we
+ * need to make sure to handle them properly. In particular, they
+ * should be ignored within QueryVolume, as they're not real shares.
+ */
+ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {
+ LOG(4, ("%s: Skipping fake share %s\n", __FUNCTION__,
+ dent->d_name));
+ free(dent);
+ continue;
+ }
+ /*
+ * The above check ignores '.' and '..' so we do not include them in
+ * the share count here.
+ */
+ shares++;
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackOpenPayloadV2 --
- *
- * Unpack and validate payload for hgfs open request V2 to the HgfsFileOpenInfo
- * structure that is used to pass around open request information.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
+ /*
+ * Check permission on the share and get the share path. It is not
+ * fatal if these do not succeed. Instead we ignore the failures
+ * (apart from logging them) until we have processed all shares. Only
+ * then do we check if there were any failures; if all shares failed
+ * to process then we bail out with an error code.
+ */
-Bool
-HgfsUnpackOpenPayloadV2(HgfsRequestOpenV2 *requestV2, // IN: request payload
- size_t payloadSize, // IN: request payload size
- HgfsFileOpenInfo *openInfo) // IN/OUT: open info struct
-{
- size_t extra;
+ nameStatus = HgfsServerPolicy_GetSharePath(dent->d_name, length,
+ HGFS_OPEN_MODE_READ_ONLY,
+ &sharePathLen,
+ &sharePath);
+ free(dent);
+ if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
+ LOG(4, ("%s: No such share or access denied\n", __FUNCTION__));
+ if (0 == firstErr) {
+ firstErr = HgfsPlatformConvertFromNameStatus(nameStatus);
+ }
+ failed++;
+ continue;
+ }
- /* Enforced by the dispatch function. */
- if (payloadSize < sizeof *requestV2) {
- return FALSE;
- }
+ /*
+ * Pick the drive with amount of space available and return that
+ * according to different volume info type.
+ */
- extra = payloadSize - sizeof *requestV2;
- if (!(requestV2->mask & HGFS_OPEN_VALID_FILE_NAME)) {
- /* We do not support open requests without a valid file name. */
- return FALSE;
- }
+ if (!HgfsServerStatFs(sharePath, sharePathLen,
+ ¤tFreeBytes, ¤tTotalBytes)) {
+ LOG(4, ("%s: error getting volume information\n",
+ __FUNCTION__));
+ if (0 == firstErr) {
+ firstErr = HGFS_ERROR_IO;
+ }
+ failed++;
+ continue;
+ }
- /*
- * The request file name length is user-provided, so this test must be
- * carefully written to prevent wraparounds.
- */
- if (requestV2->fileName.length > extra) {
- /* The input packet is smaller than the request. */
- return FALSE;
+ /*
+ * Pick the drive with amount of space available and return that
+ * according to different volume info type.
+ */
+ switch (infoType) {
+ case VOLUME_INFO_TYPE_MIN:
+ if ((outFreeBytes > currentFreeBytes) || firstShare) {
+ firstShare = FALSE;
+ outFreeBytes = currentFreeBytes;
+ outTotalBytes = currentTotalBytes;
+ }
+ break;
+ case VOLUME_INFO_TYPE_MAX:
+ if ((outFreeBytes < currentFreeBytes)) {
+ outFreeBytes = currentFreeBytes;
+ outTotalBytes = currentTotalBytes;
+ }
+ break;
+ default:
+ NOT_IMPLEMENTED();
+ }
+ }
+ if (!HgfsRemoveSearch(handle, session)) {
+ LOG(4, ("%s: could not close search on base\n", __FUNCTION__));
+ }
+ if (shares == failed) {
+ if (firstErr != 0) {
+ /*
+ * We failed to query any of the shares. We return the error]
+ * from the first share failure.
+ */
+ status = firstErr;
+ }
+ /* No shares but no error, return zero for sizes and success. */
+ }
+ break;
+ case HGFS_NAME_STATUS_COMPLETE:
+ ASSERT(utf8Name);
+ LOG(4,("%s: querying path %s\n", __FUNCTION__, utf8Name));
+ success = HgfsServerStatFs(utf8Name, utf8NameLen,
+ &outFreeBytes, &outTotalBytes);
+ free(utf8Name);
+ if (!success) {
+ LOG(4, ("%s: error getting volume information\n", __FUNCTION__));
+ status = HGFS_ERROR_IO;
+ }
+ break;
+ default:
+ LOG(4,("%s: file access check failed\n", __FUNCTION__));
+ status = HgfsPlatformConvertFromNameStatus(nameStatus);
}
- /*
- * Copy all the fields into our carrier struct. Some will probably be
- * garbage, but it's simpler to copy everything now and check the
- * valid bits before reading later.
- */
+ *freeBytes = outFreeBytes;
+ *totalBytes = outTotalBytes;
- openInfo->mask = requestV2->mask;
- openInfo->mode = requestV2->mode;
- openInfo->cpName = requestV2->fileName.name;
- openInfo->cpNameSize = requestV2->fileName.length;
- openInfo->flags = requestV2->flags;
- openInfo->specialPerms = requestV2->specialPerms;
- openInfo->ownerPerms = requestV2->ownerPerms;
- openInfo->groupPerms = requestV2->groupPerms;
- openInfo->otherPerms = requestV2->otherPerms;
- openInfo->attr = requestV2->attr;
- openInfo->allocationSize = requestV2->allocationSize;
- openInfo->desiredAccess = requestV2->desiredAccess;
- openInfo->shareAccess = requestV2->shareAccess;
- openInfo->desiredLock = requestV2->desiredLock;
- return TRUE;
+ return status;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsUnpackOpenPayloadV3 --
+ * HgfsServerQueryVolume --
*
- * Unpack and validate payload for hgfs open request V3 to the HgfsFileOpenInfo
- * structure that is used to pass around open request information.
+ * Handle a Query Volume request.
+ *
+ * Right now we only handle the volume space request. Call Wiper library
+ * to get the volume information.
+ * It is possible that shared folders can belong to different volumes on
+ * the server. If this is the case, default to return the space information
+ * of the volume that has the least amount of the available space, but it's
+ * configurable with a config option (tools.hgfs.volumeInfoType). 2 possible
+ * options, min and max.
*
* Results:
- * TRUE on success.
- * FALSE on failure.
+ * None.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsUnpackOpenPayloadV3(HgfsRequestOpenV3 *requestV3, // IN: request payload
- size_t payloadSize, // IN: request payload size
- HgfsFileOpenInfo *openInfo) // IN/OUT: open info struct
+static void
+HgfsServerQueryVolume(HgfsInputParam *input) // IN: Input params
{
- size_t extra;
-
- /* Enforced by the dispatch function. */
- if (payloadSize < sizeof *requestV3) {
- return FALSE;
- }
-
- extra = payloadSize - sizeof *requestV3;
+ HgfsInternalStatus status;
+ size_t replyPayloadSize = 0;
+ HgfsHandle file;
+ char *fileName;
+ size_t fileNameLength;
+ uint32 caseFlags;
+ Bool useHandle;
+ uint64 freeBytes;
+ uint64 totalBytes;
- if (!(requestV3->mask & HGFS_OPEN_VALID_FILE_NAME)) {
- /* We do not support open requests without a valid file name. */
- return FALSE;
- }
+ HGFS_ASSERT_INPUT(input);
- /*
- * The request file name length is user-provided, so this test must be
- * carefully written to prevent wraparounds.
- */
- if (requestV3->fileName.length > extra) {
- /* The input packet is smaller than the request. */
- return FALSE;
+ if (HgfsUnpackQueryVolumeRequest(input->payload, input->payloadSize, input->op,
+ &useHandle, &fileName,
+ &fileNameLength, &caseFlags, &file)) {
+ /*
+ * We don't yet support file handle for this operation.
+ * Clients should retry using the file name.
+ */
+ if (useHandle) {
+ LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
+ status = HGFS_ERROR_INVALID_PARAMETER;
+ } else {
+ status = HgfsQueryVolume(input->session, fileName, fileNameLength, caseFlags,
+ &freeBytes, &totalBytes);
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (!HgfsPackQueryVolumeReply(input->packet, input->metaPacket,
+ input->op, freeBytes, totalBytes,
+ &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ }
+ }
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
}
- /*
- * Copy all the fields into our carrier struct. Some will probably be
- * garbage, but it's simpler to copy everything now and check the
- * valid bits before reading later.
- */
- openInfo->mask = requestV3->mask;
- openInfo->mode = requestV3->mode;
- openInfo->cpName = requestV3->fileName.name;
- openInfo->cpNameSize = requestV3->fileName.length;
- openInfo->caseFlags = requestV3->fileName.caseType;
- openInfo->flags = requestV3->flags;
- openInfo->specialPerms = requestV3->specialPerms;
- openInfo->ownerPerms = requestV3->ownerPerms;
- openInfo->groupPerms = requestV3->groupPerms;
- openInfo->otherPerms = requestV3->otherPerms;
- openInfo->attr = requestV3->attr;
- openInfo->allocationSize = requestV3->allocationSize;
- openInfo->desiredAccess = requestV3->desiredAccess;
- openInfo->shareAccess = requestV3->shareAccess;
- openInfo->desiredLock = requestV3->desiredLock;
- return TRUE;
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsUnpackOpenRequest --
+ * HgfsSymlinkCreate --
*
- * Unpack hgfs open request to the HgfsFileOpenInfo structure that is used
- * to pass around open request information.
+ * Platform independent function that verifies whether symbolic link creation
+ * is allowed for the specific shared folder and then calls platform specific
+ * HgfsPlatformSymlinkCreate to do the actual job.
*
* Results:
- * TRUE on success.
- * FALSE on failure.
+ * Zero on success.
+ * Non-zero on failure.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsUnpackOpenRequest(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- HgfsFileOpenInfo *openInfo) // IN/OUT: open info structure
-{
- void const *payload;
- size_t payloadSize;
- HgfsOp op;
-
- ASSERT(packetIn);
- ASSERT(openInfo);
-
- if (!HgfsParseRequest(packetIn, packetSize, &payload, &payloadSize, &op)) {
- return FALSE;
- }
-
- openInfo->requestType = op;
- openInfo->caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+HgfsInternalStatus
+HgfsSymlinkCreate(HgfsSessionInfo *session, // IN: session info,
+ char *srcFileName, // IN: symbolic link file name
+ uint32 srcFileNameLength, // IN: symbolic link name length
+ uint32 srcCaseFlags, // IN: symlink case flags
+ char *trgFileName, // IN: symbolic link target name
+ uint32 trgFileNameLength, // IN: target name length
+ uint32 trgCaseFlags) // IN: target case flags
+{
+ HgfsShareInfo shareInfo;
+ HgfsInternalStatus status = 0;
+ HgfsNameStatus nameStatus;
+ HgfsShareOptions configOptions;
+ char *localSymlinkName = NULL;
+ size_t localSymlinkNameLen;
+ char localTargetName[HGFS_PACKET_MAX];
- switch (op) {
- case HGFS_OP_OPEN_V3: {
- HgfsRequestOpenV3 *requestV3 = (HgfsRequestOpenV3 *)payload;
- LOG(4, ("%s: HGFS_OP_OPEN_V3\n", __FUNCTION__));
+ /*
+ * It is now safe to read the symlink file name and the
+ * "targetName" field
+ */
- if (!HgfsUnpackOpenPayloadV3(requestV3, payloadSize, openInfo)) {
- return FALSE;
+ nameStatus = HgfsServerGetShareInfo(srcFileName,
+ srcFileNameLength,
+ srcCaseFlags,
+ &shareInfo,
+ &localSymlinkName,
+ &localSymlinkNameLen);
+ if (nameStatus == HGFS_NAME_STATUS_COMPLETE) {
+ if (shareInfo.writePermissions ) {
+ /* Get the config options. */
+ nameStatus = HgfsServerPolicy_GetShareOptions(srcFileName, srcFileNameLength,
+ &configOptions);
+ if (nameStatus == HGFS_NAME_STATUS_COMPLETE) {
+ /* Prohibit symlink ceation if symlink following is enabled. */
+ if (HgfsServerPolicy_IsShareOptionSet(configOptions, HGFS_SHARE_FOLLOW_SYMLINKS)) {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ }
+ } else {
+ LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, srcFileName));
+ status = HgfsPlatformConvertFromNameStatus(nameStatus);
}
- break;
- }
- case HGFS_OP_OPEN_V2: {
- HgfsRequestOpenV2 *requestV2 = (HgfsRequestOpenV2 *)payload;
-
- if (!HgfsUnpackOpenPayloadV2(requestV2, payloadSize, openInfo)) {
- return FALSE;
+ } else {
+ status = HgfsPlatformFileExists(localSymlinkName);
+ if (status != 0) {
+ if (status == HGFS_ERROR_FILE_NOT_FOUND) {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ }
+ } else {
+ status = HGFS_ERROR_FILE_EXIST;
}
- break;
+ LOG(4, ("%s: failed access check, error %d\n", __FUNCTION__, status));
}
- case HGFS_OP_OPEN: {
- HgfsRequestOpen *requestV1 = (HgfsRequestOpen *)payload;
+ } else {
+ LOG(4, ("%s: symlink name access check failed\n", __FUNCTION__));
+ status = HgfsPlatformConvertFromNameStatus(nameStatus);
+ }
+ if (HGFS_ERROR_SUCCESS == status) {
+ /* Convert from CPName-lite to normal and NUL-terminate. */
+ memcpy(localTargetName, trgFileName, trgFileNameLength);
+ CPNameLite_ConvertFrom(localTargetName, trgFileNameLength, DIRSEPC);
+ localTargetName[trgFileNameLength] = '\0';
- if (!HgfsUnpackOpenPayloadV1(requestV1, payloadSize, openInfo)) {
- return FALSE;
- }
- break;
- }
- default:
- NOT_REACHED();
- return FALSE;
+ status = HgfsPlatformSymlinkCreate(localSymlinkName, localTargetName);
}
- return TRUE;
+ free(localSymlinkName);
+ return status;
}
+
/*
*-----------------------------------------------------------------------------
*
- * HgfsPackReplyHeaderV4 --
+ * HgfsServerSymlinkCreate --
*
- * Pack hgfs header that corresponds an incoming packet.
+ * Handle a SymlinkCreate request.
*
* Results:
* None.
*/
static void
-HgfsPackReplyHeaderV4(HgfsInternalStatus status, // IN: reply status
- uint32 payloadSize, // IN: size of the reply payload
- HgfsHeader const *packetIn, // IN: original incoming packet
- HgfsHeader *header) // OUT: outgoing packet header
-{
- memset(header, 0, sizeof *header);
- header->version = 1;
- header->dummy = HGFS_V4_LEGACY_OPCODE;
- header->packetSize = payloadSize + sizeof *header;
- header->headerSize = sizeof *header;
- header->requestId = packetIn->requestId;
- header->op = packetIn->op;
- header->status = HgfsConvertFromInternalStatus(status);
- header->flags = 0;
- header->information = status;
- header->sessionId = packetIn->sessionId;
+HgfsServerSymlinkCreate(HgfsInputParam *input) // IN: Input params
+{
+ HgfsInternalStatus status;
+ HgfsHandle srcFile;
+ char *srcFileName;
+ size_t srcFileNameLength;
+ uint32 srcCaseFlags;
+ Bool srcUseHandle;
+ HgfsHandle trgFile;
+ char *trgFileName;
+ size_t trgFileNameLength;
+ uint32 trgCaseFlags;
+ Bool trgUseHandle;
+ size_t replyPayloadSize = 0;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (HgfsUnpackSymlinkCreateRequest(input->payload, input->payloadSize, input->op,
+ &srcUseHandle, &srcFileName,
+ &srcFileNameLength, &srcCaseFlags, &srcFile,
+ &trgUseHandle, &trgFileName,
+ &trgFileNameLength, &trgCaseFlags, &trgFile)) {
+ /*
+ * We don't yet support file handle for this operation.
+ * Clients should retry using the file name.
+ */
+ if (srcUseHandle || trgUseHandle) {
+ LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
+ status = HGFS_ERROR_INVALID_PARAMETER;
+ } else {
+ status = HgfsSymlinkCreate(input->session, srcFileName, srcFileNameLength,
+ srcCaseFlags, trgFileName, trgFileNameLength,
+ trgCaseFlags);
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (!HgfsPackSymlinkCreateReply(input->packet, input->metaPacket, input->op,
+ &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ }
+ }
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
+ }
+
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsPackLegacyReplyHeader --
+ * HgfsServerSearchOpen --
*
- * Pack pre-V4 reply header.
+ * Handle a search open request.
*
* Results:
* None.
*-----------------------------------------------------------------------------
*/
-void
-HgfsPackLegacyReplyHeader(HgfsInternalStatus status, // IN: reply status
- HgfsHandle id, // IN: original packet id
- HgfsReply *header) // OUT: outgoing packet header
+static void
+HgfsServerSearchOpen(HgfsInputParam *input) // IN: Input params
{
- memset(header, 0, sizeof *header);
- header->status = HgfsConvertFromInternalStatus(status);
- header->id = id;
+ HgfsInternalStatus status;
+ size_t replyPayloadSize = 0;
+ char *dirName;
+ uint32 dirNameLength;
+ uint32 caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+ HgfsHandle search;
+ HgfsNameStatus nameStatus;
+ HgfsShareInfo shareInfo;
+ char *baseDir = NULL;
+ size_t baseDirLen;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (HgfsUnpackSearchOpenRequest(input->payload, input->payloadSize, input->op,
+ &dirName, &dirNameLength, &caseFlags)) {
+ nameStatus = HgfsServerGetShareInfo(dirName, dirNameLength, caseFlags, &shareInfo,
+ &baseDir, &baseDirLen);
+ status = HgfsPlatformSearchDir(nameStatus, dirName, dirNameLength, caseFlags,
+ &shareInfo, baseDir, baseDirLen,
+ input->session, &search);
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (!HgfsPackSearchOpenReply(input->packet, input->metaPacket, input->op, search,
+ &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ }
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
+ }
+
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsPackOpenReplyV3 --
+ * HgfsValidateRenameFile --
*
- * Pack hgfs open V3 reply payload to the HgfsReplyOpenV3 structure.
+ * Validates if the file can can participate in rename process either as
+ * as a source or as a target.
*
* Results:
- * None.
+ * HGFS_ERROR_SUCCESS if rename operation is allowed.
+ * Appropriate error code otherwise.
*
* Side effects:
- * None
+ * Allcates locaFileName which must be freed by the caller.
*
*-----------------------------------------------------------------------------
*/
-static void
-HgfsPackOpenReplyV3(HgfsFileOpenInfo *openInfo, // IN: open info struct
- HgfsReplyOpenV3 *reply) // OUT: size of packet
-{
- reply->file = openInfo->file;
- reply->reserved = 0;
- if (openInfo->mask & HGFS_OPEN_VALID_SERVER_LOCK) {
- reply->acquiredLock = openInfo->acquiredLock;
+HgfsInternalStatus
+HgfsValidateRenameFile(Bool useHandle, // IN:
+ HgfsHandle fileHandle, // IN:
+ char *cpName, // IN:
+ size_t cpNameLength, // IN:
+ uint32 caseFlags, // IN:
+ HgfsSessionInfo *session, // IN: Session info
+ fileDesc* descr, // OUT:
+ HgfsShareInfo *shareInfo, // OUT:
+ char **localFileName, // OUT:
+ size_t *localNameLength) // OUT:
+{
+ HgfsInternalStatus status;
+ Bool sharedFolderOpen = FALSE;
+ HgfsServerLock serverLock = HGFS_LOCK_NONE;
+ HgfsNameStatus nameStatus;
+
+
+ if (useHandle) {
+ status = HgfsPlatformGetFd(fileHandle, session, FALSE, descr);
+
+ if (HGFS_ERROR_SUCCESS != status) {
+ LOG(4, ("%s: could not map cached handle %d, error %u\n",
+ __FUNCTION__, fileHandle, status));
+ } else if (!HgfsHandle2FileNameMode(fileHandle, session, &shareInfo->writePermissions,
+ &shareInfo->readPermissions, localFileName,
+ localNameLength)) {
+ /*
+ * HgfsPlatformRename requires valid source file name even when file handle
+ * is specified.
+ * Also the name will be required to update the nodes on a successful
+ * rename operation.
+ */
+ LOG(4, ("%s: could not get file name for fd %d\n", __FUNCTION__,
+ *descr));
+ status = HGFS_ERROR_INVALID_HANDLE;
+ } else if (HgfsHandleIsSharedFolderOpen(fileHandle, session, &sharedFolderOpen) &&
+ sharedFolderOpen) {
+ LOG(4, ("%s: Cannot rename shared folder\n", __FUNCTION__));
+ status = HGFS_ERROR_ACCESS_DENIED;
+ }
} else {
- reply->acquiredLock = HGFS_LOCK_NONE;
+ nameStatus = HgfsServerGetShareInfo(cpName,
+ cpNameLength,
+ caseFlags,
+ shareInfo,
+ localFileName,
+ localNameLength);
+ if (HGFS_NAME_STATUS_COMPLETE != nameStatus) {
+ LOG(4, ("%s: access check failed\n", __FUNCTION__));
+ status = HgfsPlatformConvertFromNameStatus(nameStatus);
+ } else if (HgfsServerIsSharedFolderOnly(cpName, cpNameLength)) {
+ /* Guest OS is not allowed to rename shared folder. */
+ LOG(4, ("%s: Cannot rename shared folder\n", __FUNCTION__));
+ status = HGFS_ERROR_ACCESS_DENIED;
+ } else {
+ status = HGFS_ERROR_SUCCESS;
+ }
+ }
+
+ ASSERT(*localFileName != NULL || HGFS_ERROR_SUCCESS != status);
+
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (HgfsFileHasServerLock(*localFileName, session, &serverLock, descr)) {
+ /*
+ * XXX: Before renaming the file, check to see if we are holding
+ * an oplock on both the old and new files. If one of them is oplocked, and
+ * we commence with the rename, we'll trigger an oplock break that'll
+ * deadlock us. The client should be smart enough to break necessary oplocks
+ * on the source and target files before calling rename, so we'll return
+ * an error.
+ */
+
+ LOG (4, ("%s: File has an outstanding oplock. Client "
+ "should remove this oplock and try again.\n", __FUNCTION__));
+ status = HGFS_ERROR_PATH_BUSY;
+ }
}
+
+ return status;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsPackOpenV2Reply --
+ * HgfsServerRename --
*
- * Pack hgfs open V2 reply payload to the HgfsReplyOpenV3 structure.
+ * Handle a Rename request.
+ *
+ * Simply converts the new and old names to local filenames, calls
+ * platform specific function to rename/move the file, and returns an
+ * appropriate response to the driver.
*
* Results:
* None.
*/
static void
-HgfsPackOpenV2Reply(HgfsFileOpenInfo *openInfo, // IN: open info struct
- HgfsReplyOpenV2 *reply) // OUT: reply payload
-{
- reply->file = openInfo->file;
- if (openInfo->mask & HGFS_OPEN_VALID_SERVER_LOCK) {
- reply->acquiredLock = openInfo->acquiredLock;
+HgfsServerRename(HgfsInputParam *input) // IN: Input params
+{
+ char *utf8OldName = NULL;
+ size_t utf8OldNameLen;
+ char *utf8NewName = NULL;
+ size_t utf8NewNameLen;
+ char *cpOldName;
+ size_t cpOldNameLen;
+ char *cpNewName;
+ size_t cpNewNameLen;
+ HgfsInternalStatus status;
+ fileDesc srcFileDesc;
+ fileDesc targetFileDesc;
+ HgfsHandle srcFile;
+ HgfsHandle targetFile;
+ HgfsRenameHint hints;
+ uint32 oldCaseFlags;
+ uint32 newCaseFlags;
+ HgfsShareInfo shareInfo;
+ size_t replyPayloadSize = 0;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (HgfsUnpackRenameRequest(input->payload, input->payloadSize, input->op, &cpOldName,
+ &cpOldNameLen, &cpNewName, &cpNewNameLen,
+ &hints, &srcFile, &targetFile, &oldCaseFlags,
+ &newCaseFlags)) {
+ status = HgfsValidateRenameFile((hints & HGFS_RENAME_HINT_USE_SRCFILE_DESC) != 0,
+ srcFile,
+ cpOldName,
+ cpOldNameLen,
+ oldCaseFlags,
+ input->session,
+ &srcFileDesc,
+ &shareInfo,
+ &utf8OldName,
+ &utf8OldNameLen);
+ if (HGFS_ERROR_SUCCESS == status) {
+ /*
+ * Renaming a file requires both read and write permssions for the
+ * original file.
+ * However the error code must be different depending on the existence
+ * of the file with the same name.
+ */
+ if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+ status = HgfsPlatformFileExists(utf8OldName);
+ if (HGFS_ERROR_SUCCESS == status) {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ }
+ LOG(4, ("HgfsServerRename: failed access check, error %d\n", status));
+ } else {
+ status =
+ HgfsValidateRenameFile((hints & HGFS_RENAME_HINT_USE_TARGETFILE_DESC) != 0,
+ targetFile,
+ cpNewName,
+ cpNewNameLen,
+ newCaseFlags,
+ input->session,
+ &targetFileDesc,
+ &shareInfo,
+ &utf8NewName,
+ &utf8NewNameLen);
+ if (HGFS_ERROR_SUCCESS == status) {
+ /*
+ * Renaming a file requires both read and write permssions for
+ * the target directory.
+ * However the error code must be different depending on the existence
+ * of the target directory - if the destination directory exists then
+ * ERROR_ACCESS_DENIED should be returned regardless if the destination
+ * file exists.
+ */
+ if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+ status = HgfsPlatformFileExists(utf8NewName);
+ if (HGFS_ERROR_SUCCESS == status ||
+ HGFS_ERROR_FILE_NOT_FOUND == status) {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ }
+ LOG(4, ("HgfsServerRename: failed access check, error %d\n", status));
+ }
+ }
+ }
+ }
} else {
- reply->acquiredLock = HGFS_LOCK_NONE;
+ status = HGFS_ERROR_PROTOCOL;
+ }
+
+ /* If all pre-conditions are met go ahead with actual rename. */
+ if (HGFS_ERROR_SUCCESS == status) {
+ status = HgfsPlatformRename(utf8OldName, srcFileDesc, utf8NewName,
+ targetFileDesc, hints);
+ if (HGFS_ERROR_SUCCESS == status) {
+ /* Update all file nodes that refer to this file to contain the new name. */
+ HgfsUpdateNodeNames(utf8OldName, utf8NewName, input->session);
+ if (!HgfsPackRenameReply(input->packet, input->metaPacket, input->op,
+ &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ }
}
+
+ free(utf8OldName);
+ free(utf8NewName);
+
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsPackOpenV1Reply --
+ * HgfsServerCreateDir --
+ *
+ * Handle a CreateDir request.
*
- * Pack hgfs open V1 reply payload to the HgfsReplyOpenV3 structure.
+ * Simply converts to the local filename, calls platform specific
+ * code to create a directory, and returns an appropriate response to the driver.
*
* Results:
* None.
*/
static void
-HgfsPackOpenV1Reply(HgfsFileOpenInfo *openInfo, // IN: open info struct
- HgfsReplyOpen *reply) // OUT: reply payload
+HgfsServerCreateDir(HgfsInputParam *input) // IN: Input params
{
- reply->file = openInfo->file;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsAllocInitReply --
- *
- * Allocates hgfs reply packet and initializes its header.
- *
- * Results:
- * TRUE on success, FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsAllocInitReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- size_t payloadSize, // IN: payload size
- HgfsInternalStatus status, // IN: reply status
- char **packetOut, // OUT: allocated reply
- void **payload, // OUT: pointer to the reply payload
- size_t *packetSize, // OUT: size of the allocated packet
- HgfsSessionInfo *session) // IN: Session Info
-{
- HgfsRequest *request = (HgfsRequest *)packetIn;
- size_t replyPacketSize;
- size_t headerSize = 0; /* Replies prior to V3 do not have a header. */
- HgfsInternalStatus dummyStatus;
-
- if (HGFS_V4_LEGACY_OPCODE == request->op) {
- headerSize = sizeof(HgfsHeader);
- } else if (request->op < HGFS_OP_CREATE_SESSION_V4 &&
- request->op > HGFS_OP_RENAME_V2) {
- headerSize = sizeof(HgfsReply);
- }
- replyPacketSize = *packetSize = headerSize + payloadSize;
- *packetOut = HSPU_GetReplyPacket(packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, *packetSize, replyPacketSize, dummyStatus, exit);
-
- *payload = *packetOut + headerSize;
- if (HGFS_V4_LEGACY_OPCODE == request->op) {
- HgfsPackReplyHeaderV4(status,
- payloadSize,
- (HgfsHeader const *)packetIn,
- (HgfsHeader *)*packetOut);
- } else if (request->op < HGFS_OP_CREATE_SESSION_V4) {
- HgfsRequest const *request = (HgfsRequest const *)packetIn;
- HgfsPackLegacyReplyHeader(status, request->id, (HgfsReply *)*packetOut);
- }
-
- return TRUE;
-exit:
- return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackOpenReply --
- *
- * Pack hgfs open reply to the HgfsReplyOpen{V2} structure.
- *
- * Results:
- * Always TRUE.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsPackOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsFileOpenInfo *openInfo, // IN: open info struct
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session) // IN: Session info
-{
- Bool result;
- ASSERT(packetIn);
- ASSERT(openInfo);
- ASSERT(packetSize);
-
- *packetOut = NULL;
- *packetSize = 0;
-
- switch (openInfo->requestType) {
- case HGFS_OP_OPEN_V3: {
- HgfsReplyOpenV3 *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- if (result == FALSE) {
- goto error;
- }
- HgfsPackOpenReplyV3(openInfo, reply);
- break;
- }
- case HGFS_OP_OPEN_V2: {
- HgfsReplyOpenV2 *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- if (result == FALSE) {
- goto error;
- }
- HgfsPackOpenV2Reply(openInfo, reply);
- break;
- }
- case HGFS_OP_OPEN: {
- HgfsReplyOpen *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- if (result == FALSE) {
- goto error;
- }
- HgfsPackOpenV1Reply(openInfo, reply);
- break;
- }
- default:
- goto error;
- }
-
- return TRUE;
-error:
- return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackClosePayload --
- *
- * Unpack hgfs close payload to get the handle which need to be closed.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackClosePayload(HgfsRequestClose *request, // IN: payload
- size_t payloadSize, // IN: payload size
- HgfsHandle* file) // OUT: HGFS handle to close
-{
- LOG(4, ("%s: HGFS_OP_CLOSE\n", __FUNCTION__));
- if (payloadSize >= sizeof *request) {
- *file = request->file;
- return TRUE;
- }
- return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackClosePayloadV3 --
- *
- * Unpack hgfs close payload V3 to get the handle which need to be closed.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackClosePayloadV3(HgfsRequestCloseV3 *requestV3, // IN: payload
- size_t payloadSize, // IN: payload size
- HgfsHandle* file) // OUT: HGFS handle to close
-{
- LOG(4, ("%s: HGFS_OP_CLOSE_V3\n", __FUNCTION__));
- if (payloadSize >= sizeof *requestV3) {
- *file = requestV3->file;
- return TRUE;
- }
- return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackCloseRequest --
- *
- * Unpack hgfs close request to get the handle to close.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackCloseRequest(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- HgfsOp *op, // OUT: request type
- HgfsHandle *file) // OUT: Handle to close
-{
- void const *payload;
- size_t payloadSize;
-
- ASSERT(packetIn);
-
- if (!HgfsParseRequest(packetIn, packetSize, &payload, &payloadSize, op)) {
- return FALSE;
- }
-
- switch (*op) {
- case HGFS_OP_CLOSE_V3: {
- HgfsRequestCloseV3 *requestV3 = (HgfsRequestCloseV3 *)payload;
-
- if (!HgfsUnpackClosePayloadV3(requestV3, payloadSize, file)) {
- return FALSE;
- }
- break;
- }
- case HGFS_OP_CLOSE: {
- HgfsRequestClose *requestV1 = (HgfsRequestClose *)payload;
-
- if (!HgfsUnpackClosePayload(requestV1, payloadSize, file)) {
- return FALSE;
+ HgfsInternalStatus status;
+ HgfsNameStatus nameStatus;
+ HgfsCreateDirInfo info;
+ char *utf8Name;
+ size_t utf8NameLen;
+ size_t replyPayloadSize = 0;
+ HgfsShareInfo shareInfo;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (HgfsUnpackCreateDirRequest(input->payload, input->payloadSize,
+ input->op, &info)) {
+ nameStatus = HgfsServerGetShareInfo(info.cpName, info.cpNameSize, info.caseFlags,
+ &shareInfo, &utf8Name, &utf8NameLen);
+ if (HGFS_NAME_STATUS_COMPLETE == nameStatus) {
+ ASSERT(utf8Name);
+
+ LOG(4, ("%s: making dir \"%s\"", __FUNCTION__, utf8Name));
+ /*
+ * For read-only shares we must never attempt to create a directory.
+ * However the error code must be different depending on the existence
+ * of the file with the same name.
+ */
+ if (shareInfo.writePermissions) {
+ status = HgfsPlatformCreateDir(&info, utf8Name);
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (!HgfsPackCreateDirReply(input->packet, input->metaPacket, info.requestType,
+ &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_PROTOCOL;
+ }
+ }
+ } else {
+ status = HgfsPlatformFileExists(utf8Name);
+ if (HGFS_ERROR_SUCCESS == status) {
+ status = HGFS_ERROR_FILE_EXIST;
+ } else if (HGFS_ERROR_FILE_NOT_FOUND == status) {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ }
}
- break;
- }
- default:
- NOT_REACHED();
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackCloseReply --
- *
- * Pack hgfs close reply to the HgfsReplyClose(V3) structure.
- *
- * Results:
- * TRUE on success, FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsPackCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session) // IN: Session Info
-{
- Bool result;
- ASSERT(packetIn);
- ASSERT(packetSize);
-
- *packetOut = NULL;
- *packetSize = 0;
-
- switch (op) {
- case HGFS_OP_CLOSE_V3: {
- HgfsReplyCloseV3 *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- case HGFS_OP_CLOSE: {
- HgfsReplyClose *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- default:
- result = FALSE;
- NOT_REACHED();
- }
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackSearchClosePayload --
- *
- * Unpack hgfs search close payload to get the search handle which need to be closed.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackSearchClosePayload(HgfsRequestSearchClose *request, // IN: payload
- size_t payloadSize, // IN: payload size
- HgfsHandle* search) // OUT: search to close
-{
- LOG(4, ("%s: HGFS_OP_SEARCH_CLOSE\n", __FUNCTION__));
- if (payloadSize >= sizeof *request) {
- *search = request->search;
- return TRUE;
- }
- return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackClosePayloadV3 --
- *
- * Unpack hgfs search close payload V3 to get the search handle which need to
- * be closed.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackSearchClosePayloadV3(HgfsRequestSearchCloseV3 *requestV3, // IN: payload
- size_t payloadSize, // IN: payload size
- HgfsHandle* search) // OUT: search
-{
- LOG(4, ("%s: HGFS_OP_SEARCH_CLOSE_V3\n", __FUNCTION__));
- if (payloadSize >= sizeof *requestV3) {
- *search = requestV3->search;
- return TRUE;
- }
- return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackSearchCloseRequest --
- *
- * Unpack hgfs search close request to get the search handle.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackSearchCloseRequest(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- HgfsOp *op, // OUT: request type
- HgfsHandle *search) // OUT: search to close
-{
- void const *payload;
- size_t payloadSize;
-
- ASSERT(packetIn);
-
- if (!HgfsParseRequest(packetIn, packetSize, &payload, &payloadSize, op)) {
- return FALSE;
- }
-
- switch (*op) {
- case HGFS_OP_SEARCH_CLOSE_V3: {
- HgfsRequestSearchCloseV3 *requestV3 = (HgfsRequestSearchCloseV3 *)payload;
-
- if (!HgfsUnpackSearchClosePayloadV3(requestV3, payloadSize, search)) {
- return FALSE;
- }
- break;
- }
- case HGFS_OP_SEARCH_CLOSE: {
- HgfsRequestSearchClose *requestV1 = (HgfsRequestSearchClose *)payload;
-
- if (!HgfsUnpackSearchClosePayload(requestV1, payloadSize, search)) {
- return FALSE;
- }
- break;
- }
- default:
- NOT_REACHED();
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackSearchCloseReply --
- *
- * Pack hgfs SearchClose reply into a HgfsReplySearchClose(V3) structure.
- *
- * Results:
- * TRUE on success, FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsPackSearchCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session) // IN: Session Info
-{
- Bool result;
- ASSERT(packetIn);
- ASSERT(packetSize);
-
- *packetOut = NULL;
- *packetSize = 0;
-
- switch (op) {
- case HGFS_OP_SEARCH_CLOSE_V3: {
- HgfsReplyCloseV3 *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- case HGFS_OP_SEARCH_CLOSE: {
- HgfsReplyClose *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- default:
- NOT_REACHED();
- result = FALSE;
- }
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackFileName --
- *
- * Unpack HgfsFileName into a pointer to a CPName and size of the name.
- * Verifies that input buffer has enough space to hold the name.
- *
- * Results:
- * TRUE on success, FALSE on failure (buffer too small).
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackFileName(HgfsFileName *name, // IN: file name
- size_t maxNameSize, // IN: space allocated for the name
- char **cpName, // OUT: CP name
- size_t *cpNameSize) // OUT: CP name size
-{
- /*
- * The request file name length is user-provided, so this test must be
- * carefully written to prevent wraparounds.
- */
- if (name->length > maxNameSize) {
- /* The input packet is smaller than the request. */
- return FALSE;
- }
- *cpName = name->name;
- *cpNameSize = name->length;
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackFileNameV3 --
- *
- * Unpack HgfsFileNameV3 into a pointer to a CPName and size of the name
- * or into file handle.
- * Verifies that input buffer has enough space to hold the name.
- *
- * Results:
- * TRUE on success, FALSE on failure (buffer too small).
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackFileNameV3(HgfsFileNameV3 *name, // IN: file name
- size_t maxNameSize, // IN: space allocated for the name
- Bool *useHandle, // OUT: file name or handle returned?
- char **cpName, // OUT: CP name
- size_t *cpNameSize, // OUT: CP name size
- HgfsHandle *file, // OUT: HGFS file handle
- uint32 *caseFlags) // OUT: case-sensitivity flags
-{
- /*
- * If we've been asked to reuse a handle, we don't need to look at, let
- * alone test the filename or its length.
- */
- if (name->flags & HGFS_FILE_NAME_USE_FILE_DESC) {
- *file = name->fid;
- *cpName = NULL;
- *cpNameSize = 0;
- *caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
- *useHandle = TRUE;
- } else {
- /*
- * The request file name length is user-provided, so this test must be
- * carefully written to prevent wraparounds.
- */
- if (name->length > maxNameSize) {
- /* The input packet is smaller than the request */
- return FALSE;
- }
- *file = HGFS_INVALID_HANDLE;
- *cpName = name->name;
- *cpNameSize = name->length;
- *caseFlags = name->caseType;
- *useHandle = FALSE;
- }
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackDeletePayloadV3 --
- *
- * Unpack hgfs delete request V3 payload and initialize a corresponding
- * HgfsHandle or file name to tell us which to delete. Hints
- * holds flags to specify a handle or name for the file or
- * directory to delete.
- *
- * Since the structure of the get delete request packet is the same
- * for Delete File or Directory of the protocol, code is identical for
- * both operations.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackDeletePayloadV3(HgfsRequestDeleteV3 *requestV3, // IN: request payload
- size_t payloadSize, // IN: payload size
- char **cpName, // OUT: cpName
- size_t *cpNameSize, // OUT: cpName size
- HgfsDeleteHint *hints, // OUT: delete hints
- HgfsHandle *file, // OUT: file handle
- uint32 *caseFlags) // OUT: case-sensitivity flags
-{
- Bool result;
- Bool useHandle;
-
- if (payloadSize < sizeof *requestV3) {
- return FALSE;
- }
-
- *hints = requestV3->hints;
-
- result = HgfsUnpackFileNameV3(&requestV3->fileName,
- payloadSize - sizeof *requestV3,
- &useHandle,
- cpName,
- cpNameSize,
- file,
- caseFlags);
- if (useHandle) {
- *hints |= HGFS_DELETE_HINT_USE_FILE_DESC;
- }
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackDeletePayloadV2 --
- *
- * Unpack hgfs delete request V2 payload and initialize a corresponding
- * HgfsHandle or file name to tell us which to delete. Hints
- * holds flags to specify a handle or name for the file or
- * directory to delete.
- *
- * Since the structure of the get delete request packet is the same
- * for Delete File or Directory of the protocol, code is identical for
- * both operations.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackDeletePayloadV2(HgfsRequestDeleteV2 *requestV2, // IN: request payload
- size_t payloadSize, // IN: payload size
- char **cpName, // OUT: cpName
- size_t *cpNameSize, // OUT: cpName size
- HgfsDeleteHint *hints, // OUT: delete hints
- HgfsHandle *file) // OUT: file handle
-{
- Bool result = TRUE;
-
- /* Enforced by the dispatch function. */
- ASSERT(payloadSize >= sizeof *requestV2);
-
- *file = HGFS_INVALID_HANDLE;
- *hints = requestV2->hints;
-
- /*
- * If we've been asked to reuse a handle, we don't need to look at, let
- * alone test the filename or its length.
- */
-
- if (requestV2->hints & HGFS_DELETE_HINT_USE_FILE_DESC) {
- *file = requestV2->file;
- *cpName = NULL;
- *cpNameSize = 0;
- } else {
- result = HgfsUnpackFileName(&requestV2->fileName,
- payloadSize - sizeof *requestV2,
- cpName,
- cpNameSize);
- }
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackDeletePayloadV1 --
- *
- * Unpack hgfs delete request V1 payload and initialize a corresponding
- * file name to tell us which to delete.
- *
- * Since the structure of the get delete request packet is the same
- * for Delete File or Directory of the protocol, code is identical for
- * both operations.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackDeletePayloadV1(HgfsRequestDelete *requestV1, // IN: request payload
- size_t payloadSize, // IN: payload size
- char **cpName, // OUT: cpName
- size_t *cpNameSize) // OUT: cpName size
-{
- return HgfsUnpackFileName(&requestV1->fileName,
- payloadSize - sizeof *requestV1,
- cpName,
- cpNameSize);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackDeleteRequest --
- *
- * Unpack hgfs delete request and initialize a corresponding
- * HgfsHandle or file name to tell us which to delete. Hints
- * holds flags to specify a handle or name for the file or
- * directory to delete.
- *
- * Since the structure of the get delete request packet is the same
- * for Delete File or Directory of the protocol, code is identical for
- * both operations.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackDeleteRequest(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- HgfsOp *op, // OUT: requested operation
- char **cpName, // OUT: cpName
- size_t *cpNameSize, // OUT: cpName size
- HgfsDeleteHint *hints, // OUT: delete hints
- HgfsHandle *file, // OUT: file handle
- uint32 *caseFlags) // OUT: case-sensitivity flags
-{
- void const *payload;
- size_t payloadSize;
-
- ASSERT(packetIn);
- ASSERT(cpName);
- ASSERT(cpNameSize);
- ASSERT(file);
- ASSERT(hints);
- ASSERT(caseFlags);
-
- if (!HgfsParseRequest(packetIn, packetSize, &payload, &payloadSize, op)) {
- return FALSE;
- }
-
- *caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
- *hints = 0;
- *file = HGFS_INVALID_HANDLE;
-
- switch (*op) {
- case HGFS_OP_DELETE_FILE_V3:
- case HGFS_OP_DELETE_DIR_V3: {
- HgfsRequestDeleteV3 *requestV3 = (HgfsRequestDeleteV3 *)payload;
-
- if (!HgfsUnpackDeletePayloadV3(requestV3,
- payloadSize,
- cpName,
- cpNameSize,
- hints,
- file,
- caseFlags)) {
- return FALSE;
- }
- break;
- }
- case HGFS_OP_DELETE_FILE_V2:
- case HGFS_OP_DELETE_DIR_V2: {
- HgfsRequestDeleteV2 *requestV2 = (HgfsRequestDeleteV2 *)payload;
-
- if (!HgfsUnpackDeletePayloadV2(requestV2,
- payloadSize,
- cpName,
- cpNameSize,
- hints,
- file)) {
- return FALSE;
- }
- break;
- }
- case HGFS_OP_DELETE_FILE:
- case HGFS_OP_DELETE_DIR: {
- HgfsRequestDelete *requestV1 = (HgfsRequestDelete *)payload;
-
- if (!HgfsUnpackDeletePayloadV1(requestV1,
- payloadSize,
- cpName,
- cpNameSize)) {
- return FALSE;
- }
- break;
- }
- default:
- NOT_REACHED();
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackDeleteReply --
- *
- * Pack hgfs delete reply.
- * Since the structure of the delete reply packet hasn't changed in
- * version 2 of the protocol, HgfsReplyDeleteV2 is identical to
- * HgfsReplyDelete. So use HgfsReplyDelete type to access packetIn to
- * keep the code simple.
- *
- * Results:
- * TRUE if valid op version reply filled, FALSE otherwise.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsPackDeleteReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: requested operation
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session) // IN: Session Info
-{
- Bool result = TRUE;
- ASSERT(packetIn);
- ASSERT(packetSize);
-
- *packetOut = NULL;
- *packetSize = 0;
-
- /* No reply payload, just header. */
- switch (op) {
- case HGFS_OP_DELETE_FILE_V3:
- case HGFS_OP_DELETE_DIR_V3: {
- HgfsReplyDeleteV3 *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- case HGFS_OP_DELETE_FILE_V2:
- case HGFS_OP_DELETE_FILE:
- case HGFS_OP_DELETE_DIR_V2:
- case HGFS_OP_DELETE_DIR: {
- HgfsReplyDelete *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- default:
- LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, op));
- result = FALSE;
- NOT_REACHED();
- break;
- }
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackRenamePayloadV3 --
- *
- * Unpack hgfs rename request V3 payload and initialize a corresponding
- * HgfsHandles or file names to tell us old and new names/handles. Hints
- * holds flags to specify a handle or name for the file or
- * directory to rename.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackRenamePayloadV3(HgfsRequestRenameV3 *requestV3, // IN: request payload
- size_t payloadSize, // IN: payload size
- char **cpOldName, // OUT: rename src
- size_t *cpOldNameLen, // OUT: rename src size
- char **cpNewName, // OUT: rename dst
- size_t *cpNewNameLen, // OUT: rename dst size
- HgfsRenameHint *hints, // OUT: rename hints
- HgfsHandle *srcFile, // OUT: src file handle
- HgfsHandle *targetFile, // OUT: target file handle
- uint32 *oldCaseFlags, // OUT: source case flags
- uint32 *newCaseFlags) // OUT: dest. case flags
-{
- size_t extra;
- HgfsFileNameV3 *newName;
- Bool useHandle;
-
- LOG(4, ("%s: HGFS_OP_RENAME_V3\n", __FUNCTION__));
-
- if (payloadSize < sizeof *requestV3) {
- return FALSE;
- }
- extra = payloadSize - sizeof *requestV3;
-
- *hints = requestV3->hints;
-
- /*
- * Get the old and new filenames from the request.
- *
- * Getting the new filename is somewhat inconvenient, because we
- * don't know where request->newName actually starts, thanks to the
- * fact that request->oldName is of variable length. We get around
- * this by using an HgfsFileName*, assigning it to the correct address
- * just after request->oldName ends, and using that to access the
- * new name.
- */
-
- /*
- * If we've been asked to reuse a handle, we don't need to look at, let
- * alone test the filename or its length. This applies to the source
- * and the target.
- */
- if (!HgfsUnpackFileNameV3(&requestV3->oldName,
- extra,
- &useHandle,
- cpOldName,
- cpOldNameLen,
- srcFile,
- oldCaseFlags)) {
- return FALSE;
- }
- if (useHandle) {
- *hints |= HGFS_RENAME_HINT_USE_SRCFILE_DESC;
- newName = &requestV3->newName;
- } else {
- newName = (HgfsFileNameV3 *)(requestV3->oldName.name + 1 + *cpOldNameLen);
- extra -= *cpOldNameLen;
- }
- if (!HgfsUnpackFileNameV3(newName,
- extra,
- &useHandle,
- cpNewName,
- cpNewNameLen,
- targetFile,
- newCaseFlags)) {
- return FALSE;
- }
- if (useHandle) {
- *hints |= HGFS_RENAME_HINT_USE_TARGETFILE_DESC;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackRenamePayloadV2 --
- *
- * Unpack hgfs rename request V2 payload and initialize a corresponding
- * HgfsHandle or file name to tell us which to delete. Hints
- * holds flags to specify a handle or name for the file or
- * directory to rename.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackRenamePayloadV2(HgfsRequestRenameV2 *requestV2, // IN: request payload
- size_t payloadSize, // IN: payload size
- char **cpOldName, // OUT: rename src
- size_t *cpOldNameLen, // OUT: rename src size
- char **cpNewName, // OUT: rename dst
- size_t *cpNewNameLen, // OUT: rename dst size
- HgfsRenameHint *hints, // OUT: rename hints
- HgfsHandle *srcFile, // OUT: src file handle
- HgfsHandle *targetFile) // OUT: target file handle
-{
- HgfsFileName *newName;
- size_t extra;
-
- /* Enforced by the dispatch function. */
- if (payloadSize < sizeof *requestV2) {
- return FALSE;
- }
- extra = payloadSize - sizeof *requestV2;
-
- *hints = requestV2->hints;
-
- /*
- * If we've been asked to reuse a handle, we don't need to look at, let
- * alone test the filename or its length. This applies to the source
- * and the target.
- */
-
- if (*hints & HGFS_RENAME_HINT_USE_SRCFILE_DESC) {
- *srcFile = requestV2->srcFile;
- *cpOldName = NULL;
- *cpOldNameLen = 0;
- } else {
- if (!HgfsUnpackFileName(&requestV2->oldName,
- extra,
- cpOldName,
- cpOldNameLen)) {
- return FALSE;
- }
- extra -= *cpOldNameLen;
- }
-
- if (*hints & HGFS_RENAME_HINT_USE_TARGETFILE_DESC) {
- *targetFile = requestV2->targetFile;
- *cpNewName = NULL;
- *cpNewNameLen = 0;
- } else {
- newName = (HgfsFileName *)((char *)(&requestV2->oldName + 1)
- + *cpOldNameLen);
- if (!HgfsUnpackFileName(newName,
- extra,
- cpNewName,
- cpNewNameLen)) {
- return FALSE;
- }
- }
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackRenamePayloadV1 --
- *
- * Unpack hgfs rename request V1 payload and initialize a corresponding
- * old and new file names.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackRenamePayloadV1(HgfsRequestRename *requestV1, // IN: request payload
- size_t payloadSize, // IN: payload size
- char **cpOldName, // OUT: rename src
- size_t *cpOldNameLen, // OUT: rename src size
- char **cpNewName, // OUT: rename dst
- size_t *cpNewNameLen) // OUT: rename dst size
-{
- HgfsFileName *newName;
- uint32 extra;
-
- if (payloadSize < sizeof *requestV1) {
- return FALSE;
- }
-
- extra = payloadSize - sizeof *requestV1;
-
- if (!HgfsUnpackFileName(&requestV1->oldName,
- extra,
- cpOldName,
- cpOldNameLen)) {
- return FALSE;
- }
-
- extra -= requestV1->oldName.length;
- newName = (HgfsFileName *)((char *)(&requestV1->oldName + 1)
- + requestV1->oldName.length);
-
- return HgfsUnpackFileName(newName, extra, cpNewName, cpNewNameLen);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackRenameRequest --
- *
- * Unpack hgfs rename request and initialize a corresponding
- * HgfsHandle or file name to tell us which to rename. Hints
- * holds flags to specify a handle or name for the file or
- * directory to rename.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- HgfsOp *op, // OUT: requested operation
- char **cpOldName, // OUT: rename src
- size_t *cpOldNameLen, // OUT: rename src size
- char **cpNewName, // OUT: rename dst
- size_t *cpNewNameLen, // OUT: rename dst size
- HgfsRenameHint *hints, // OUT: rename hints
- HgfsHandle *srcFile, // OUT: src file handle
- HgfsHandle *targetFile, // OUT: target file handle
- uint32 *oldCaseFlags, // OUT: source case-sensitivity flags
- uint32 *newCaseFlags) // OUT: dest. case-sensitivity flags
-{
- void const *payload;
- size_t payloadSize;
-
- ASSERT(packetIn);
- ASSERT(cpOldName);
- ASSERT(cpOldNameLen);
- ASSERT(cpNewName);
- ASSERT(cpNewNameLen);
- ASSERT(srcFile);
- ASSERT(targetFile);
- ASSERT(hints);
- ASSERT(oldCaseFlags);
- ASSERT(newCaseFlags);
-
- if (!HgfsParseRequest(packetIn, packetSize, &payload, &payloadSize, op)) {
- return FALSE;
- }
-
- /* Default values for legacy requests. */
- *oldCaseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
- *newCaseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
- *hints = 0;
-
- switch (*op) {
- case HGFS_OP_RENAME_V3:
- {
- HgfsRequestRenameV3 *requestV3 = (HgfsRequestRenameV3 *)payload;
-
- if (!HgfsUnpackRenamePayloadV3(requestV3,
- payloadSize,
- cpOldName,
- cpOldNameLen,
- cpNewName,
- cpNewNameLen,
- hints,
- srcFile,
- targetFile,
- oldCaseFlags,
- newCaseFlags)) {
- return FALSE;
- }
- break;
- }
- case HGFS_OP_RENAME_V2:
- {
- HgfsRequestRenameV2 *requestV2 = (HgfsRequestRenameV2 *)payload;
-
- if (!HgfsUnpackRenamePayloadV2(requestV2,
- payloadSize,
- cpOldName,
- cpOldNameLen,
- cpNewName,
- cpNewNameLen,
- hints,
- srcFile,
- targetFile)) {
- return FALSE;
- }
- break;
- }
-
- case HGFS_OP_RENAME:
- {
- HgfsRequestRename *requestV1 = (HgfsRequestRename *)payload;
-
- if (!HgfsUnpackRenamePayloadV1(requestV1,
- payloadSize,
- cpOldName,
- cpOldNameLen,
- cpNewName,
- cpNewNameLen)) {
- return FALSE;
- }
- break;
- }
-
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackRenameReply --
- *
- * Pack hgfs rename reply.
- * Since the structure of the rename reply packet hasn't changed in
- * version 2 of the protocol, HgfsReplyRenameV2 is identical to
- * HgfsReplyRename. So use HgfsReplyRename type to access packetIn to
- * keep the code simple.
- *
- * Results:
- * TRUE if valid op and reply set, FALSE otherwise.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsPackRenameReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: requested operation
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session) // IN: Session Info
-{
- Bool result = TRUE;
- ASSERT(packetIn);
- ASSERT(packetSize);
-
- *packetOut = NULL;
- *packetSize = 0;
-
- switch (op) {
- case HGFS_OP_RENAME_V3: {
- HgfsReplyRenameV3 *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- case HGFS_OP_RENAME_V2:
- case HGFS_OP_RENAME: {
- HgfsReplyRename *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- default:
- LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, op));
- result = FALSE;
- NOT_REACHED();
- break;
- }
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackGetattrPayloadV3 --
- *
- * Unpack hgfs get attr request V3 payload and initialize a corresponding
- * HgfsHandle or file name to tell us which file to get attributes. Hints
- * holds flags to specify a handle or name for the file or
- * directory to get attributes.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackGetattrPayloadV3(HgfsRequestGetattrV3 *requestV3,// IN: request payload
- size_t payloadSize, // IN: payload size
- char **cpName, // OUT: cpName
- size_t *cpNameSize, // OUT: cpName size
- HgfsAttrHint *hints, // OUT: getattr hints
- HgfsHandle *file, // OUT: file handle
- uint32 *caseFlags) // OUT: case-sensitivity flags
-{
- Bool result;
- Bool useHandle;
-
- if (payloadSize < sizeof *requestV3) {
- return FALSE;
- }
-
- *hints = requestV3->hints;
-
- result = HgfsUnpackFileNameV3(&requestV3->fileName,
- payloadSize - sizeof *requestV3,
- &useHandle,
- cpName,
- cpNameSize,
- file,
- caseFlags);
- if (useHandle) {
- *hints |= HGFS_ATTR_HINT_USE_FILE_DESC;
- }
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackGetattrPayloadV2 --
- *
- * Unpack hgfs Getattr request V2 payload and initialize a corresponding
- * HgfsHandle or file name to tell us which to get attributes. Hints
- * holds flags to specify a handle or name for the file or
- * directory to get attributes.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackGetattrPayloadV2(HgfsRequestGetattrV2 *requestV2,// IN: request payload
- size_t payloadSize, // IN: payload size
- char **cpName, // OUT: cpName
- size_t *cpNameSize, // OUT: cpName size
- HgfsAttrHint *hints, // OUT: delete hints
- HgfsHandle *file) // OUT: file handle
-{
- Bool result = TRUE;
-
- if (payloadSize < sizeof *requestV2) {
- return FALSE;
- }
-
-
- *file = HGFS_INVALID_HANDLE;
- *hints = requestV2->hints;
-
- /*
- * If we've been asked to reuse a handle, we don't need to look at, let
- * alone test the filename or its length.
- */
-
- if (requestV2->hints & HGFS_ATTR_HINT_USE_FILE_DESC) {
- *file = requestV2->file;
- *cpName = NULL;
- *cpNameSize = 0;
- } else {
- result = HgfsUnpackFileName(&requestV2->fileName,
- payloadSize - sizeof *requestV2,
- cpName,
- cpNameSize);
- }
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackGetattrPayloadV1 --
- *
- * Unpack hgfs getattr request V1 payload and initialize a corresponding
- * file name to tell us which to get attributes.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackGetattrPayloadV1(HgfsRequestGetattr *requestV1, // IN: request payload
- size_t payloadSize, // IN: payload size
- char **cpName, // OUT: cpName
- size_t *cpNameSize) // OUT: cpName size
-{
- return HgfsUnpackFileName(&requestV1->fileName,
- payloadSize - sizeof *requestV1,
- cpName,
- cpNameSize);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackAttrV2 --
- *
- * Packs attr version 2 reply structure.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-HgfsPackAttrV2(HgfsFileAttrInfo *attr, // IN: attr stucture
- HgfsAttrV2 *attr2) // OUT: attr in payload
-{
- attr2->mask = attr->mask;
- attr2->type = attr->type;
- attr2->size = attr->size;
- attr2->creationTime = attr->creationTime;
- attr2->accessTime = attr->accessTime;
- attr2->writeTime = attr->writeTime;
- attr2->attrChangeTime = attr->attrChangeTime;
- attr2->specialPerms = attr->specialPerms;
- attr2->ownerPerms = attr->ownerPerms;
- attr2->groupPerms = attr->groupPerms;
- attr2->otherPerms = attr->otherPerms;
- attr2->flags = attr->flags;
- attr2->allocationSize = attr->allocationSize;
- attr2->userId = attr->userId;
- attr2->groupId = attr->groupId;
- attr2->hostFileId = attr->hostFileId;
- attr2->volumeId = attr->volumeId;
- attr2->effectivePerms = attr->effectivePerms;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackAttrV2 --
- *
- * Unpacks attr version 2 reply structure.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-HgfsUnpackAttrV2(HgfsAttrV2 *attr2, // IN: attr in payload
- HgfsFileAttrInfo *attr) // OUT: attr stucture
-{
- attr->mask = attr2->mask;
- attr->type = attr2->type;
- attr->size = attr2->size;
- attr->creationTime = attr2->creationTime;
- attr->accessTime = attr2->accessTime;
- attr->writeTime = attr2->writeTime;
- attr->attrChangeTime = attr2->attrChangeTime;
- attr->specialPerms = attr2->specialPerms;
- attr->ownerPerms = attr2->ownerPerms;
- attr->groupPerms = attr2->groupPerms;
- attr->otherPerms = attr2->otherPerms;
- attr->flags = attr2->flags;
- attr->allocationSize = attr2->allocationSize;
- attr->userId = attr2->userId;
- attr->groupId = attr2->groupId;
- attr->hostFileId = attr2->hostFileId;
- attr->volumeId = attr2->volumeId;
- attr->effectivePerms = attr2->effectivePerms;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsInitFileAttr --
- *
- * Initializes HgfsFileAttrInfo structure.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-HgfsInitFileAttr(HgfsOp op, // IN: request type
- HgfsFileAttrInfo *attr) // OUT: attr stucture
-{
- /* Initialize all fields with 0. */
- memset(attr, 0, sizeof *attr);
-
- /* Explicitly initialize fields which need it. */
- attr->requestType = op;
- attr->mask = HGFS_ATTR_VALID_NONE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackGetattrReplyPayloadV3 --
- *
- * Packs Getattr V3 reply payload.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-HgfsPackGetattrReplyPayloadV3(HgfsFileAttrInfo *attr, // IN: attr stucture
- const char *utf8TargetName, // IN: optional target name
- uint32 utf8TargetNameLen, // IN: file name length
- HgfsReplyGetattrV3 *reply) // OUT: payload
-{
- LOG(4, ("%s: attr type: %u\n", __FUNCTION__, reply->attr.type));
-
- HgfsPackAttrV2(attr, &reply->attr);
- reply->reserved = 0;
-
- if (utf8TargetName) {
- memcpy(reply->symlinkTarget.name, utf8TargetName, utf8TargetNameLen);
- CPNameLite_ConvertTo(reply->symlinkTarget.name, utf8TargetNameLen,
- DIRSEPC);
- } else {
- ASSERT(utf8TargetNameLen == 0);
- }
- reply->symlinkTarget.length = utf8TargetNameLen;
- reply->symlinkTarget.name[utf8TargetNameLen] = '\0';
- reply->symlinkTarget.flags = 0;
- reply->symlinkTarget.fid = 0;
- reply->symlinkTarget.caseType = HGFS_FILE_NAME_DEFAULT_CASE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackGetattrReplyPayloadV2 --
- *
- * Packs rename reply payload V2 requests.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-HgfsPackGetattrReplyPayloadV2(HgfsHandle id, // IN: id of the request
- HgfsInternalStatus status, // IN: error code
- HgfsFileAttrInfo *attr, // IN: attr stucture
- const char *utf8TargetName, // IN: optional target name
- uint32 utf8TargetNameLen, // IN: file name length
- HgfsReplyGetattrV2 *reply) // OUT: payload
-{
- reply->header.status = HgfsConvertFromInternalStatus(status);
- reply->header.id = id;
-
- HgfsPackAttrV2(attr, &reply->attr);
-
- if (utf8TargetName) {
- memcpy(reply->symlinkTarget.name, utf8TargetName, utf8TargetNameLen);
- CPNameLite_ConvertTo(reply->symlinkTarget.name, utf8TargetNameLen,
- DIRSEPC);
- } else {
- ASSERT(utf8TargetNameLen == 0);
- }
- reply->symlinkTarget.length = utf8TargetNameLen;
- reply->symlinkTarget.name[utf8TargetNameLen] = '\0';
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackGetattrReplyPayloadV1 --
- *
- * Packs rename reply payload for V1 requests.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-HgfsPackGetattrReplyPayloadV1(HgfsHandle id, // IN: id of the request
- HgfsInternalStatus status, // IN: error code
- HgfsFileAttrInfo *attr, // IN: attr stucture
- HgfsReplyGetattr *reply) // OUT: reply info
-{
- reply->header.status = HgfsConvertFromInternalStatus(status);
- reply->header.id = id;
-
- /* In GetattrV1, symlinks are treated as regular files. */
- if (attr->type == HGFS_FILE_TYPE_SYMLINK) {
- reply->attr.type = HGFS_FILE_TYPE_REGULAR;
- } else {
- reply->attr.type = attr->type;
- }
-
- reply->attr.size = attr->size;
- reply->attr.creationTime = attr->creationTime;
- reply->attr.accessTime = attr->accessTime;
- reply->attr.writeTime = attr->writeTime;
- reply->attr.attrChangeTime = attr->attrChangeTime;
- reply->attr.permissions = attr->ownerPerms;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsValidateReplySize --
- *
- * Verify if the size of a reply does not exceed maximum supported size.
- *
- * Results:
- * TRUE if the packet size is acceptable, FALSE otherwise.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsValidateReplySize(char const *packetIn,
- HgfsOp op,
- size_t packetSize)
-{
- HgfsRequest *request = (HgfsRequest *)packetIn;
- /*
- * XXX:
- * At the moment assume that V4 protocol does not impose any restrictions
- * on the packet size.
- * May need to review later.
- */
- if (HGFS_V4_LEGACY_OPCODE == request->op) {
- return TRUE;
- }
-
- if (HGFS_OP_READ_V3 == op) {
- return packetSize <= HGFS_LARGE_PACKET_MAX;
- }
-
- return packetSize <= HGFS_PACKET_MAX;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackGetattrRequest --
- *
- * Unpack hgfs getattr request and initialize a corresponding
- * HgfsFileAttrInfo structure that is used to pass around getattr request
- * information.
- *
- * Since the structure of the get attributes request packet hasn't changed
- * in version 2 of the protocol, HgfsRequestGetattrV2 is identical to
- * HgfsRequestGetattr. So use HgfsRequestGetattr type to access packetIn to
- * keep the code simple.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackGetattrRequest(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- HgfsFileAttrInfo *attrInfo, // IN/OUT: getattr info
- HgfsAttrHint *hints, // OUT: getattr hints
- char **cpName, // OUT: cpName
- size_t *cpNameSize, // OUT: cpName size
- HgfsHandle *file, // OUT: file handle
- uint32 *caseType) // OUT: case-sensitivity flags
-{
- void const *payload;
- size_t payloadSize;
- HgfsOp op;
-
- ASSERT(packetIn);
- ASSERT(attrInfo);
- ASSERT(cpName);
- ASSERT(cpNameSize);
- ASSERT(file);
- ASSERT(caseType);
-
- if (!HgfsParseRequest(packetIn, packetSize, &payload, &payloadSize, &op)) {
- return FALSE;
- }
-
- HgfsInitFileAttr(op, attrInfo);
-
- /* Default values for legacy requests. */
- *caseType = HGFS_FILE_NAME_DEFAULT_CASE;
- *hints = 0;
- *file = HGFS_INVALID_HANDLE;
-
- switch (op) {
- case HGFS_OP_GETATTR_V3: {
- HgfsRequestGetattrV3 *requestV3 = (HgfsRequestGetattrV3 *)payload;
-
- if (!HgfsUnpackGetattrPayloadV3(requestV3,
- payloadSize,
- cpName,
- cpNameSize,
- hints,
- file,
- caseType)) {
- return FALSE;
- }
- LOG(4, ("%s: HGFS_OP_GETATTR_V3: %u\n", __FUNCTION__, *caseType));
- break;
- }
-
- case HGFS_OP_GETATTR_V2: {
- HgfsRequestGetattrV2 *requestV2 = (HgfsRequestGetattrV2 *)payload;
-
- if (!HgfsUnpackGetattrPayloadV2(requestV2,
- payloadSize,
- cpName,
- cpNameSize,
- hints,
- file)) {
- return FALSE;
- }
- break;
- }
-
- case HGFS_OP_GETATTR: {
- HgfsRequestGetattr *requestV1 = (HgfsRequestGetattr *)payload;
-
- if (!HgfsUnpackGetattrPayloadV1(requestV1,payloadSize, cpName, cpNameSize)) {
- return FALSE;
- }
- break;
- }
-
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackGetattrReply --
- *
- * Pack hgfs getattr reply to the HgfsReplyGetattr structure.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsPackGetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsFileAttrInfo *attr, // IN: attr stucture
- const char *utf8TargetName, // IN: optional target name
- uint32 utf8TargetNameLen, // IN: file name length
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session) // IN: Session Info
-{
- Bool result;
- ASSERT(packetIn);
- ASSERT(attr);
-
- *packetOut = NULL;
- *packetSize = 0;
-
- switch (attr->requestType) {
- case HGFS_OP_GETATTR_V3: {
- HgfsReplyGetattrV3 *reply;
- uint32 payloadSize = sizeof *reply + utf8TargetNameLen;
-
- result = HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
- (void **)&reply, packetSize, session);
- if (result == FALSE) {
- goto error;
- }
-
- if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
- free(reply);
- goto error;
- }
- HgfsPackGetattrReplyPayloadV3(attr, utf8TargetName, utf8TargetNameLen, reply);
- break;
- }
-
- case HGFS_OP_GETATTR_V2: {
- HgfsReplyGetattrV2 *reply;
- HgfsRequest *request = (HgfsRequest *)packetIn;
- uint32 payloadSize = sizeof *reply + utf8TargetNameLen;
-
- result = HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
- (void **)&reply, packetSize, session);
- if (result == FALSE) {
- goto error;
- }
-
- if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
- free(reply);
- goto error;
- }
- HgfsPackGetattrReplyPayloadV2(request->id,
- status,
- attr,
- utf8TargetName,
- utf8TargetNameLen,
- reply);
- break;
- }
-
- case HGFS_OP_GETATTR: {
- HgfsReplyGetattr *reply;
- HgfsRequest *request = (HgfsRequest *)packetIn;
+ } else {
+ LOG(4, ("%s: shared folder does not exist.\n", __FUNCTION__));
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- if (result == FALSE) {
- goto error;
+ if (HGFS_NAME_STATUS_DOES_NOT_EXIST == nameStatus) {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ } else {
+ status = HgfsPlatformConvertFromNameStatus(nameStatus);
+ }
}
- HgfsPackGetattrReplyPayloadV1(request->id, status, attr, reply);
- break;
- }
-
- default:
- LOG(4, ("%s: Invalid GetAttr op.\n", __FUNCTION__));
- NOT_REACHED();
- result = FALSE;
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
}
-error:
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackSearchReadReplyPayloadV3 --
- *
- * Packs SearchRead V3 reply payload.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-HgfsPackSearchReadReplyPayloadV3(HgfsFileAttrInfo *attr, // IN: attr stucture
- const char *utf8Name, // IN: file name
- uint32 utf8NameLen, // IN: file name length
- HgfsReplySearchReadV3 *reply) // OUT: payload
-{
- HgfsDirEntry *dirent = (HgfsDirEntry *)reply->payload;
-
- reply->count = 1;
- reply->reserved = 0;
-
- dirent->fileName.length = (uint32)utf8NameLen;
- dirent->fileName.flags = 0;
- dirent->fileName.fid = 0;
- dirent->fileName.caseType = HGFS_FILE_NAME_DEFAULT_CASE;
- dirent->nextEntry = 0;
-
- if (utf8NameLen != 0) {
- memcpy(dirent->fileName.name, utf8Name, utf8NameLen);
- dirent->fileName.name[utf8NameLen] = 0;
-
- HgfsPackAttrV2(attr, &dirent->attr);
- }
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsPackSearchReadReplyPayloadV2 --
- *
- * Packs SearchRead V2 reply payload.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None
+ * HgfsServerDeleteFile --
*
- *-----------------------------------------------------------------------------
- */
-
-void
-HgfsPackSearchReadReplyPayloadV2(HgfsFileAttrInfo *attr, // IN: attr stucture
- const char *utf8Name, // IN: file name
- uint32 utf8NameLen, // IN: file name length
- HgfsReplySearchReadV2 *reply) // OUT: payload
-{
- reply->fileName.length = (uint32)utf8NameLen;
-
- if (utf8NameLen != 0) {
- memcpy(reply->fileName.name, utf8Name, utf8NameLen);
- reply->fileName.name[utf8NameLen] = 0;
- HgfsPackAttrV2(attr, &reply->attr);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
+ * Handle a Delete File request.
*
- * HgfsPackSearchReadReplyPayloadV1 --
+ * Simply converts to the local filename, calls DeleteFile on the
+ * file or calls the Windows native API Delete, and returns an
+ * appropriate response to the driver.
*
- * Packs SearchRead V1 reply payload.
+ * Enforcing read-only shares restrictions
*
* Results:
* None.
*-----------------------------------------------------------------------------
*/
-void
-HgfsPackSearchReadReplyPayloadV1(HgfsFileAttrInfo *attr, // IN: attr stucture
- const char *utf8Name, // IN: file name
- uint32 utf8NameLen, // IN: file name length
- HgfsReplySearchRead *reply) // OUT: payload
+static void
+HgfsServerDeleteFile(HgfsInputParam *input) // IN: Input params
{
- reply->fileName.length = (uint32)utf8NameLen;
+ char *cpName;
+ size_t cpNameSize;
+ HgfsServerLock serverLock = HGFS_LOCK_NONE;
+ fileDesc fileDesc;
+ HgfsHandle file;
+ HgfsDeleteHint hints = 0;
+ HgfsInternalStatus status;
+ HgfsNameStatus nameStatus;
+ uint32 caseFlags;
+ size_t replyPayloadSize = 0;
+ HgfsShareInfo shareInfo;
- if (utf8NameLen != 0) {
- memcpy(reply->fileName.name, utf8Name, utf8NameLen);
- reply->fileName.name[utf8NameLen] = 0;
+ HGFS_ASSERT_INPUT(input);
- /* In SearchReadV1, symlinks are treated as regular files. */
- if (attr->type == HGFS_FILE_TYPE_SYMLINK) {
- reply->attr.type = HGFS_FILE_TYPE_REGULAR;
+ if (HgfsUnpackDeleteRequest(input->payload, input->payloadSize, input->op, &cpName,
+ &cpNameSize, &hints, &file, &caseFlags)) {
+ if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) {
+ status = HgfsPlatformDeleteFileByHandle(file, input->session);
} else {
- reply->attr.type = attr->type;
- }
- reply->attr.size = attr->size;
- reply->attr.creationTime = attr->creationTime;
- reply->attr.accessTime = attr->accessTime;
- reply->attr.writeTime = attr->writeTime;
- reply->attr.attrChangeTime = attr->attrChangeTime;
- reply->attr.permissions = attr->ownerPerms;
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackSearchReadRequest --
- *
- * Unpack hgfs search read request and initialize a corresponding
- * HgfsFileAttrInfo structure that is used to pass around attribute
- * information.
- *
- * Since the structure of the search read request packet hasn't changed in
- * version 2 of the protocol, HgfsRequestSearchReadV2 is identical to
- * HgfsRequestSearchRead. So use HgfsRequestSearchRead type to access
- * packetIn to keep the code simple.
- *
- * Results:
- * Always TRUE.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackSearchReadRequest(const char *packetIn, // IN: request packet
- size_t packetSize, // IN: packet size
- HgfsFileAttrInfo *attr, // OUT: unpacked attr struct
- HgfsHandle *hgfsSearchHandle, // OUT: hgfs search handle
- uint32 *offset) // OUT: entry offset
-{
- void const *payload;
- size_t payloadSize;
- HgfsOp op;
-
- ASSERT(packetIn);
- ASSERT(attr);
- ASSERT(hgfsSearchHandle);
- ASSERT(offset);
-
- if (!HgfsParseRequest(packetIn, packetSize, &payload, &payloadSize, &op)) {
- return FALSE;
- }
-
- HgfsInitFileAttr(op, attr);
-
-
- if (op == HGFS_OP_SEARCH_READ_V3) {
- HgfsRequestSearchReadV3 *request = (HgfsRequestSearchReadV3 *)payload;
-
- /* Enforced by the dispatch function. */
- ASSERT(payloadSize >= sizeof *request);
-
- *hgfsSearchHandle = request->search;
- *offset = request->offset;
-
- LOG(4, ("%s: HGFS_OP_SEARCH_READ_V3\n", __FUNCTION__));
- } else {
- HgfsRequestSearchRead *request = (HgfsRequestSearchRead *)payload;
-
- /* Enforced by the dispatch function. */
- ASSERT(payloadSize >= sizeof *request);
-
- *hgfsSearchHandle = request->search;
- *offset = request->offset;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPackSearchReadReply --
- *
- * Pack hgfs search read reply to the HgfsReplySearchRead{V2} structure.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsPackSearchReadReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- const char *utf8Name, // IN: file name
- size_t utf8NameLen, // IN: file name length
- HgfsFileAttrInfo *attr, // IN: file attr struct
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session) // IN: Session Info
-{
- Bool result = TRUE;
- ASSERT(packetIn);
-
- *packetOut = NULL;
- *packetSize = 0;
-
- switch (attr->requestType) {
- case HGFS_OP_SEARCH_READ_V3: {
- HgfsReplySearchReadV3 *reply;
- uint32 payloadSize = sizeof *reply + utf8NameLen + sizeof(HgfsDirEntry);
-
- if (!HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
- (void **)&reply, packetSize, session)) {
- result = FALSE;
- goto error;
- }
-
- if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
- free(reply);
- result = FALSE;
- goto error;
- }
- HgfsPackSearchReadReplyPayloadV3(attr, utf8Name, utf8NameLen, reply);
- break;
- }
-
- case HGFS_OP_SEARCH_READ_V2: {
- HgfsReplySearchReadV2 *reply;
- uint32 payloadSize = sizeof *reply + utf8NameLen;
-
- if (!HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
- (void **)&reply, packetSize, session)) {
- result = FALSE;
- goto error;
- }
-
- if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
- free(reply);
- result = FALSE;
- goto error;
- }
- HgfsPackSearchReadReplyPayloadV2(attr,
- utf8Name,
- utf8NameLen,
- reply);
- break;
- }
+ char *utf8Name = NULL;
+ size_t utf8NameLen;
- case HGFS_OP_SEARCH_READ: {
- HgfsReplySearchRead *reply;
- uint32 payloadSize = sizeof *reply + utf8NameLen;
-
- if (!HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
- (void **)&reply, packetSize, session)) {
- result = FALSE;
- goto error;
+ nameStatus = HgfsServerGetShareInfo(cpName, cpNameSize, caseFlags, &shareInfo,
+ &utf8Name, &utf8NameLen);
+ if (nameStatus == HGFS_NAME_STATUS_COMPLETE) {
+ /*
+ * Deleting a file needs both read and write permssions.
+ * However the error code must be different depending on the existence
+ * of the file with the same name.
+ */
+ if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+ status = HgfsPlatformFileExists(utf8Name);
+ if (HGFS_ERROR_SUCCESS == status) {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ }
+ LOG(4, ("HgfsServerDeleteFile: failed access check, error %d\n", status));
+ } else if (HgfsFileHasServerLock(utf8Name, input->session, &serverLock,
+ &fileDesc)) {
+ /*
+ * XXX: If the file has an oplock, the client should have broken it on
+ * its own by now. Sorry!
+ */
+ LOG (4, ("%s: File has an outstanding oplock. Client should "
+ "remove this oplock and try again.\n", __FUNCTION__));
+ status = HGFS_ERROR_PATH_BUSY;
+ } else {
+ LOG(4, ("%s: deleting \"%s\"\n", __FUNCTION__, utf8Name));
+ status = HgfsPlatformDeleteFileByName(utf8Name);
+ }
+ free(utf8Name);
+ } else {
+ LOG(4, ("%s: Shared folder does not exist.\n", __FUNCTION__));
+ status = HgfsPlatformConvertFromNameStatus(nameStatus);
+ }
}
-
- if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
- free(reply);
- result = FALSE;
- goto error;
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (!HgfsPackDeleteReply(input->packet, input->metaPacket, input->op,
+ &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
}
- HgfsPackSearchReadReplyPayloadV1(attr,
- utf8Name,
- utf8NameLen,
- reply);
- break;
- }
-
- default: {
- LOG(4, ("%s: Invalid SearchRead Op.", __FUNCTION__));
- NOT_REACHED();
- result = FALSE;
- }
- }
-
-error:
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackSetattrPayloadV3 --
- *
- * Unpack hgfs set attr request V3 payload and initialize a corresponding
- * HgfsHandle or file name to tell us which file to set attributes. Hints
- * holds flags to specify a handle or name for the file or
- * directory to set attributes.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackSetattrPayloadV3(HgfsRequestSetattrV3 *requestV3,// IN: request payload
- size_t payloadSize, // IN: payload size
- HgfsFileAttrInfo *attr, // OUT: setattr info
- char **cpName, // OUT: cpName
- size_t *cpNameSize, // OUT: cpName size
- HgfsAttrHint *hints, // OUT: getattr hints
- HgfsHandle *file, // OUT: file handle
- uint32 *caseFlags) // OUT: case-sensitivity flags
-{
- Bool result;
- Bool useHandle;
-
- if (payloadSize < sizeof *requestV3) {
- return FALSE;
- }
-
- *hints = requestV3->hints;
-
- HgfsUnpackAttrV2(&requestV3->attr, attr);
-
- result = HgfsUnpackFileNameV3(&requestV3->fileName,
- payloadSize - sizeof *requestV3,
- &useHandle,
- cpName,
- cpNameSize,
- file,
- caseFlags);
- if (useHandle) {
- *hints |= HGFS_ATTR_HINT_USE_FILE_DESC;
- }
-
- LOG(4, ("%s: unpacking HGFS_OP_SETATTR_V3, %u\n", __FUNCTION__,
- *caseFlags));
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackSetattrPayloadV2 --
- *
- * Unpack hgfs Setattr request V2 payload and initialize a corresponding
- * HgfsHandle or file name to tell us which to set attributes. Hints
- * holds flags to specify a handle or name for the file or
- * directory to set attributes.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackSetattrPayloadV2(HgfsRequestSetattrV2 *requestV2,// IN: request payload
- size_t payloadSize, // IN: payload size
- HgfsFileAttrInfo *attr, // OUT: setattr info
- char **cpName, // OUT: cpName
- size_t *cpNameSize, // OUT: cpName size
- HgfsAttrHint *hints, // OUT: delete hints
- HgfsHandle *file) // OUT: file handle
-{
- Bool result = TRUE;
-
- /* Enforced by the dispatch function. */
- if (payloadSize < sizeof *requestV2) {
- return FALSE;
- }
-
- LOG(4, ("%s: unpacking HGFS_OP_SETATTR_V2\n", __FUNCTION__));
-
- *file = HGFS_INVALID_HANDLE;
- *hints = requestV2->hints;
-
- HgfsUnpackAttrV2(&requestV2->attr, attr);
-
- if (requestV2->hints & HGFS_ATTR_HINT_USE_FILE_DESC) {
- *file = requestV2->file;
- *cpName = NULL;
- *cpNameSize = 0;
} else {
- result = HgfsUnpackFileName(&requestV2->fileName,
- payloadSize - sizeof *requestV2,
- cpName,
- cpNameSize);
+ status = HGFS_ERROR_PROTOCOL;
}
- return result;
-}
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsUnpackSetattrPayloadV1 --
- *
- * Unpack hgfs setattr request V1 payload and initialize a corresponding
- * file name to tell us which to set attributes.
- *
- * Results:
- * TRUE on success.
- * FALSE on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-HgfsUnpackSetattrPayloadV1(HgfsRequestSetattr *requestV1, // IN: request payload
- size_t payloadSize, // IN: payload size
- HgfsFileAttrInfo *attr, // OUT: setattr info
- char **cpName, // OUT: cpName
- size_t *cpNameSize, // OUT: cpName size
- HgfsAttrHint *hints) // OUT: setattr hints
-{
- LOG(4, ("%s: unpacking HGFS_OP_SETATTR\n", __FUNCTION__));
-
- attr->mask = 0;
- attr->mask |= requestV1->update & HGFS_ATTR_SIZE ? HGFS_ATTR_VALID_SIZE : 0;
- attr->mask |= requestV1->update & HGFS_ATTR_CREATE_TIME ?
- HGFS_ATTR_VALID_CREATE_TIME : 0;
- attr->mask |= requestV1->update & HGFS_ATTR_ACCESS_TIME ?
- HGFS_ATTR_VALID_ACCESS_TIME : 0;
- attr->mask |= requestV1->update & HGFS_ATTR_WRITE_TIME ?
- HGFS_ATTR_VALID_WRITE_TIME : 0;
- attr->mask |= requestV1->update & HGFS_ATTR_CHANGE_TIME ?
- HGFS_ATTR_VALID_CHANGE_TIME : 0;
- attr->mask |= requestV1->update & HGFS_ATTR_PERMISSIONS ?
- HGFS_ATTR_VALID_OWNER_PERMS : 0;
- *hints |= requestV1->update & HGFS_ATTR_ACCESS_TIME_SET ?
- HGFS_ATTR_HINT_SET_ACCESS_TIME : 0;
- *hints |= requestV1->update & HGFS_ATTR_WRITE_TIME_SET ?
- HGFS_ATTR_HINT_SET_WRITE_TIME : 0;
-
- attr->type = requestV1->attr.type;
- attr->size = requestV1->attr.size;
- attr->creationTime = requestV1->attr.creationTime;
- attr->accessTime = requestV1->attr.accessTime;
- attr->writeTime = requestV1->attr.writeTime;
- attr->attrChangeTime = requestV1->attr.attrChangeTime;
- attr->ownerPerms = requestV1->attr.permissions;
- return HgfsUnpackFileName(&requestV1->fileName,
- payloadSize - sizeof *requestV1,
- cpName,
- cpNameSize);
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsUnpackSetattrRequest --
+ * HgfsServerDeleteDir --
*
- * Unpack hgfs setattr request and initialize a corresponding
- * HgfsFileAttrInfo structure that is used to pass around setattr request
- * information.
+ * Handle a Delete Dir request.
+ *
+ * Simply converts to the local filename, calls RemoveDirectory on the
+ * directory or Windows native API delete if we have a valid handle,
+ * and returns an appropriate response to the driver.
*
* Results:
- * TRUE on success.
- * FALSE on failure.
+ * None.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsUnpackSetattrRequest(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- HgfsFileAttrInfo *attr, // OUT: setattr info
- HgfsAttrHint *hints, // OUT: setattr hints
- char **cpName, // OUT: cpName
- size_t *cpNameSize, // OUT: cpName size
- HgfsHandle *file, // OUT: server file ID
- uint32 *caseType) // OUT: case-sensitivity flags
+static void
+HgfsServerDeleteDir(HgfsInputParam *input) // IN: Input params
{
- void const *payload;
- size_t payloadSize;
- HgfsOp op;
-
- ASSERT(packetIn);
- ASSERT(attr);
- ASSERT(cpName);
- ASSERT(cpNameSize);
- ASSERT(file);
- ASSERT(caseType);
-
- if (!HgfsParseRequest(packetIn, packetSize, &payload, &payloadSize, &op)) {
- return FALSE;
- }
-
- attr->requestType = op;
-
- /* Default values for legacy requests. */
- *caseType = HGFS_FILE_NAME_DEFAULT_CASE;
- *hints = 0;
- *file = HGFS_INVALID_HANDLE;
-
- switch (op) {
- case HGFS_OP_SETATTR_V3:
- {
- HgfsRequestSetattrV3 *requestV3 = (HgfsRequestSetattrV3 *)payload;
- if (!HgfsUnpackSetattrPayloadV3(requestV3,
- payloadSize,
- attr,
- cpName,
- cpNameSize,
- hints,
- file,
- caseType)) {
- return FALSE;
+ char *cpName;
+ size_t cpNameSize;
+ HgfsInternalStatus status;
+ HgfsNameStatus nameStatus;
+ HgfsHandle file;
+ HgfsDeleteHint hints = 0;
+ fileDesc fileDesc;
+ Bool sharedFolderOpen = FALSE;
+ uint32 caseFlags;
+ size_t replyPayloadSize = 0;
+ HgfsShareInfo shareInfo;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (HgfsUnpackDeleteRequest(input->payload, input->payloadSize, input->op, &cpName,
+ &cpNameSize, &hints, &file, &caseFlags)) {
+ if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) {
+
+ status = HgfsPlatformGetFd(file, input->session, FALSE, &fileDesc);
+
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (HgfsHandleIsSharedFolderOpen(file, input->session, &sharedFolderOpen) &&
+ sharedFolderOpen) {
+ LOG(4, ("%s: Cannot delete shared folder\n", __FUNCTION__));
+ status = HGFS_ERROR_ACCESS_DENIED;
+ } else {
+ status = HgfsPlatformDeleteDirByHandle(file, input->session);
+ if (HGFS_ERROR_SUCCESS != status) {
+ LOG(4, ("%s: error deleting directory %d: %d\n", __FUNCTION__,
+ file, status));
+ }
+ }
+ } else {
+ LOG(4, ("%s: could not map cached handle %u, error %u\n",
+ __FUNCTION__, file, status));
}
- break;
- }
-
- case HGFS_OP_SETATTR_V2:
- {
- HgfsRequestSetattrV2 *requestV2 = (HgfsRequestSetattrV2 *)payload;
- if (!HgfsUnpackSetattrPayloadV2(requestV2,
- payloadSize,
- attr,
- cpName,
- cpNameSize,
- hints,
- file)) {
- return FALSE;
+ } else {
+ char *utf8Name = NULL;
+ size_t utf8NameLen;
+
+ nameStatus = HgfsServerGetShareInfo(cpName, cpNameSize, caseFlags, &shareInfo,
+ &utf8Name, &utf8NameLen);
+ if (HGFS_NAME_STATUS_COMPLETE == nameStatus) {
+ ASSERT(utf8Name);
+ /* Guest OS is not allowed to delete shared folder. */
+ if (HgfsServerIsSharedFolderOnly(cpName, cpNameSize)){
+ LOG(4, ("%s: Cannot delete shared folder\n", __FUNCTION__));
+ status = HGFS_ERROR_ACCESS_DENIED;
+ } else if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+ /*
+ * Deleting a directory requires both read and write permissions.
+ * However the error code must be different depending on the existence
+ * of the file with the same name.
+ */
+ status = HgfsPlatformFileExists(utf8Name);
+ if (HGFS_ERROR_SUCCESS == status) {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ }
+ LOG(4, ("HgfsServerDeleteDir: failed access check, error %d\n", status));
+ } else {
+ LOG(4, ("%s: removing \"%s\"\n", __FUNCTION__, utf8Name));
+ status = HgfsPlatformDeleteDirByName(utf8Name);
+ }
+ free(utf8Name);
+ } else {
+ LOG(4, ("%s: access check failed\n", __FUNCTION__));
+ status = HgfsPlatformConvertFromNameStatus(nameStatus);
}
- break;
}
- case HGFS_OP_SETATTR:
- {
- HgfsRequestSetattr *requestV1 = (HgfsRequestSetattr *)payload;
- if (!HgfsUnpackSetattrPayloadV1(requestV1,
- payloadSize,
- attr,
- cpName,
- cpNameSize,
- hints)) {
- return FALSE;
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (!HgfsPackDeleteReply(input->packet, input->metaPacket, input->op,
+ &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_INTERNAL;
}
- break;
}
- default:
- return FALSE;
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
}
- return TRUE;
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsPackSetattrReply --
+ * HgfsServerServerLockChange --
*
- * Pack hgfs setattr reply.
- * Since the structure of the set attributes reply packet hasn't changed in
- * version 2 of the protocol, HgfsReplySetattrV2 is identical to
- * HgfsReplySetattr. So use HgfsReplySetattr type to access packetIn to
- * keep the code simple.
+ * Called by the client when it wants to either acquire an oplock on a file
+ * that was previously opened, or when it wants to release/downgrade an
+ * oplock on a file that was previously oplocked.
*
* Results:
- * TRUE if valid op and reply set, FALSE otherwise.
+ * None.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsPackSetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session) // IN: Session Info
+static void
+HgfsServerServerLockChange(HgfsInputParam *input) // IN: Input params
{
- Bool result = TRUE;
-
- ASSERT(packetIn);
-
- *packetOut = NULL;
- *packetSize = 0;
-
- switch (op) {
- case HGFS_OP_SETATTR_V3: {
- HgfsReplySetattrV3 *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- case HGFS_OP_SETATTR_V2:
- case HGFS_OP_SETATTR: {
- HgfsReplySetattr *reply;
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- default:
- result = FALSE;
- LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, op));
- NOT_REACHED();
- break;
- }
- ASSERT(result);
+ HGFS_ASSERT_INPUT(input);
- return result;
+ HgfsServerCompleteRequest(HGFS_ERROR_NOT_SUPPORTED, 0, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsUnpackCreateDirPayloadV3 --
+ * HgfsServerWriteWin32Stream --
*
- * Unpack hgfs create directory request V3 payload and initialize a corresponding
- * file name to tell us which directory to create.
+ * Handle a write request in the WIN32_STREAM_ID format.
*
* Results:
- * TRUE on success.
- * FALSE on failure.
+ * ERROR_SUCCESS or an appropriate Win32 error code.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsUnpackCreateDirPayloadV3(HgfsRequestCreateDirV3 *requestV3, // IN: request payload
- size_t payloadSize, // IN: payload size
- HgfsCreateDirInfo *info) // IN/OUT: info struct
+static void
+HgfsServerWriteWin32Stream(HgfsInputParam *input) // IN: Input params
{
- /*
- * The request file name length is user-provided, so this test must be
- * carefully written to prevent wraparounds.
- */
-
- LOG(4, ("%s: HGFS_OP_CREATE_DIR_V3\n", __FUNCTION__));
- ASSERT(payloadSize >= sizeof *requestV3);
- if (requestV3->fileName.length > payloadSize - sizeof *requestV3) {
- /* The input packet is smaller than the request. */
- return FALSE;
- }
- if (!(requestV3->mask & HGFS_CREATE_DIR_VALID_FILE_NAME)) {
- /* We do not support requests without a valid file name. */
- return FALSE;
+ uint32 actualSize;
+ HgfsInternalStatus status;
+ HgfsHandle file;
+ char *dataToWrite;
+ Bool doSecurity;
+ size_t replyPayloadSize = 0;
+ size_t requiredSize;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (HgfsUnpackWriteWin32StreamRequest(input->payload, input->payloadSize, input->op, &file,
+ &dataToWrite, &requiredSize, &doSecurity)) {
+ status = HgfsPlatformWriteWin32Stream(file, dataToWrite, (uint32)requiredSize,
+ doSecurity, &actualSize, input->session);
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (!HgfsPackWriteWin32StreamReply(input->packet, input->metaPacket, input->op,
+ actualSize, &replyPayloadSize,
+ input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ }
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
}
- /*
- * Copy all the fields into our carrier struct. Some will probably be
- * garbage, but it's simpler to copy everything now and check the
- * valid bits before reading later.
- */
-
- info->mask = requestV3->mask;
- info->cpName = requestV3->fileName.name;
- info->cpNameSize = requestV3->fileName.length;
- info->caseFlags = requestV3->fileName.caseType;
- info->specialPerms = requestV3->specialPerms;
- info->fileAttr = requestV3->fileAttr;
- info->ownerPerms = requestV3->ownerPerms;
- info->groupPerms = requestV3->groupPerms;
- info->otherPerms = requestV3->otherPerms;
- return TRUE;
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsUnpackCreateDirPayloadV2 --
+ * HgfsServerGetattr --
*
- * Unpack hgfs create directory request V2 payload and initialize a corresponding
- * file name to tell us which directory to create.
+ * Handle a Getattr request.
*
* Results:
- * TRUE on success.
- * FALSE on failure.
+ * None.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsUnpackCreateDirPayloadV2(HgfsRequestCreateDirV2 *requestV2, // IN: request payload
- size_t payloadSize, // IN: payload size
- HgfsCreateDirInfo *info) // IN/OUT: info struct
+static void
+HgfsServerGetattr(HgfsInputParam *input) // IN: Input params
{
- /*
- * The request file name length is user-provided, so this test must be
- * carefully written to prevent wraparounds.
- */
+ char *localName;
+ HgfsAttrHint hints = 0;
+ HgfsFileAttrInfo attr;
+ HgfsInternalStatus status = 0;
+ HgfsNameStatus nameStatus;
+ char *cpName;
+ size_t cpNameSize;
+ char *targetName = NULL;
+ uint32 targetNameLen = 0;
+ HgfsHandle file; /* file handle from driver */
+ uint32 caseFlags = 0;
+ HgfsShareOptions configOptions;
+ size_t localNameLen;
+ HgfsShareInfo shareInfo;
+ size_t replyPayloadSize = 0;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (HgfsUnpackGetattrRequest(input->payload, input->payloadSize, input->op, &attr,
+ &hints, &cpName, &cpNameSize, &file, &caseFlags)) {
+ /* Client wants us to reuse an existing handle. */
+ if (hints & HGFS_ATTR_HINT_USE_FILE_DESC) {
+ fileDesc fd;
+
+ targetNameLen = 0;
+ status = HgfsPlatformGetFd(file, input->session, FALSE, &fd);
+ if (HGFS_ERROR_SUCCESS == status) {
+ status = HgfsPlatformGetattrFromFd(fd, input->session, &attr);
+ } else {
+ LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
+ }
- LOG(4, ("%s: HGFS_OP_CREATE_DIR_V2\n", __FUNCTION__));
- ASSERT(payloadSize >= sizeof *requestV2);
- if (requestV2->fileName.length > payloadSize - sizeof *requestV2) {
- /* The input packet is smaller than the request. */
- return FALSE;
- }
- if (!(requestV2->mask & HGFS_CREATE_DIR_VALID_FILE_NAME)) {
- /* We do not support requests without a valid file name. */
- return FALSE;
- }
+ } else {
+ /*
+ * Depending on whether this file/dir is real or virtual, either
+ * forge its attributes or look them up in the actual filesystem.
+ */
+ nameStatus = HgfsServerGetShareInfo(cpName, cpNameSize, caseFlags, &shareInfo,
+ &localName, &localNameLen);
+ switch (nameStatus) {
+ case HGFS_NAME_STATUS_INCOMPLETE_BASE:
+ /*
+ * This is the base of our namespace; make up fake status for
+ * this directory.
+ */
- /*
- * Copy all the fields into our carrier struct. Some will probably be
- * garbage, but it's simpler to copy everything now and check the
- * valid bits before reading later.
- */
+ LOG(4, ("%s: getting attrs for base dir\n", __FUNCTION__));
+ HgfsPlatformGetDefaultDirAttrs(&attr);
+ break;
- info->mask = requestV2->mask;
- info->cpName = requestV2->fileName.name;
- info->cpNameSize = requestV2->fileName.length;
- info->specialPerms = requestV2->specialPerms;
- info->ownerPerms = requestV2->ownerPerms;
- info->groupPerms = requestV2->groupPerms;
- info->otherPerms = requestV2->otherPerms;
- info->fileAttr = 0;
- return TRUE;
+ case HGFS_NAME_STATUS_COMPLETE:
+ /* This is a regular lookup; proceed as usual */
+ ASSERT(localName);
+
+ /* Get the config options. */
+ nameStatus = HgfsServerPolicy_GetShareOptions(cpName, cpNameSize,
+ &configOptions);
+ if (HGFS_NAME_STATUS_COMPLETE == nameStatus) {
+ status = HgfsPlatformGetattrFromName(localName, configOptions, cpName, &attr,
+ &targetName);
+ } else {
+ LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, cpName));
+ status = HGFS_ERROR_FILE_NOT_FOUND;
+ }
+ free(localName);
+
+ if (HGFS_ERROR_SUCCESS == status &&
+ !HgfsServerPolicy_CheckMode(HGFS_OPEN_MODE_READ_ONLY,
+ shareInfo.writePermissions,
+ shareInfo.readPermissions)) {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ } else if (status != HGFS_ERROR_SUCCESS) {
+ /*
+ * If it is a dangling share server should not return
+ * HGFS_ERROR_FILE_NOT_FOUND
+ * to the client because it causes confusion: a name that is returned
+ * by directory enumeration should not produce "name not found"
+ * error.
+ * Replace it with a more appropriate error code: no such device.
+ */
+ if (status == HGFS_ERROR_FILE_NOT_FOUND &&
+ HgfsIsShareRoot(cpName, cpNameSize)) {
+ status = HGFS_ERROR_IO;
+ }
+ }
+ break;
+
+ default:
+ status = HgfsPlatformHandleIncompleteName(nameStatus, &attr);
+ }
+ targetNameLen = targetName ? strlen(targetName) : 0;
+
+ }
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (!HgfsPackGetattrReply(input->packet, input->metaPacket, &attr, targetName,
+ targetNameLen, &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ }
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
+ }
+
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsUnpackCreateDirPayloadV1 --
+ * HgfsServerSetattr --
*
- * Unpack hgfs create directory request V1 payload and initialize a corresponding
- * file name to tell us which directory to create.
+ * Handle a Setattr request.
*
* Results:
- * TRUE on success.
- * FALSE on failure.
+ * None.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsUnpackCreateDirPayloadV1(HgfsRequestCreateDir *requestV1, // IN: request payload
- size_t payloadSize, // IN: payload size
- HgfsCreateDirInfo *info) // IN/OUT: info struct
+static void
+HgfsServerSetattr(HgfsInputParam *input) // IN: Input params
{
- /*
- * The request file name length is user-provided, so this test must be
- * carefully written to prevent wraparounds.
- */
+ HgfsInternalStatus status = HGFS_ERROR_SUCCESS;
+ HgfsNameStatus nameStatus;
+ HgfsFileAttrInfo attr;
+ char *cpName;
+ size_t cpNameSize = 0;
+ HgfsAttrHint hints = 0;
+ HgfsOpenMode shareMode;
+ uint32 caseFlags = 0;
+ HgfsShareInfo shareInfo;
+ HgfsHandle file;
+ size_t replyPayloadSize = 0;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (HgfsUnpackSetattrRequest(input->payload, input->payloadSize, input->op, &attr,
+ &hints, &cpName, &cpNameSize, &file, &caseFlags)) {
+ /* Client wants us to reuse an existing handle. */
+ if (hints & HGFS_ATTR_HINT_USE_FILE_DESC) {
+ if (HgfsHandle2ShareMode(file, input->session, &shareMode)) {
+ if (HGFS_OPEN_MODE_READ_ONLY != shareMode) {
+ status = HgfsPlatformSetattrFromFd(file, input->session, &attr, hints);
+ } else {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ }
+ } else {
+ LOG(4, ("%s: could not get share mode fd %d\n", __FUNCTION__,
+ file));
+ status = HGFS_ERROR_INVALID_HANDLE;
+ }
+ } else { /* Client wants us to open a new handle for this operation. */
+ char *utf8Name = NULL;
+ size_t utf8NameLen;
- LOG(4, ("%s: HGFS_OP_CREATE_DIR_V1\n", __FUNCTION__));
- ASSERT(payloadSize >= sizeof *requestV1);
- if (requestV1->fileName.length > payloadSize - sizeof *requestV1) {
- /* The input packet is smaller than the request. */
- return FALSE;
+ nameStatus = HgfsServerGetShareInfo(cpName, cpNameSize, caseFlags, &shareInfo,
+ &utf8Name, &utf8NameLen);
+ if (HGFS_NAME_STATUS_COMPLETE == nameStatus) {
+ fileDesc hFile;
+ HgfsServerLock serverLock = HGFS_LOCK_NONE;
+ HgfsShareOptions configOptions;
+
+ /*
+ * XXX: If the client has an oplock on this file, it must reuse the
+ * handle for the oplocked node (or break the oplock) prior to making
+ * a setattr request. Fail this request.
+ */
+ if (!HgfsServerPolicy_CheckMode(HGFS_OPEN_MODE_WRITE_ONLY,
+ shareInfo.writePermissions,
+ shareInfo.readPermissions)) {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ } else if (HGFS_NAME_STATUS_COMPLETE !=
+ HgfsServerPolicy_GetShareOptions(cpName, cpNameSize,
+ &configOptions)) {
+ LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, cpName));
+ status = HGFS_ERROR_FILE_NOT_FOUND;
+ } else if (HgfsFileHasServerLock(utf8Name, input->session, &serverLock, &hFile)) {
+ LOG(4, ("%s: An open, oplocked handle exists for "
+ "this file. The client should retry with that handle\n",
+ __FUNCTION__));
+ status = HGFS_ERROR_PATH_BUSY;
+ } else {
+ status = HgfsPlatformSetattrFromName(utf8Name, &attr, configOptions, hints);
+ }
+ free(utf8Name);
+ } else {
+ LOG(4, ("%s: file not found.\n", __FUNCTION__));
+ status = HgfsPlatformConvertFromNameStatus(nameStatus);
+ }
+ }
+
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (!HgfsPackSetattrReply(input->packet, input->metaPacket, attr.requestType,
+ &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ }
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
}
- /* For CreateDirV1 requests, we know exactly what fields we expect. */
- info->mask = HGFS_CREATE_DIR_VALID_OWNER_PERMS | HGFS_CREATE_DIR_VALID_FILE_NAME;
- info->cpName = requestV1->fileName.name;
- info->cpNameSize = requestV1->fileName.length;
- info->ownerPerms = requestV1->permissions;
- info->fileAttr = 0;
- return TRUE;
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsUnpackCreateDirRequest --
+ * HgfsServerValidateOpenParameters --
*
- * Unpack hgfs CreateDir request and initialize a corresponding
- * HgfsCreateDirInfo structure that is used to pass around CreateDir request
- * information.
+ * Performs sanity check of the input parameters.
*
* Results:
- * TRUE on success.
- * FALSE on failure.
+ * HGFS_ERROR_SUCCESS if the parameters are valid.
+ * Appropriate error code otherwise.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsCreateDirInfo *info) // IN/OUT: info struct
-{
- void const *payload;
- size_t payloadSize;
- HgfsOp op;
-
- ASSERT(packetIn);
- ASSERT(info);
-
- if (!HgfsParseRequest(packetIn, packetSize, &payload, &payloadSize, &op)) {
- return FALSE;
+static HgfsInternalStatus
+HgfsServerValidateOpenParameters(HgfsFileOpenInfo *openInfo, // IN/OUT: openfile info
+ Bool *denyCreatingFile, // OUT: No new files
+ int *followSymlinks) // OUT: Host resolves link
+{
+ size_t utf8NameLen;
+ HgfsInternalStatus status;
+
+ *followSymlinks = 0;
+ *denyCreatingFile = FALSE;
+
+ if ((openInfo->mask & HGFS_OPEN_VALID_MODE)) {
+ HgfsNameStatus nameStatus;
+ /* It is now safe to read the file name. */
+ nameStatus = HgfsServerGetShareInfo(openInfo->cpName,
+ openInfo->cpNameSize,
+ openInfo->caseFlags,
+ &openInfo->shareInfo,
+ &openInfo->utf8Name,
+ &utf8NameLen);
+ if (HGFS_NAME_STATUS_COMPLETE == nameStatus) {
+ if (openInfo->mask & HGFS_OPEN_VALID_FLAGS) {
+ HgfsOpenFlags savedOpenFlags = openInfo->flags;
+
+ if (HgfsServerCheckOpenFlagsForShare(openInfo, &openInfo->flags)) {
+ HgfsShareOptions configOptions;
+
+ /* Get the config options. */
+ nameStatus = HgfsServerPolicy_GetShareOptions(openInfo->cpName,
+ openInfo->cpNameSize,
+ &configOptions);
+ if (nameStatus == HGFS_NAME_STATUS_COMPLETE) {
+ *followSymlinks =
+ HgfsServerPolicy_IsShareOptionSet(configOptions,
+ HGFS_SHARE_FOLLOW_SYMLINKS);
+ *denyCreatingFile = savedOpenFlags != openInfo->flags;
+ status = HGFS_ERROR_SUCCESS;
+ } else {
+ LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, openInfo->cpName));
+ *denyCreatingFile = TRUE;
+ status = HGFS_ERROR_FILE_NOT_FOUND;
+ }
+ } else {
+ /* Incompatible open mode with share mode. */
+ status = HGFS_STATUS_ACCESS_DENIED;
+ }
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
+ }
+ } else {
+ LOG(4, ("%s: Shared folder not found\n", __FUNCTION__));
+ status = HgfsPlatformConvertFromNameStatus(nameStatus);
+ }
+ } else {
+ LOG(4, ("%s: filename or mode not provided\n", __FUNCTION__));
+ status = HGFS_ERROR_PROTOCOL;
}
+ return status;
+}
- info->requestType = op;
- /* Default value for legacy requests. */
- info->caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
- switch (op) {
- case HGFS_OP_CREATE_DIR_V3:
- {
- HgfsRequestCreateDirV3 *requestV3 = (HgfsRequestCreateDirV3 *)payload;
- if (!HgfsUnpackCreateDirPayloadV3(requestV3,
- payloadSize,
- info)) {
- return FALSE;
- }
- break;
- }
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsServerOpen --
+ *
+ * Handle an Open request.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
- case HGFS_OP_CREATE_DIR_V2:
- {
- HgfsRequestCreateDirV2 *requestV2 = (HgfsRequestCreateDirV2 *)payload;
- if (!HgfsUnpackCreateDirPayloadV2(requestV2,
- payloadSize,
- info)) {
- return FALSE;
- }
- break;
- }
- case HGFS_OP_CREATE_DIR:
- {
- HgfsRequestCreateDir *requestV1 = (HgfsRequestCreateDir *)payload;
- if (!HgfsUnpackCreateDirPayloadV1(requestV1,
- payloadSize,
- info)) {
- return FALSE;
+static void
+HgfsServerOpen(HgfsInputParam *input) // IN: Input params
+{
+ HgfsInternalStatus status;
+ fileDesc newHandle;
+ HgfsLocalId localId;
+ HgfsFileOpenInfo openInfo;
+ fileDesc fileDesc;
+ HgfsServerLock serverLock = HGFS_LOCK_NONE;
+ size_t replyPayloadSize = 0;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (HgfsUnpackOpenRequest(input->payload, input->payloadSize, input->op, &openInfo)) {
+ int followSymlinks;
+ Bool denyCreatingFile;
+
+ status = HgfsServerValidateOpenParameters(&openInfo, &denyCreatingFile,
+ &followSymlinks);
+ if (HGFS_ERROR_SUCCESS == status) {
+ ASSERT(openInfo.utf8Name);
+ LOG(4, ("%s: opening \"%s\", mode %u, flags %u, perms %u%u%u%u attr %u\n",
+ __FUNCTION__, openInfo.utf8Name, openInfo.mode,
+ openInfo.mask & HGFS_OPEN_VALID_FLAGS ? openInfo.flags : 0,
+ (openInfo.mask & HGFS_OPEN_VALID_SPECIAL_PERMS) ?
+ openInfo.specialPerms : 0,
+ (openInfo.mask & HGFS_OPEN_VALID_OWNER_PERMS) ?
+ openInfo.ownerPerms : 0,
+ (openInfo.mask & HGFS_OPEN_VALID_GROUP_PERMS) ?
+ openInfo.groupPerms : 0,
+ (openInfo.mask & HGFS_OPEN_VALID_OTHER_PERMS) ?
+ openInfo.otherPerms : 0,
+ openInfo.mask & HGFS_OPEN_VALID_FILE_ATTR ? (uint32)openInfo.attr : 0));
+ /*
+ * XXX: Before opening the file, see if we already have this file opened on
+ * the server with an oplock on it. If we do, we must fail the new open
+ * request, otherwise we will trigger an oplock break that the guest cannot
+ * handle at this time (since the HGFS server is running in the context of
+ * the vcpu thread), and we'll deadlock.
+ *
+ * Until we overcome this limitation via Crosstalk, we will be extra smart
+ * in the client drivers so as to prevent open requests on handles that
+ * already have an oplock. And the server will protect itself like so.
+ *
+ * XXX: With some extra effort, we could allow a second open for read here,
+ * since that won't break a shared oplock, but the clients should already
+ * realize that the second open can be avoided via sharing handles, too.
+ */
+ if (!HgfsFileHasServerLock(openInfo.utf8Name, input->session, &serverLock,
+ &fileDesc)) {
+ /* See if the name is valid, and if so add it and return the handle. */
+ status = HgfsPlatformValidateOpen(&openInfo, followSymlinks, input->session,
+ &localId, &newHandle);
+ if (status == HGFS_ERROR_SUCCESS) {
+ ASSERT(newHandle >= 0);
+
+ /*
+ * Open succeeded, so make new node and return its handle. If we fail,
+ * it's almost certainly an internal server error.
+ */
+
+ if (HgfsCreateAndCacheFileNode(&openInfo, &localId, newHandle,
+ FALSE, input->session)) {
+ if (!HgfsPackOpenReply(input->packet, input->metaPacket, &openInfo,
+ &replyPayloadSize, input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ }
+ } else if (denyCreatingFile && HGFS_ERROR_FILE_NOT_FOUND == status) {
+ status = HGFS_ERROR_ACCESS_DENIED;
+ }
+ } else {
+ status = HGFS_ERROR_PATH_BUSY;
}
- break;
+ free(openInfo.utf8Name);
}
- default:
- return FALSE;
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
}
- return TRUE;
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsPackCreateDirReply --
+ * HgfsGetDirEntry --
*
- * Pack hgfs CreateDir reply.
+ * Gets a directory entry at specified offset.
*
* Results:
- * TRUE if valid op and reply set, FALSE otherwise.
+ * None.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsPackCreateDirReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: create dir operation version
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session) // IN: Session Info
-{
- Bool result = TRUE;
+static HgfsInternalStatus
+HgfsGetDirEntry(HgfsHandle hgfsSearchHandle,
+ uint32 requestedOffset,
+ HgfsSearch *search,
+ HgfsShareOptions configOptions,
+ HgfsSessionInfo *session,
+ HgfsFileAttrInfo *attr,
+ char **entryName,
+ size_t *nameLength)
+{
+ HgfsInternalStatus status;
+ DirectoryEntry *dent;
+
+ dent = HgfsGetSearchResult(hgfsSearchHandle, session, requestedOffset, FALSE);
+ if (dent) {
+ unsigned int length;
+ char *fullName;
+ char *sharePath;
+ size_t sharePathLen;
+ size_t fullNameLen;
+ HgfsServerLock serverLock = HGFS_LOCK_NONE;
+ fileDesc fileDesc;
+
+ length = strlen(dent->d_name);
+
+ /* Each type of search gets a dent's attributes in a different way. */
+ switch (search->type) {
+ case DIRECTORY_SEARCH_TYPE_DIR:
- ASSERT(packetIn);
+ /*
+ * Construct the UTF8 version of the full path to the file, and call
+ * HgfsGetattrFromName to get the attributes of the file.
+ */
+ fullNameLen = search->utf8DirLen + 1 + length;
+ fullName = (char *)malloc(fullNameLen + 1);
+ if (fullName) {
+ memcpy(fullName, search->utf8Dir, search->utf8DirLen);
+ fullName[search->utf8DirLen] = DIRSEPC;
+ memcpy(&fullName[search->utf8DirLen + 1], dent->d_name, length + 1);
- *packetOut = NULL;
- *packetSize = 0;
+ LOG(4, ("%s: about to stat \"%s\"\n", __FUNCTION__, fullName));
- switch (op) {
- case HGFS_OP_CREATE_DIR_V3: {
- HgfsReplyCreateDirV3 *reply;
+ /*
+ * XXX: It is unreasonable to make the caller either 1) pass existing
+ * handles for directory objects as part of the SearchRead, or 2)
+ * prior to calling SearchRead on a directory, break all oplocks on
+ * that directory's objects.
+ *
+ * To compensate for that, if we detect that this directory object
+ * has an oplock, we'll quietly reuse the handle. Note that this
+ * requires clients who take out an exclusive oplock to open a
+ * handle with read as well as write access, otherwise we'll fail
+ * further down in HgfsStat.
+ *
+ * XXX: We could open a new handle safely if its a shared oplock.
+ * But isn't this handle sharing always desirable?
+ */
+ if (HgfsFileHasServerLock(fullName, session, &serverLock, &fileDesc)) {
+ LOG(4, ("%s: Reusing existing oplocked handle "
+ "to avoid oplock break deadlock\n", __FUNCTION__));
+ status = HgfsPlatformGetattrFromFd(fileDesc, session, attr);
+ } else {
+ status = HgfsPlatformGetattrFromName(fullName, configOptions,
+ search->utf8ShareName, attr, NULL);
+ }
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- case HGFS_OP_CREATE_DIR_V2: {
- HgfsReplyCreateDirV2 *reply;
+ if (HGFS_ERROR_SUCCESS != status) {
+ HgfsOp savedOp = attr->requestType;
+ LOG(4, ("%s: stat FAILED %s (%d)\n", __FUNCTION__, fullName, status));
+ memset(attr, 0, sizeof *attr);
+ attr->requestType = savedOp;
+ attr->type = HGFS_FILE_TYPE_REGULAR;
+ attr->mask = 0;
+ }
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- case HGFS_OP_CREATE_DIR: {
- HgfsReplyCreateDir *reply;
+ free(fullName);
+ status = HGFS_ERROR_SUCCESS;
+ } else {
+ LOG(4, ("%s: could not allocate space for \"%s\\%s\"\n",
+ __FUNCTION__, search->utf8Dir, dent->d_name));
+ status = HGFS_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ break;
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- break;
- }
- default:
- result = FALSE;
- LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, op));
- NOT_REACHED();
- break;
- }
+ case DIRECTORY_SEARCH_TYPE_BASE:
- return result;
+ /*
+ * For a search enumerating all shares, give the default attributes
+ * for '.' and ".." (which aren't really shares anyway). Each real
+ * share gets resolved into its full path, and gets its attributes
+ * via HgfsGetattrFromName.
+ */
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0) {
+ LOG(4, ("%s: assigning %s default attributes\n",
+ __FUNCTION__, dent->d_name));
+ HgfsPlatformGetDefaultDirAttrs(attr);
+ status = HGFS_ERROR_SUCCESS;
+ } else {
+ HgfsNameStatus nameStatus;
+
+ /* Check permission on the share and get the share path */
+ nameStatus =
+ HgfsServerPolicy_GetSharePath(dent->d_name, length,
+ HGFS_OPEN_MODE_READ_ONLY,
+ &sharePathLen,
+ (char const **)&sharePath);
+ if (nameStatus == HGFS_NAME_STATUS_COMPLETE) {
+
+ /*
+ * Server needs to produce list of shares that is consistent with
+ * the list defined in UI. If a share can't be accessed because of
+ * problems on the host, the server still enumerates it and
+ * returns to the client.
+ */
+ /*
+ * XXX: We will open a new handle for this, but it should be safe
+ * from oplock-induced deadlock because these are all directories,
+ * and thus cannot have oplocks placed on them.
+ */
+ status = HgfsPlatformGetattrFromName(sharePath, configOptions,
+ dent->d_name, attr, NULL);
+
+ /*
+ * For some reason, Windows marks drives as hidden and system. So
+ * if one of the top level shared folders is mapped to a drive
+ * letter (like C:\), then GetFileAttributesEx() will return hidden
+ * and system attributes for that drive. We don't want that
+ * since we want the users to see all top level shared folders.
+ * Even in the case when the top level shared folder is mapped
+ * to a non-drive hidden/system directory, we still want to display
+ * it to the user. So make sure that system and hidden attributes
+ * are not set.
+ * Note, that for network shares this doesn't apply, since each
+ * top level network share is a separate mount point that doesn't
+ * have such attributes. So when we finally have per share
+ * mounting, this hack will go away.
+ *
+ * See bug 125065.
+ */
+ attr->flags &= ~(HGFS_ATTR_HIDDEN | HGFS_ATTR_SYSTEM);
+
+ if (HGFS_ERROR_SUCCESS != status) {
+ /*
+ * The dent no longer exists. Log the event.
+ */
+
+ LOG(4, ("%s: stat FAILED\n", __FUNCTION__));
+ status = HGFS_ERROR_SUCCESS;
+ }
+ } else {
+ LOG(4, ("%s: No such share or access denied\n", __FUNCTION__));
+ status = HgfsPlatformConvertFromNameStatus(nameStatus);
+ }
+ }
+ break;
+ case DIRECTORY_SEARCH_TYPE_OTHER:
+
+ /*
+ * The POSIX implementation of HgfsSearchOpen could not have created
+ * this kind of search.
+ */
+#if !defined(_WIN32)
+ NOT_IMPLEMENTED();
+#endif
+ /*
+ * All "other" searches get the default attributes. This includes
+ * an enumeration of drive, and the root enumeration (which contains
+ * a "drive" dent and a "unc" dent).
+ */
+ HgfsPlatformGetDefaultDirAttrs(attr);
+ break;
+ default:
+ NOT_IMPLEMENTED();
+ break;
+ }
+
+ /*
+ * We need to unescape the name before sending it back to the client
+ */
+ if (HGFS_ERROR_SUCCESS == status) {
+ *entryName = strdup(dent->d_name);
+ *nameLength = HgfsEscape_Undo(dent->d_name, length + 1);
+ LOG(4, ("%s: dent name is \"%s\" len = %"FMTSZ"u\n", __FUNCTION__,
+ *entryName, *nameLength));
+ } else {
+ *entryName = NULL;
+ *nameLength = 0;
+ LOG(4, ("%s: error %d getting dent\n", __FUNCTION__, status));
+ }
+
+ free(dent);
+ } else {
+ /* End of directory entries marker. */
+ *entryName = NULL;
+ *nameLength = 0;
+ status = HGFS_ERROR_SUCCESS;
+ }
+ return status;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsUnpackWriteWin32StreamPayloadV3 --
+ * HgfsServerSearchRead --
*
- * Unpack hgfs write stream request V3 payload and initialize a corresponding
- * file name to tell us which directory to create.
+ * Handle a "Search Read" request.
*
* Results:
- * TRUE on success.
- * FALSE on failure.
+ * None.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsUnpackWriteWin32StreamPayloadV3(HgfsRequestWriteWin32StreamV3 *requestV3, // IN:
- size_t payloadSize, // IN:
- HgfsHandle *file, // OUT:
- char **data, // OUT:
- size_t *dataSize, // OUT:
- Bool *doSecurity) // OUT:
+static void
+HgfsServerSearchRead(HgfsInputParam *input) // IN: Input params
{
- LOG(4, ("%s: HGFS_OP_WRITE_WIN32_STREAM_V3\n", __FUNCTION__));
- if (payloadSize < sizeof *requestV3) {
- return FALSE;
- }
+ uint32 requestedOffset;
+ HgfsFileAttrInfo attr;
+ HgfsInternalStatus status;
+ HgfsNameStatus nameStatus;
+ HgfsHandle hgfsSearchHandle;
+ HgfsSearch search;
+ HgfsShareOptions configOptions = 0;
+ size_t replyPayloadSize = 0;
+ char *entryName;
+ size_t nameLength;
+
+ HGFS_ASSERT_INPUT(input);
+
+ if (HgfsUnpackSearchReadRequest(input->payload, input->payloadSize, input->op, &attr,
+ &hgfsSearchHandle, &requestedOffset)) {
+ LOG(4, ("%s: read search #%u, offset %u\n", __FUNCTION__,
+ hgfsSearchHandle, requestedOffset));
+ if (HgfsGetSearchCopy(hgfsSearchHandle, input->session, &search)) {
+ /* Get the config options. */
+ status = HGFS_ERROR_SUCCESS;
+ if (search.utf8ShareNameLen != 0) {
+ nameStatus = HgfsServerPolicy_GetShareOptions(search.utf8ShareName,
+ search.utf8ShareNameLen,
+ &configOptions);
+ if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
+ LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__,
+ search.utf8ShareName));
+ status = HGFS_ERROR_FILE_NOT_FOUND;
+ }
+ }
- if (payloadSize >= requestV3->requiredSize + sizeof *requestV3) {
- *file = requestV3->file;
- *data = requestV3->payload;
- *dataSize = requestV3->requiredSize;
- *doSecurity = (requestV3->flags & HGFS_WIN32_STREAM_IGNORE_SECURITY) == 0;
- return TRUE;
+ if (HGFS_ERROR_SUCCESS == status) {
+ status = HgfsGetDirEntry(hgfsSearchHandle, requestedOffset, &search,
+ configOptions, input->session, &attr, &entryName,
+ &nameLength);
+ if (HGFS_ERROR_SUCCESS == status) {
+ if (!HgfsPackSearchReadReply(input->packet, input->metaPacket, entryName,
+ nameLength, &attr, &replyPayloadSize,
+ input->session)) {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ free(entryName);
+ }
+ }
+
+ free(search.utf8Dir);
+ free(search.utf8ShareName);
+ } else {
+ LOG(4, ("%s: handle %u is invalid\n", __FUNCTION__, hgfsSearchHandle));
+ status = HGFS_ERROR_INVALID_HANDLE;
+ }
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
}
- return FALSE;
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
+
/*
*-----------------------------------------------------------------------------
*
- * HgfsUnpackWriteWin32StreamRequest --
+ * HgfsServerCreateSession --
*
- * Unpack hgfs SendFileUsingReader request. Returns file to write to, data
- * and whether to restore the security stream.
+ * Handle a "Create session" request.
*
* Results:
- * TRUE on success.
- * FALSE on failure.
+ * None.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsOp *op, // OUT: request type
- HgfsHandle *file, // OUT: file to write to
- char **data, // OUT: data to write
- size_t *dataSize, // OUT: size of data
- Bool *doSecurity) // OUT: restore sec.str.
+static void
+HgfsServerCreateSession(HgfsInputParam *input) // IN: Input params
{
- void const *payload;
- size_t payloadSize;
+ size_t replyPayloadSize = 0;
+ HgfsCreateSessionInfo info;
+ HgfsInternalStatus status;
- ASSERT(packetIn);
- ASSERT(file);
- ASSERT(data);
- ASSERT(dataSize);
- ASSERT(doSecurity);
-
- if (!HgfsParseRequest(packetIn, packetSize, &payload, &payloadSize, op)) {
- return FALSE;
- }
+ HGFS_ASSERT_INPUT(input);
- if (*op != HGFS_OP_WRITE_WIN32_STREAM_V3) {
- /* The only supported version for the moment is V3. */
- NOT_REACHED();
- return FALSE;
+ if (HgfsUnpackCreateSessionRequest(input->payload, input->payloadSize,
+ input->op, &info)) {
+ LOG(4, ("%s: create session\n", __FUNCTION__));
+ if (info.maxPacketSize < input->session->maxPacketSize) {
+ input->session->maxPacketSize = info.maxPacketSize;
+ }
+ if (HgfsPackCreateSessionReply(input->packet, input->metaPacket,
+ &replyPayloadSize, input->session)) {
+ HgfsServerSessionGet(input->session);
+ status = HGFS_ERROR_SUCCESS;
+ } else {
+ status = HGFS_ERROR_INTERNAL;
+ }
+ } else {
+ status = HGFS_ERROR_PROTOCOL;
}
- return HgfsUnpackWriteWin32StreamPayloadV3((HgfsRequestWriteWin32StreamV3 *)payload,
- payloadSize,
- file,
- data,
- dataSize,
- doSecurity);
+ HgfsServerCompleteRequest(status, replyPayloadSize, input);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsPackWriteWin32StreamReply --
+ * HgfsServerDestroySession --
*
- * Pack hgfs SendFileUsingReader reply.
- * Returns the actual amount of data written in the reply.
+ * Handle a "Destroy session" request.
*
* Results:
- * TRUE if valid op and reply set, FALSE otherwise.
+ * None.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-Bool
-HgfsPackWriteWin32StreamReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: request type
- uint32 actualSize, // IN: amount written
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session) // IN:Session Info
+static void
+HgfsServerDestroySession(HgfsInputParam *input) // IN: Input params
{
- HgfsReplyWriteWin32StreamV3 *reply;
- Bool result;
+ HGFS_ASSERT_INPUT(input);
- ASSERT(packetIn);
-
- *packetOut = NULL;
- *packetSize = 0;
-
- if (op != HGFS_OP_WRITE_WIN32_STREAM_V3) {
- NOT_REACHED();
- return FALSE;
- }
-
- result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize, session);
- if (result != FALSE) {
- reply->actualSize = actualSize;
- }
-
- return result;
+ HgfsServerCompleteRequest(HGFS_ERROR_SUCCESS, 0, input);
+ HgfsServerSessionPut(input->session);
}
-
/*
*-----------------------------------------------------------------------------
*
mask));
}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsShareRoot --
+ *
+ * Checks if the cpName represents the root directory for a share.
+ * Components in CPName format are separated by NUL characters.
+ * CPName for the root of a share contains only one component thus
+ * it does not have any embedded '\0' characters in the name.
+ *
+ * Results:
+ * TRUE if it is the root directory, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsShareRoot(char const *cpName, // IN: name to test
+ size_t cpNameSize) // IN: length of the name
+{
+ size_t i;
+ for (i = 0; i < cpNameSize; i++) {
+ if (cpName[i] == '\0') {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
#ifdef HGFS_OPLOCKS
/*
*-----------------------------------------------------------------------------
#include "vm_atomic.h"
#include "userlock.h"
-#ifdef _WIN32
-# define HGFS_REPLYPKT_STATUS RPC_S_PROTOCOL_ERROR
-#else
-# define HGFS_REPLYPKT_STATUS EPROTO
-#endif
-
-#define HGFS_REPLYPKT_CHECK(replyPacket, replySize, replyPacketSize, status, label) \
- do { \
- LOG(4, ("%s: \n", __FUNCTION__)); \
- ASSERT_DEVEL(replyPacket); \
- if (!replyPacket || ((replySize) > (replyPacketSize))) { \
- status = HGFS_REPLYPKT_STATUS; \
- goto label; \
- } \
- } while(0)
-
#define HGFS_DEBUG_ASYNC (0)
/*
} HgfsLocalId;
typedef enum {
- REQ_ASYNC, /* Hint that request should be processed Async */
- REQ_SYNC, /* " Sync */
+ REQ_ASYNC, /* Hint that request should be processed Async. */
+ REQ_SYNC, /* " Sync. */
} RequestHint;
typedef struct HgfsSessionInfo {
+ /* Unique session id. */
+ uint64 sessionId;
+
+ /* Max packet size that is supported by both client and server. */
+ uint32 maxPacketSize;
+
/* Transport session context. */
void *transportData;
HgfsAttrFlags fileAttr; /* Various flags and Windows 'attributes' */
} HgfsCreateDirInfo;
+typedef struct HgfsCreateSessionInfo {
+ uint32 maxPacketSize;
+} HgfsCreateSessionInfo;
+
/* Server lock related structure */
typedef struct {
HgfsServerLock serverLock;
} ServerLockData;
-typedef
-struct HgfsInputParam {
+typedef struct HgfsInputParam {
const char *metaPacket;
size_t metaPacketSize;
HgfsSessionInfo *session;
HgfsPacket *packet;
- Bool v4header;
+ void const *payload;
+ size_t payloadSize;
HgfsOp op;
-}
-HgfsInputParam;
+ uint32 id;
+ Bool v4header;
+} HgfsInputParam;
Bool
HgfsCreateAndCacheFileNode(HgfsFileOpenInfo *openInfo, // IN: Open info struct
HgfsSessionInfo *session, // IN: Session info
HgfsHandle *handle); // OUT: Search handle
-/*
- * Opcode handlers
- */
-
-HgfsInternalStatus
-HgfsServerOpen(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerRead(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerWrite(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerSearchOpen(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerSearchRead(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerGetattr(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerSetattr(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerCreateDir(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerDeleteFile(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerDeleteDir(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerRename(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerQueryVolume(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerSymlinkCreate(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerServerLockChange(HgfsInputParam *input); // IN: Input params
-
-HgfsInternalStatus
-HgfsServerWriteWin32Stream(HgfsInputParam *input); // IN: Input params
/* Unpack/pack requests/reply helper functions. */
Bool
-HgfsUnpackOpenRequest(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsFileOpenInfo *openInfo); // IN/OUT: open info struct
+HgfsParseRequest(HgfsPacket *packet, // IN: request packet
+ HgfsSessionInfo *session, // IN: current session
+ HgfsInputParam **input, // OUT: request parameters
+ HgfsInternalStatus *status); // OUT: error code
+
+void
+HgfsPackLegacyReplyHeader(HgfsInternalStatus status, // IN: reply status
+ HgfsHandle id, // IN: original packet id
+ HgfsReply *header); // OUT: outgoing packet header
+Bool
+HgfsAllocInitReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: incoming packet header
+ size_t payloadSize, // IN: payload size
+ void **payload, // OUT: size of the allocated packet
+ HgfsSessionInfo *session); // IN: Session Info
+Bool
+HgfsUnpackOpenRequest(void const *packet, // IN: incoming packet
+ size_t packetSize, // IN: size of packet
+ HgfsOp op, // IN: request type
+ HgfsFileOpenInfo *openInfo); // IN/OUT: open info struct
Bool
-HgfsPackOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsFileOpenInfo *openInfo, // IN: open info struct
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session); // IN: Session info
+HgfsPackOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsFileOpenInfo *openInfo, // IN: open info struct
+ size_t *payloadSize, // OUT: outgoing packet size
+ HgfsSessionInfo *session); // IN: Session Info
+
Bool
-HgfsUnpackGetattrRequest(char const *packetIn, // IN: request packet
+HgfsUnpackGetattrRequest(void const *packetHeader, // IN: packet header
size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
HgfsFileAttrInfo *attrInfo, // IN/OUT: unpacked attr struct
HgfsAttrHint *hints, // OUT: getattr hints
char **cpName, // OUT: cpName
uint32 *caseFlags); // OUT: case-sensitivity flags
Bool
-HgfsUnpackDeleteRequest(char const *packetIn, // IN: request packet
+HgfsUnpackDeleteRequest(void const *packet, // IN: request packet
size_t packetSize, // IN: request packet size
- HgfsOp *op, // OUT: requested operation
+ HgfsOp op, // IN: requested operation
char **cpName, // OUT: cpName
size_t *cpNameSize, // OUT: cpName size
HgfsDeleteHint *hints, // OUT: delete hints
Bool
HgfsPackDeleteReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
+ char const *packetHeader, // IN: packet header
HgfsOp op, // IN: requested operation
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
+ size_t *payloadSize, // OUT: size of HGFS packet
HgfsSessionInfo *session); // IN: Session Info
Bool
-HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet
+HgfsUnpackRenameRequest(void const *packet, // IN: request packet
size_t packetSize, // IN: request packet size
- HgfsOp *op, // OUT: requested operation
+ HgfsOp op, // IN: requested operation
char **cpOldName, // OUT: rename src
size_t *cpOldNameLen, // OUT: rename src size
char **cpNewName, // OUT: rename dst
Bool
HgfsPackRenameReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
+ char const *packetHeader, // IN: packet header
HgfsOp op, // IN: requested operation
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
+ size_t *payloadSize, // OUT: size of packet
HgfsSessionInfo *session); // IN: Session Info
Bool
HgfsPackGetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
+ char const *packetHeader, // IN: packet header
HgfsFileAttrInfo *attr, // IN: attr stucture
const char *utf8TargetName, // IN: optional target name
uint32 utf8TargetNameLen, // IN: file name length
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
+ size_t *payloadSize, // OUT: size of HGFS packet
HgfsSessionInfo *session); // IN: Session Info
Bool
-HgfsUnpackSearchReadRequest(const char *packetIn, // IN: request packet
+HgfsPackSymlinkCreateReply(HgfsPacket *packet, // IN/OUT: Hgfs packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ size_t *payloadSize, // OUT: size of HGFS packet
+ HgfsSessionInfo *session); // IN: Session Info
+Bool
+HgfsUnpackSearchReadRequest(const void *packet, // IN: request packet
size_t packetSize, // IN: packet size
+ HgfsOp op, // IN: requested operation
HgfsFileAttrInfo *attr, // OUT: unpacked attr struct
HgfsHandle *hgfsSearchHandle, // OUT: hgfs search handle
uint32 *offset); // OUT: entry offset
Bool
HgfsPackSearchReadReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
+ char const *packetHeader, // IN: packet header
const char *utf8Name, // IN: file name
size_t utf8NameLen, // IN: file name length
HgfsFileAttrInfo *attr, // IN: file attr struct
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
+ size_t *payloadSize, // OUT: size of packet
HgfsSessionInfo *session); // IN: Session Info
Bool
-HgfsUnpackSetattrRequest(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- HgfsFileAttrInfo *attr, // IN/OUT: getattr info
- HgfsAttrHint *hints, // OUT: setattr hints
- char **cpName, // OUT: cpName
- size_t *cpNameSize, // OUT: cpName size
- HgfsHandle *file, // OUT: server file ID
- uint32 *caseFlags); // OUT: case-sensitivity flags
+HgfsUnpackSetattrRequest(void const *packet, // IN: request packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: requested operation
+ HgfsFileAttrInfo *attr, // IN/OUT: getattr info
+ HgfsAttrHint *hints, // OUT: setattr hints
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize, // OUT: cpName size
+ HgfsHandle *file, // OUT: server file ID
+ uint32 *caseFlags); // OUT: case-sensitivity flags
Bool
HgfsPackSetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
+ char const *packetHeader, // IN: packet header
HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
+ size_t *payloadSize, // OUT: size of packet
HgfsSessionInfo *session); // IN: Session Info
Bool
-HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming packet
+HgfsUnpackCreateDirRequest(void const *packet, // IN: HGFS packet
size_t packetSize, // IN: size of packet
+ HgfsOp op, // IN: requested operation
HgfsCreateDirInfo *info); // IN/OUT: info struct
Bool
HgfsPackCreateDirReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: create dir operation version
- HgfsInternalStatus status , // IN: reply status
+ char const *packetHeader, // IN: packet header
HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
+ size_t *payloadSize, // OUT: size of packet
HgfsSessionInfo *session); // IN: Session Info
Bool
-HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet
+HgfsPackQueryVolumeReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ uint64 freeBytes, // IN: volume free space
+ uint64 totalBytes, // IN: volume capacity
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
+Bool
+HgfsUnpackQueryVolumeRequest(void const *packet, // IN: HGFS packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ Bool *useHandle, // OUT: use handle
+ char **fileName, // OUT: file name
+ size_t *fileNameLength, // OUT: file name length
+ uint32 *caseFlags, // OUT: case sensitivity
+ HgfsHandle *file); // OUT: Handle to the volume
+Bool
+HgfsUnpackSymlinkCreateRequest(void const *packet, // IN: request packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ Bool *srcUseHandle, // OUT: use source handle
+ char **srcFileName, // OUT: source file name
+ size_t *srcFileNameLength, // OUT: source file name length
+ uint32 *srcCaseFlags, // OUT: source case sensitivity
+ HgfsHandle *srcFile, // OUT: source file handle
+ Bool *tgUseHandle, // OUT: use target handle
+ char **tgFileName, // OUT: target file name
+ size_t *tgFileNameLength, // OUT: target file name length
+ uint32 *tgCaseFlags, // OUT: target case sensitivity
+ HgfsHandle *tgFile); // OUT: target file handle
+Bool
+HgfsUnpackWriteWin32StreamRequest(void const *packet, // IN: HGFS packet
size_t packetSize, // IN: size of packet
- HgfsOp *op, // OUT: request type
+ HgfsOp op, // IN: request type
HgfsHandle *file, // OUT: file to write to
char **payload, // OUT: data to write
size_t *requiredSize, // OUT: size of data
Bool *doSecurity); // OUT: restore sec.str.
-
+Bool
+HgfsUnpackCreateSessionRequest(void const *packetHeader, // IN: request packet
+ size_t packetSize, // IN: size of packet
+ HgfsOp op, // IN: request type
+ HgfsCreateSessionInfo *info); // IN/OUT: info struct
Bool
HgfsPackWriteWin32StreamReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
+ char const *packetHeader, // IN: packet headert
HgfsOp op, // IN: request type
- uint32 actualSize, // IN: amount written
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
+ uint32 actualSize, // IN: amount written
+ size_t *payloadSize, // OUT: size of packet
HgfsSessionInfo *session); // IN:Session Info
Bool
-HgfsUnpackCloseRequest(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- HgfsOp *op, // OUT: request type
- HgfsHandle *file); // OUT: Handle to close
-
+HgfsUnpackCloseRequest(void const *packet, // IN: request packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ HgfsHandle *file); // OUT: Handle to close
+Bool
+HgfsUnpackSearchOpenRequest(void const *packet, // IN: HGFS packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ char **dirName, // OUT: directory name
+ uint32 *dirNameLength, // OUT: name length
+ uint32 *caseFlags); // OUT: case flags
Bool
HgfsPackCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
+ char const *packetHeader, // IN: packet header
HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
+ size_t *payloadSize, // OUT: size of packet
HgfsSessionInfo *session); // IN: Session Info
Bool
-HgfsUnpackSearchCloseRequest(char const *packetIn, // IN: request packet
- size_t packetSize, // IN: request packet size
- HgfsOp *op, // OUT: request type
- HgfsHandle *file); // OUT: Handle to close
-
+HgfsUnpackSearchCloseRequest(void const *packet, // IN: request packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ HgfsHandle *file); // OUT: Handle to close
Bool
-HgfsPackSearchCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize, // OUT: size of packet
- HgfsSessionInfo *session); // IN: Session Info
-
+HgfsPackSearchOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ HgfsHandle search, // IN: search handle
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
+Bool
+HgfsPackSearchCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
+Bool
+HgfsPackWriteReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ uint32 actualSize, // IN: number of bytes that were written
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session info
+Bool
+HgfsUnpackReadRequest(void const *packet, // IN: HGFS request
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ HgfsHandle *file, // OUT: Handle to close
+ uint64 *offset, // OUT: offset to read from
+ uint32 *length); // OUT: length of data to read
+Bool
+HgfsUnpackWriteRequest(HgfsInputParam *input, // IN: Input params
+ HgfsHandle *file, // OUT: Handle to write to
+ uint64 *offset, // OUT: offset to write to
+ uint32 *length, // OUT: length of data to write
+ HgfsWriteFlags *flags, // OUT: write flags
+ char **data); // OUT: data to be written
+Bool
+HgfsPackCreateSessionReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
+Bool
+HgfsPackDestorySessionReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
/* Node cache functions. */
Bool
Bool
HgfsServerCheckOpenFlagsForShare(HgfsFileOpenInfo *openInfo, // IN: Hgfs file handle
HgfsOpenFlags *flags); // IN/OUT: open mode
+HgfsInternalStatus
+HgfsPlatformConvertFromNameStatus(HgfsNameStatus status); // IN: name status
+HgfsInternalStatus
+HgfsPlatformSymlinkCreate(char *localSymlinkName, // IN: symbolic link file name
+ char *localTargetName); // IN: symlink target name
+HgfsInternalStatus
+HgfsPlatformGetattrFromName(char *fileName, // IN: file name
+ HgfsShareOptions configOptions, // IN: configuration options
+ char *shareName, // IN: share name
+ HgfsFileAttrInfo *attr, // OUT: file attributes
+ char **targetName); // OUT: Symlink target
+HgfsInternalStatus
+HgfsPlatformSearchDir(HgfsNameStatus nameStatus, // IN: name status
+ char *dirName, // IN: relative directory name
+ uint32 dirNameLength, // IN: length of dirName
+ uint32 caseFlags, // IN: case flags
+ HgfsShareInfo *shareInfo, // IN: sharfed folder information
+ char *baseDir, // IN: name of the shared directory
+ uint32 baseDirLen, // IN: length of the baseDir
+ HgfsSessionInfo *session, // IN: session info
+ HgfsHandle *handle); // OUT: search handle
+HgfsInternalStatus
+HgfsAccess(char *fileName, // IN: local file path
+ char *shareName, // IN: Name of the share
+ size_t shareNameLen); // IN: Length of the share name
+HgfsInternalStatus
+HgfsPlatformReadFile(HgfsHandle file, // IN: Hgfs file handle
+ HgfsSessionInfo *session, // IN: session info
+ uint64 offset, // IN: file offset to read from
+ uint32 requiredSize, // IN: length of data to read
+ void* payload, // OUT: buffer for the read data
+ uint32 *actualSize); // OUT: actual length read
+HgfsInternalStatus
+HgfsPlatformWriteFile(HgfsHandle file, // IN: Hgfs file handle
+ HgfsSessionInfo *session, // IN: session info
+ uint64 offset, // IN: file offset to write to
+ uint32 requiredSize, // IN: length of data to write
+ HgfsWriteFlags flags, // IN: write flags
+ void* payload, // IN: data to be written
+ uint32 *actualSize); // OUT: actual length written
+HgfsInternalStatus
+HgfsPlatformWriteWin32Stream(HgfsHandle file, // IN: packet header
+ char *dataToWrite, // IN: data to write
+ size_t requiredSize, // IN: data size
+ Bool doSecurity, // IN: write ACL
+ uint32 *actualSize, // OUT: written data size
+ HgfsSessionInfo *session); // IN: session info
+Bool
+HgfsValidatePacket(char const *packetIn, // IN: HGFS packet
+ size_t packetSize, // IN: HGFS packet size
+ Bool v4header); // IN: HGFS header type
+void
+HgfsPackReplyHeaderV4(HgfsInternalStatus status, // IN: platfrom independent HGFS status code
+ uint32 payloadSize, // IN: size of HGFS operational packet
+ HgfsOp op, // IN: request type
+ uint64 sessionId, // IN: session id
+ uint32 requestId, // IN: request id
+ HgfsHeader *header); // OUT: packet header
+HgfsInternalStatus
+HgfsPlatformGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle
+ HgfsSessionInfo *session, // IN: Session info
+ Bool append, // IN: Open with append flag
+ fileDesc *fd); // OUT: Opened file descriptor
+HgfsInternalStatus
+HgfsPlatformFileExists(char *utf8LocalName); // IN: Full file path utf8 encoding
+
+/*
+ * NOTE.
+ * This function requires valid localSrcName and localTargetName even when
+ * srcFile and targetFile are specified.
+ * Depending on some various conditions it may fall back on using file names
+ * instead of file handles.
+ */
+HgfsInternalStatus
+HgfsPlatformRename(char *localSrcName, // IN: local path to source file
+ fileDesc srcFile, // IN: source file handle
+ char *localTargetName, // IN: local path to target file
+ fileDesc targetFile, // IN: target file handle
+ HgfsRenameHint hints); // IN: rename hints
+HgfsInternalStatus
+HgfsPlatformCreateDir(HgfsCreateDirInfo *info, // IN: direcotry properties
+ char *utf8Name); // IN: full path for the new directory
+HgfsInternalStatus
+HgfsPlatformDeleteFileByHandle(HgfsHandle file, // IN: file being deleted
+ HgfsSessionInfo *session); // IN: session info
+HgfsInternalStatus
+HgfsPlatformDeleteFileByName(char const *utf8Name); // IN: full file path in utf8 encoding
+HgfsInternalStatus
+HgfsPlatformDeleteDirByHandle(HgfsHandle dir, // IN: directory being deleted
+ HgfsSessionInfo *session); // IN: session info
+HgfsInternalStatus
+HgfsPlatformDeleteDirByName(char const *utf8Name); // IN: full file path in utf8 encoding
+HgfsInternalStatus
+HgfsPlatformHandleIncompleteName(HgfsNameStatus nameStatus, // IN: name status
+ HgfsFileAttrInfo *attr); // OUT: attributes
+void
+HgfsPlatformGetDefaultDirAttrs(HgfsFileAttrInfo *attr); // OUT: attributes
+HgfsInternalStatus
+HgfsPlatformGetattrFromFd(fileDesc fileDesc, // IN: file descriptor to query
+ HgfsSessionInfo *session, // IN: session info
+ HgfsFileAttrInfo *attr); // OUT: file attributes
+HgfsInternalStatus
+HgfsPlatformSetattrFromFd(HgfsHandle file, // IN: file descriptor
+ HgfsSessionInfo *session, // IN: session info
+ HgfsFileAttrInfo *attr, // IN: attrs to set
+ HgfsAttrHint hints); // IN: attr hints
+HgfsInternalStatus
+HgfsPlatformSetattrFromName(char *utf8Name, // IN: local file path
+ HgfsFileAttrInfo *attr, // IN: attrs to set
+ HgfsShareOptions configOptions, // IN: share options
+ HgfsAttrHint hints); // IN: attr hints
+HgfsInternalStatus
+HgfsPlatformValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct
+ Bool followLinks, // IN: follow symlinks on the host
+ HgfsSessionInfo *session, // IN: Session info
+ HgfsLocalId *localId, // OUT: Local unique file ID
+ fileDesc *newHandle); // OUT: Handle to the file
+void HgfsServerSessionGet(HgfsSessionInfo *session); // IN: session context
void *
HSPU_GetBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet
void
HSPU_PutPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
- HgfsSessionInfo *session); // IN: Session Info
+ HgfsSessionInfo *session); // IN: Session Info
void
HSPU_PutBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet
uint32 startIndex, // IN: Start of iov
void **buf, // IN/OUT: Buffer to be freed
size_t *bufSize, // IN: Size of the buffer
- Bool *isAllocated, // IN: Was buffer allocated ?
- MappingType mappingType, // IN: Readable/ Writeable ?
- HgfsSessionInfo *session); // IN: Session info
+ Bool *isAllocated, // IN: Was buffer allocated ?
+ MappingType mappingType, // IN: Readable/ Writeable ?
+ HgfsSessionInfo *session); // IN: Session info
void
HSPU_PutDataPacketBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet
};
/* Local functions. */
-static HgfsInternalStatus HgfsConvertFromNameStatus(HgfsNameStatus status);
-
static HgfsInternalStatus HgfsGetattrResolveAlias(char const *fileName,
char **targetName);
-static HgfsInternalStatus HgfsGetattrFromName(char *fileName,
- HgfsShareOptions configOptions,
- char *shareName,
- HgfsFileAttrInfo *attr,
- char **targetName);
-static HgfsInternalStatus HgfsAccess(char *fileName,
- char *shareName,
- size_t shareNameLen);
-
-static HgfsInternalStatus HgfsGetattrFromFd(int fd,
- HgfsSessionInfo *session,
- HgfsFileAttrInfo *attr);
-
static void HgfsStatToFileAttr(struct stat *stats,
uint64 *creationTime,
HgfsFileAttrInfo *attr);
struct timeval *modTime,
Bool *timesChanged);
-static HgfsInternalStatus HgfsSetattrFromFd(HgfsHandle file,
- HgfsSessionInfo *session,
- HgfsFileAttrInfo *attr,
- HgfsAttrHint hints);
-
-static HgfsInternalStatus HgfsSetattrFromName(char *cpName,
- size_t cpNameSize,
- HgfsFileAttrInfo *attr,
- HgfsAttrHint hints,
- uint32 caseFlags,
- HgfsSessionInfo *session);
-
-static Bool HgfsIsShareRoot(char const *cpName, size_t cpNameSize);
static HgfsInternalStatus HgfsGetHiddenXAttr(char const *fileName, Bool *attribute);
static HgfsInternalStatus HgfsSetHiddenXAttr(char const *fileName, Bool value);
static HgfsInternalStatus HgfsEffectivePermissions(char *fileName,
/*
*-----------------------------------------------------------------------------
*
- * HgfsConvertFromNameStatus --
+ * HgfsPlatformConvertFromNameStatus --
*
* This function converts between a status code used in processing a cross
* platform filename, and a platform-specific status code.
*-----------------------------------------------------------------------------
*/
-static HgfsInternalStatus
-HgfsConvertFromNameStatus(HgfsNameStatus status) // IN
+HgfsInternalStatus
+HgfsPlatformConvertFromNameStatus(HgfsNameStatus status) // IN
{
switch(status) {
case HGFS_NAME_STATUS_COMPLETE:
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerGetDefaultDirAttrs --
+ * HgfsPlatformGetDefaultDirAttrs --
*
* Get default directory attributes. Permissions are Read and
* Execute permission only.
*-----------------------------------------------------------------------------
*/
-static void
-HgfsServerGetDefaultDirAttrs(HgfsFileAttrInfo *attr) // OUT
+void
+HgfsPlatformGetDefaultDirAttrs(HgfsFileAttrInfo *attr) // OUT
{
struct timeval tv;
uint64 hgfsTime;
/*
*-----------------------------------------------------------------------------
*
- * HgfsGetFd --
+ * HgfsPlatformGetFd --
*
* Returns the file descriptor associated with the node. If the node is
* cached then it just returns the cached file descriptor (checking for
*-----------------------------------------------------------------------------
*/
-static HgfsInternalStatus
-HgfsGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle
- HgfsSessionInfo *session, // IN: Session info
- Bool append, // IN: Open with append flag
- fileDesc *fd) // OUT: Opened file descriptor
+HgfsInternalStatus
+HgfsPlatformGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle
+ HgfsSessionInfo *session, // IN: Session info
+ Bool append, // IN: Open with append flag
+ fileDesc *fd) // OUT: Opened file descriptor
{
int newFd = -1, openFlags = 0;
HgfsFileNode node;
*-----------------------------------------------------------------------------
*/
-static HgfsInternalStatus
-HgfsValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct
- int followSymlinks, // IN: followSymlinks config option
- HgfsSessionInfo *session, // IN: session info
- HgfsLocalId *localId, // OUT: Local unique file ID
- int *fileDesc) // OUT: Handle to the file
+HgfsInternalStatus
+HgfsPlatformValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct
+ Bool followSymlinks, // IN: followSymlinks config option
+ HgfsSessionInfo *session, // IN: session info
+ HgfsLocalId *localId, // OUT: Local unique file ID
+ fileDesc *fileDesc) // OUT: Handle to the file
{
struct stat fileStat;
int fd;
/*
*-----------------------------------------------------------------------------
*
- * HgfsGetattrFromName --
+ * HgfsPlatformGetattrFromName --
*
* Performs a stat operation on the given filename, and, if it is a symlink,
* allocates the target filename on behalf of the caller and performs a
*-----------------------------------------------------------------------------
*/
-static HgfsInternalStatus
-HgfsGetattrFromName(char *fileName, // IN/OUT: Input filename
- HgfsShareOptions configOptions, // IN: Share config options
- char *shareName, // IN: Share name
- HgfsFileAttrInfo *attr, // OUT: Struct to copy into
- char **targetName) // OUT: Symlink target filename
+HgfsInternalStatus
+HgfsPlatformGetattrFromName(char *fileName, // IN/OUT: Input filename
+ HgfsShareOptions configOptions, // IN: Share config options
+ char *shareName, // IN: Share name
+ HgfsFileAttrInfo *attr, // OUT: Struct to copy into
+ char **targetName) // OUT: Symlink target
{
HgfsInternalStatus status = 0;
struct stat stats;
targetName, NULL)) {
LOG(4, ("%s: Unable to normalize form C \"%s\"\n",
__FUNCTION__, myTargetName));
- status = HgfsConvertFromNameStatus(HGFS_NAME_STATUS_FAILURE);
+ status = HgfsPlatformConvertFromNameStatus(HGFS_NAME_STATUS_FAILURE);
goto exit;
}
#else
return status;
}
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsAccess --
- *
- * Check is a file with the given name exists and accessible, error code
- * otherwise.
- * The function does not follow symlinks unless HGFS_SHARE_FOLLOW_SYMLINKS
- * flag is specified for the shared folder.
- *
- * Results:
- * Zero on success.
- * Non-zero on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-static HgfsInternalStatus
-HgfsAccess(char *fileName, // IN: local file path
- char *shareName, // IN: Name of the share
- size_t shareNameLen) // IN: Length of the share name
-{
- HgfsFileAttrInfo attr;
- HgfsShareOptions configOptions;
- HgfsNameStatus nameStatus;
- HgfsInternalStatus status;
-
- /* Get the config options. */
- nameStatus = HgfsServerPolicy_GetShareOptions(shareName, shareNameLen,
- &configOptions);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, shareName));
- status = ENOENT;
- } else {
- status = HgfsGetattrFromName(fileName, configOptions, shareName,
- &attr, NULL);
- }
- return status;
-}
-
/*
*-----------------------------------------------------------------------------
*
- * HgfsGetattrFromFd --
+ * HgfsPlatformGetattrFromFd --
*
* Performs a stat operation on the given file desc.
* Does necessary translation between Unix file stats and the
*-----------------------------------------------------------------------------
*/
-static HgfsInternalStatus
-HgfsGetattrFromFd(int fd, // IN: file descriptor
- HgfsSessionInfo *session, // IN: session info
- HgfsFileAttrInfo *attr) // OUT: FileAttrInfo to copy into
+HgfsInternalStatus
+HgfsPlatformGetattrFromFd(fileDesc fileDesc, // IN: file descriptor
+ HgfsSessionInfo *session, // IN: session info
+ HgfsFileAttrInfo *attr) // OUT: FileAttrInfo to copy into
{
HgfsInternalStatus status = 0;
struct stat stats;
ASSERT(attr);
ASSERT(session);
- LOG(4, ("%s: getting attrs for %u\n", __FUNCTION__, fd));
+ LOG(4, ("%s: getting attrs for %u\n", __FUNCTION__, fileDesc));
- error = HgfsFStat(fd, &stats, &creationTime);
+ error = HgfsFStat(fileDesc, &stats, &creationTime);
if (error) {
LOG(4, ("%s: error stating file: %s\n", __FUNCTION__, strerror(error)));
status = error;
* are cached, for setting attributes, renaming and deletion.
*/
- if (!HgfsFileDesc2Handle(fd, session, &handle)) {
- LOG(4, ("%s: could not get HGFS handle for fd %u\n", __FUNCTION__, fd));
+ if (!HgfsFileDesc2Handle(fileDesc, session, &handle)) {
+ LOG(4, ("%s: could not get HGFS handle for fd %u\n", __FUNCTION__, fileDesc));
status = EBADF;
goto exit;
}
if (!HgfsHandle2ShareMode(handle, session, &shareMode)) {
- LOG(4, ("%s: could not get share mode fd %u\n", __FUNCTION__, fd));
+ LOG(4, ("%s: could not get share mode fd %u\n", __FUNCTION__, fileDesc));
status = EBADF;
goto exit;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsSetattrFromFd --
+ * HgfsPlatformSetattrFromFd --
*
* Handle a Setattr request by file descriptor.
*
*-----------------------------------------------------------------------------
*/
-static HgfsInternalStatus
-HgfsSetattrFromFd(HgfsHandle file, // IN: file descriptor
- HgfsSessionInfo *session, // IN: session info
- HgfsFileAttrInfo *attr, // OUT: attrs to set
- HgfsAttrHint hints) // IN: attr hints
+HgfsInternalStatus
+HgfsPlatformSetattrFromFd(HgfsHandle file, // IN: file descriptor
+ HgfsSessionInfo *session, // IN: session info
+ HgfsFileAttrInfo *attr, // OUT: attrs to set
+ HgfsAttrHint hints) // IN: attr hints
{
HgfsInternalStatus status = 0, timesStatus;
int error;
Bool idChanged = FALSE;
int fd;
HgfsServerLock serverLock;
- HgfsOpenMode shareMode;
ASSERT(session);
ASSERT(file != HGFS_INVALID_HANDLE);
- status = HgfsGetFd(file, session, FALSE, &fd);
+ status = HgfsPlatformGetFd(file, session, FALSE, &fd);
if (status != 0) {
LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
goto exit;
}
- if (!HgfsHandle2ShareMode(file, session, &shareMode)) {
- LOG(4, ("%s: could not get share mode fd %u\n", __FUNCTION__, fd));
- status = EBADF;
- goto exit;
- }
-
- if (shareMode == HGFS_OPEN_MODE_READ_ONLY) {
- status = EACCES;
- goto exit;
- }
-
/* We need the old stats so that we can preserve times. */
if (fstat(fd, &statBuf) == -1) {
error = errno;
/*
*-----------------------------------------------------------------------------
*
- * HgfsSetattrFromName --
+ * HgfsPlatformSetattrFromName --
*
* Handle a Setattr request by name.
*
*
*-----------------------------------------------------------------------------
*/
-static HgfsInternalStatus
-HgfsSetattrFromName(char *cpName, // IN: Name
- size_t cpNameSize, // IN: Name length
- HgfsFileAttrInfo *attr, // IN: attrs to set
- HgfsAttrHint hints, // IN: attr hints
- uint32 caseFlags, // IN: case-sensitivity flags
- HgfsSessionInfo *session) // IN: session info
+HgfsInternalStatus
+HgfsPlatformSetattrFromName(char *localName, // IN: Name
+ HgfsFileAttrInfo *attr, // IN: attrs to set
+ HgfsShareOptions configOptions, // IN: share options
+ HgfsAttrHint hints) // IN: attr hints
{
HgfsInternalStatus status = 0, timesStatus;
- HgfsNameStatus nameStatus;
- int error, fd;
- char *localName;
struct stat statBuf;
struct timeval times[2];
mode_t newPermissions;
Bool permsChanged = FALSE;
Bool timesChanged = FALSE;
Bool idChanged = FALSE;
- HgfsServerLock serverLock;
- HgfsShareOptions configOptions;
- size_t localNameLen;
- HgfsShareInfo shareInfo;
-
- nameStatus = HgfsServerGetShareInfo(cpName,
- cpNameSize,
- caseFlags,
- &shareInfo,
- &localName,
- &localNameLen);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: access check failed\n", __FUNCTION__));
- status = HgfsConvertFromNameStatus(nameStatus);
- goto exit;
- }
+ int error;
ASSERT(localName);
- /* Get the config options. */
- nameStatus = HgfsServerPolicy_GetShareOptions(cpName, cpNameSize,
- &configOptions);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, cpName));
- goto exit;
- }
if (!HgfsServerPolicy_IsShareOptionSet(configOptions,
HGFS_SHARE_FOLLOW_SYMLINKS)) {
if (File_IsSymLink(localName)) {
LOG(4, ("%s: pathname contains a symlink\n", __FUNCTION__));
status = EINVAL;
- goto exit_free;
+ goto exit;
}
}
LOG(4, ("%s: error stating file \"%s\": %s\n", __FUNCTION__,
localName, strerror(error)));
status = error;
- goto exit_free;
- }
-
- if (!HgfsServerPolicy_CheckMode(HGFS_OPEN_MODE_WRITE_ONLY,
- shareInfo.writePermissions,
- shareInfo.readPermissions)) {
- status = EACCES;
- goto exit_free;
+ goto exit;
}
/*
}
if (attr->mask & HGFS_ATTR_VALID_SIZE) {
- /*
- * XXX: Truncating the file will trigger an oplock break. The client
- * should have predicted this and removed the oplock prior to sending
- * the truncate request. At this point, the server must safeguard itself
- * against deadlock.
- */
- if (HgfsFileHasServerLock(localName, session, &serverLock, &fd)) {
- LOG(4, ("%s: Client attempted to truncate an oplocked file\n",
- __FUNCTION__));
- status = EBUSY;
- } else if (Posix_Truncate(localName, attr->size) < 0) {
+ if (Posix_Truncate(localName, attr->size) < 0) {
error = errno;
LOG(4, ("%s: error truncating file \"%s\": %s\n", __FUNCTION__,
localName, strerror(error)));
status = timesStatus;
}
-exit_free:
- free(localName);
exit:
return status;
}
+HgfsInternalStatus
+HgfsPlatformWriteWin32Stream(HgfsHandle file, // IN: packet header
+ char *dataToWrite, // IN: request type
+ size_t requiredSize,
+ Bool doSecurity,
+ uint32 *actualSize,
+ HgfsSessionInfo *session)
+{
+ return EPROTO;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsConvertToUtf8FormC --
+ *
+ * Converts file name coming from OS to Utf8 form C.
+ * The function NOOP on Linux where the name is already in correct
+ * encoding.
+ * On Mac OS the default encoding is Utf8 form D thus a convertion to
+ * Utf8 for C is required.
+ *
+ * Results:
+ * TRUE on success. Buffer has name in Utf8 form C encoding.
+ * FALSE on error.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsConvertToUtf8FormC(char *buffer, // IN/OUT: name to normalize
+ size_t bufferSize) // IN: size of the name buffer
+{
+#if defined(__APPLE__)
+ size_t entryNameLen;
+ char *entryName = NULL;
+ Bool result;
+
+ /*
+ * HGFS clients receive names in unicode normal form C,
+ * (precomposed) so Mac hosts must convert from normal form D
+ * (decomposed).
+ */
+
+ if (CodeSet_Utf8FormDToUtf8FormC(buffer, bufferSize, &entryName, &entryNameLen)) {
+ result = entryNameLen < bufferSize;
+ if (result) {
+ memcpy(buffer, entryName, entryNameLen + 1);
+ }
+ free(entryName);
+ } else {
+ LOG(4, ("%s: Unable to normalize form C \"%s\"\n", __FUNCTION__, buffer));
+ result = FALSE;
+ }
+
+ return result;
+#else
+ /* NOOP on Linux where the name is already has the correct encoding. */
+ return TRUE;
+#endif /* defined(__APPLE__) */
+}
+
+
/*
*-----------------------------------------------------------------------------
*
status = ENOMEM;
goto exit;
}
- memcpy(myDents[myNumDents], newDent, newDent->d_reclen);
- /*
- * Dent is done. Bump the offset to the batched buffer to process the
- * next dent within it.
- */
- myNumDents++;
+ if (HgfsConvertToUtf8FormC(newDent->d_name, sizeof newDent->d_name)) {
+ memcpy(myDents[myNumDents], newDent, newDent->d_reclen);
+ /*
+ * Dent is done. Bump the offset to the batched buffer to process the
+ * next dent within it.
+ */
+ myNumDents++;
+ } else {
+ /*
+ * XXX:
+ * HGFS discards all file names that can't be converted to utf8.
+ * It is not desirable since it causes many problems like
+ * failure to delete directories which contain such files.
+ * Need to change this to a more reasonable behavior, similar
+ * to name escaping which is used to deal with illegal file names.
+ */
+ free(myDents[myNumDents]);
+ }
offset += newDent->d_reclen;
}
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerOpen --
- *
- * Handle an Open request.
- *
- * Results:
- * Zero on success.
- * Non-zero on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-HgfsInternalStatus
-HgfsServerOpen(HgfsInputParam *input) // IN: Input params
-{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
- HgfsNameStatus nameStatus;
- HgfsInternalStatus status;
- int newFd = -1;
- HgfsLocalId localId;
- HgfsFileOpenInfo openInfo;
- char *localName = NULL;
- HgfsServerLock serverLock = HGFS_LOCK_NONE;
- HgfsShareOptions configOptions;
- int followSymlinks;
- char *packetOut;
- size_t packetOutSize;
- HgfsOpenFlags savedOpenFlags = 0;
- size_t localNameLen;
-
- ASSERT(packetIn);
- ASSERT(session);
-
- if (!HgfsUnpackOpenRequest(packetIn, packetSize, &openInfo)) {
- status = EPROTO;
- goto exit;
- }
-
- /* HGFS_OPEN_VALID_FILE_NAME is checked in the unpack function. */
- if (!(openInfo.mask & HGFS_OPEN_VALID_MODE)) {
- LOG(4, ("%s: filename or mode not provided\n", __FUNCTION__));
- status = EINVAL;
- goto exit;
- }
-
- nameStatus = HgfsServerGetShareInfo(openInfo.cpName,
- openInfo.cpNameSize,
- openInfo.caseFlags,
- &openInfo.shareInfo,
- &localName,
- &localNameLen);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: access check failed\n", __FUNCTION__));
- status = HgfsConvertFromNameStatus(nameStatus);
- goto exit;
- }
-
- if (openInfo.mask & HGFS_OPEN_VALID_FLAGS) {
- savedOpenFlags = openInfo.flags;
- if (!HgfsServerCheckOpenFlagsForShare(&openInfo, &openInfo.flags)) {
- /* Incompatible open mode with share mode. */
- status = EACCES;
- goto exit;
- }
- }
-
- ASSERT(localName);
- openInfo.utf8Name = localName;
-
- LOG(4, ("%s: opening \"%s\", mode %u, flags %u, perms %u%u%u%u\n",
- __FUNCTION__, openInfo.utf8Name,
- (openInfo.mask & HGFS_OPEN_VALID_MODE) ? openInfo.mode : 0,
- (openInfo.mask & HGFS_OPEN_VALID_FLAGS) ? openInfo.flags : 0,
- (openInfo.mask & HGFS_OPEN_VALID_SPECIAL_PERMS) ?
- openInfo.specialPerms : 0,
- (openInfo.mask & HGFS_OPEN_VALID_OWNER_PERMS) ?
- openInfo.ownerPerms : 0,
- (openInfo.mask & HGFS_OPEN_VALID_GROUP_PERMS) ?
- openInfo.groupPerms : 0,
- (openInfo.mask & HGFS_OPEN_VALID_OTHER_PERMS) ?
- openInfo.otherPerms : 0));
-
- /*
- * XXX: Before opening the file, see if we already have this file opened on
- * the server with an oplock on it. If we do, we must fail the new open
- * request, otherwise we will trigger an oplock break that the guest cannot
- * handle at this time (since the HGFS server is running in the context of
- * the vcpu thread), and we'll deadlock.
- *
- * Until we overcome this limitation via Crosstalk, we will be extra smart
- * in the client drivers so as to prevent open requests on handles that
- * already have an oplock. And the server will protect itself like so.
- *
- * XXX: With some extra effort, we could allow a second open for read here,
- * since that won't break a shared oplock, but the clients should already
- * realize that the second open can be avoided via sharing handles, too.
- */
- if (HgfsFileHasServerLock(localName, session, &serverLock, &newFd)) {
- LOG (4, ("%s: Client tried to open new handle for oplocked file %s.\n",
- __FUNCTION__, localName));
- status = EBUSY;
- goto exit;
- }
-
- /* Get the config options. */
- nameStatus = HgfsServerPolicy_GetShareOptions(openInfo.cpName,
- openInfo.cpNameSize,
- &configOptions);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, openInfo.cpName));
- status = ENOENT;
- goto exit;
- }
-
- followSymlinks = HgfsServerPolicy_IsShareOptionSet(configOptions,
- HGFS_SHARE_FOLLOW_SYMLINKS);
-
- /* See if the name is valid, and if so add it and return the handle. */
- status = HgfsValidateOpen(&openInfo, followSymlinks, session, &localId,
- &newFd);
- if (status == 0) {
- ASSERT(newFd >= 0);
-
- /*
- * Open succeeded, so make new node and return its handle. If we fail,
- * it's almost certainly an internal server error.
- */
-
- if (!HgfsCreateAndCacheFileNode(&openInfo, &localId, newFd, FALSE,
- session)) {
- status = HGFS_INTERNAL_STATUS_ERROR;
- goto exit;
- }
-
- if (HgfsPackOpenReply(input->packet, packetIn, status, &openInfo, &packetOut,
- &packetOutSize, session)) {
- if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
- HSPU_PutReplyPacket(input->packet, session);
- }
- } else {
- status = EPROTO;
- }
- } else {
- /*
- * The open failed, if we modified the open flags, force the return
- * status to be access denied, not the error for the modified open.
- */
- if (openInfo.mask & HGFS_OPEN_VALID_FLAGS &&
- savedOpenFlags != openInfo.flags &&
- status == ENOENT) {
- status = EACCES;
- }
- }
-
- exit:
- free(localName);
- return status;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsServerRead --
+ * HgfsPlatformReadFile --
*
- * Handle a Read request.
+ * Reads data from a file.
*
* Results:
* Zero on success.
*/
HgfsInternalStatus
-HgfsServerRead(HgfsInputParam *input) // IN: Input params
+HgfsPlatformReadFile(HgfsHandle file, // IN: Hgfs file handle
+ HgfsSessionInfo *session, // IN: session info
+ uint64 offset, // IN: file offset to read from
+ uint32 requiredSize, // IN: length of data to read
+ void* payload, // OUT: buffer for the read data
+ uint32 *actualSize) // OUT: actual length read
{
- const char *packetIn = input->metaPacket;
- HgfsSessionInfo *session = input->session;
- HgfsRequest *header = (HgfsRequest *)packetIn;
int fd;
int error;
HgfsInternalStatus status;
- uint32 extra;
Bool sequentialOpen;
- HgfsHandle file;
- uint64 offset;
- uint32 requiredSize;
- char *payload;
- uint32 *replyActualSize;
- size_t replySize;
- size_t replyPacketSize;
- char *packetOut;
-
- ASSERT(packetIn);
- ASSERT(session);
-
- if (header->op == HGFS_OP_READ_FAST_V4) {
- HgfsRequestReadV3 *request =
- (HgfsRequestReadV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
- HgfsReplyReadV3 *reply;
-
- file = request->file;
- offset = request->offset;
- requiredSize = request->requiredSize;
-
- replySize = HGFS_REP_PAYLOAD_SIZE_V3(reply) - 1;
- /* Get a data packet buffer that is writeable */
- payload = HSPU_GetDataPacketBuf(input->packet, BUF_WRITEABLE, session);
- if (!payload) {
- ASSERT_DEVEL(payload);
- status = EPROTO;
- goto error;
- }
- replyPacketSize = replySize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
- reply = (HgfsReplyReadV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
-
- replyActualSize = &reply->actualSize;
- reply->reserved = 0;
-
- } else if (header->op == HGFS_OP_READ_V3) {
- HgfsRequestReadV3 *request =
- (HgfsRequestReadV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
- HgfsReplyReadV3 *reply;
-
- file = request->file;
- offset = request->offset;
- requiredSize = request->requiredSize;
-
- replySize = HGFS_REP_PAYLOAD_SIZE_V3(reply) - 1;
- ASSERT(HGFS_LARGE_PACKET_MAX >= replySize);
- extra = HGFS_LARGE_PACKET_MAX - replySize;
-
- /*
- * requiredSize is user-provided, so this test must be carefully
- * written to prevent wraparounds.
- */
- if (requiredSize > extra) {
- /*
- * The client wants to read more bytes than our payload can handle.
- * Truncate the request
- */
- requiredSize = extra;
- }
- replyPacketSize = replySize + requiredSize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, replySize + requiredSize, replyPacketSize, status, error);
- reply = (HgfsReplyReadV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
- payload = reply->payload;
- replyActualSize = &reply->actualSize;
- reply->reserved = 0;
- } else {
- HgfsRequestRead *request = (HgfsRequestRead *)packetIn;
- HgfsReplyRead *reply;
- file = request->file;
- offset = request->offset;
- requiredSize = request->requiredSize;
-
- replySize = sizeof *reply - 1;
- ASSERT(HGFS_PACKET_MAX >= replySize);
- extra = HGFS_PACKET_MAX - replySize;
-
- /*
- * requiredSize is user-provided, so this test must be carefully
- * written to prevent wraparounds.
- */
- if (requiredSize > extra) {
- /*
- * The client wants to read more bytes than our payload can handle.
- * Truncate the request
- */
- requiredSize = extra;
- }
+ ASSERT(session);
- replyPacketSize = replySize + requiredSize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, replySize + requiredSize, replyPacketSize, status, error);
- reply = (HgfsReplyRead *)packetOut;
- payload = reply->payload;
- replyActualSize = &reply->actualSize;
- }
LOG(4, ("%s: read fh %u, offset %"FMT64"u, count %u\n", __FUNCTION__,
file, offset, requiredSize));
/* Get the file descriptor from the cache */
- status = HgfsGetFd(file, session, FALSE, &fd);
+ status = HgfsPlatformGetFd(file, session, FALSE, &fd);
if (status != 0) {
LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
- goto error;
+ return status;
}
if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) {
LOG(4, ("%s: Could not get sequenial open status\n", __FUNCTION__));
- status = EBADF;
- goto error;
+ return EBADF;
}
#if defined(GLIBC_VERSION_21) || defined(__APPLE__)
MXUser_AcquireExclLock(session->fileIOLock);
- if (!sequentialOpen) {
+ if (sequentialOpen) {
+ error = 0; // No error from seek
+ } else {
# ifdef linux
{
uint64 res;
# else
error = lseek(fd, offset, 0);
# endif
+ }
- if (error < 0) {
- status = errno;
- LOG(4, ("%s: could not seek to %"FMT64"u: %s\n", __FUNCTION__,
- offset, strerror(status)));
- MXUser_ReleaseExclLock(session->fileIOLock);
- goto error;
- }
+ if (error >= 0) {
+ error = read(fd, payload, requiredSize);
+ } else {
+ LOG(4, ("%s: could not seek to %"FMT64"u: %s\n", __FUNCTION__,
+ offset, strerror(status)));
}
- error = read(fd, payload, requiredSize);
MXUser_ReleaseExclLock(session->fileIOLock);
#endif
if (error < 0) {
status = errno;
LOG(4, ("%s: error reading from file: %s\n", __FUNCTION__,
strerror(status)));
- goto error;
- }
-
- LOG(4, ("%s: read %d bytes\n", __FUNCTION__, error));
- *replyActualSize = error;
-
- if (header->op == HGFS_OP_READ_FAST_V4) {
- HSPU_PutDataPacketBuf(input->packet, session);
} else {
- replySize += error;
- }
-
- /* Send the reply. */
- if (!HgfsPackAndSendPacket(input->packet, packetOut, replySize, 0,
- header->id, session, 0)) {
- status = 0;
- goto error;
+ LOG(4, ("%s: read %d bytes\n", __FUNCTION__, error));
+ *actualSize = error;
}
- return 0;
-error:
- HSPU_PutReplyPacket(input->packet, session);
return status;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerWrite --
+ * HgfsPlatformWriteFile --
*
- * Handle a Write request.
+ * Performs actual writing data to a file.
*
* Results:
* Zero on success.
*/
HgfsInternalStatus
-HgfsServerWrite(HgfsInputParam *input) // IN: Input params
+HgfsPlatformWriteFile(HgfsHandle file, // IN: Hgfs file handle
+ HgfsSessionInfo *session, // IN: session info
+ uint64 offset, // IN: file offset to write to
+ uint32 requiredSize, // IN: length of data to write
+ HgfsWriteFlags flags, // IN: write flags
+ void* payload, // IN: data to be written
+ uint32 *actualSize) // OUT: actual length written
{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
- HgfsRequest *header = (HgfsRequest *)packetIn;
HgfsInternalStatus status;
int fd;
- int error;
+ int error = 0;
Bool sequentialOpen;
- HgfsHandle file;
- HgfsWriteFlags flags;
- uint64 offset;
- uint32 requiredSize;
- char *payload;
- uint32 *actualSize;
- size_t replySize;
- size_t replyPacketSize;
- char *packetOut;
-
- ASSERT(packetIn);
- ASSERT(session);
-
- if (header->op == HGFS_OP_WRITE_FAST_V4) {
- HgfsRequestWriteV3 *request;
- HgfsReplyWriteV3 *reply;
-
- replySize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
- replyPacketSize = replySize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
-
- request = (HgfsRequestWriteV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
- reply = (HgfsReplyWriteV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
-
- /* Enforced by the dispatch function */
- ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
-
- file = request->file;
- flags = request->flags;
- offset = request->offset;
- requiredSize = request->requiredSize;
- reply->reserved = 0;
- actualSize = &reply->actualSize;
- /* Get a data packet buffer that is readable */
- payload = HSPU_GetDataPacketBuf(input->packet, BUF_READABLE, session);
- if (!payload) {
- ASSERT_DEVEL(payload);
- status = EPROTO;
- goto error;
- }
- } else if (header->op == HGFS_OP_WRITE_V3) {
- HgfsRequestWriteV3 *request;
- HgfsReplyWriteV3 *reply;
- uint32 extra;
-
- replySize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
- replyPacketSize = replySize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
-
- request = (HgfsRequestWriteV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
- reply = (HgfsReplyWriteV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
+ LOG(4, ("%s: write fh %u, offset %"FMT64"u, count %u\n",
+ __FUNCTION__, file, offset, requiredSize));
- /* Enforced by the dispatch function */
- ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
- extra = packetSize - (HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
+ /* Get the file desriptor from the cache */
+ status = HgfsPlatformGetFd(file, session,
+ ((flags & HGFS_WRITE_APPEND) ? TRUE : FALSE),
+ &fd);
- file = request->file;
- flags = request->flags;
- offset = request->offset;
- requiredSize = request->requiredSize;
- reply->reserved = 0;
- actualSize = &reply->actualSize;
+ if (status != 0) {
+ LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
+ return status;
+ }
- payload = request->payload;
-
- /*
- * requiredSize is user-provided, so this test must be carefully
- * written to prevent wraparounds.
- */
- if (requiredSize > extra) {
- requiredSize = extra;
- }
-
- } else {
- HgfsRequestWrite *request;
- HgfsReplyWrite *reply;
- uint32 extra;
-
- replySize = sizeof *reply;
- replyPacketSize = replySize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
-
- request = (HgfsRequestWrite *)packetIn;
- reply = (HgfsReplyWrite *)packetOut;
-
- /* Enforced by the dispatch function */
- ASSERT(packetSize >= sizeof *request - 1);
- extra = packetSize - (sizeof *request - 1);
-
- file = request->file;
- flags = request->flags;
- offset = request->offset;
- payload = request->payload;
- requiredSize = request->requiredSize;
- actualSize = &reply->actualSize;
-
- /*
- * requiredSize is user-provided, so this test must be carefully
- * written to prevent wraparounds.
- */
- if (requiredSize > extra) {
- requiredSize = extra;
- }
- }
-
- LOG(4, ("%s: write fh %u, offset %"FMT64"u, count %u\n",
- __FUNCTION__, file, offset, requiredSize));
-
- /* Get the file desriptor from the cache */
- status = HgfsGetFd(file, session, ((flags & HGFS_WRITE_APPEND) ?
- TRUE : FALSE),
- &fd);
-
- if (status != 0) {
- LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
- goto error;
- }
-
- if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) {
- LOG(4, ("%s: Could not get sequential open status\n", __FUNCTION__));
- status = EBADF;
- goto error;
- }
+ if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) {
+ LOG(4, ("%s: Could not get sequential open status\n", __FUNCTION__));
+ return EBADF;
+ }
#if defined(GLIBC_VERSION_21) || defined(__APPLE__)
/* Write to the file. */
error = lseek(fd, offset, 0);
# endif
+ }
+
+ if (error < 0) {
+ status = errno;
+ LOG(4, ("%s: could not seek to %"FMT64"u: %s\n", __FUNCTION__,
+ offset, strerror(status)));
+ } else {
+ error = write(fd, payload, requiredSize);
if (error < 0) {
status = errno;
- LOG(4, ("%s: could not seek to %"FMT64"u: %s\n", __FUNCTION__,
- offset, strerror(status)));
- MXUser_ReleaseExclLock(session->fileIOLock);
- goto error;
+ LOG(4, ("%s: error writing to file: %s\n", __FUNCTION__,
+ strerror(status)));
+ } else {
+ LOG(4, ("%s: wrote %d bytes\n", __FUNCTION__, error));
+ *actualSize = error;
}
}
-
- error = write(fd, payload, requiredSize);
MXUser_ReleaseExclLock(session->fileIOLock);
#endif
- if (error < 0) {
- status = errno;
- LOG(4, ("%s: error writing to file: %s\n", __FUNCTION__,
- strerror(status)));
- goto error;
- }
-
- LOG(4, ("%s: wrote %d bytes\n", __FUNCTION__, error));
- *actualSize = error;
- status = 0;
-
- if (header->op == HGFS_OP_WRITE_FAST_V4) {
- HSPU_PutDataPacketBuf(input->packet, session);
- }
-
- if (!HgfsPackAndSendPacket(input->packet, packetOut, replySize,
- 0, header->id, session, 0)) {
- goto error;
- }
-
- return 0;
-
-error:
- HSPU_PutReplyPacket(input->packet, session);
return status;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerSearchOpen --
+ * HgfsPlatformSearchDir --
*
- * Handle a "Search Open" request.
+ * Handle platform specific logic needed to perform search open request.
*
* Results:
* Zero on success.
*/
HgfsInternalStatus
-HgfsServerSearchOpen(HgfsInputParam *input) // IN: Input params
+HgfsPlatformSearchDir(HgfsNameStatus nameStatus, // IN: name status
+ char *dirName, // IN: relative directory name
+ uint32 dirNameLength, // IN: length of dirName
+ uint32 caseFlags, // IN: case flags
+ HgfsShareInfo *shareInfo, // IN: sharfed folder information
+ char *baseDir, // IN: name of the shared directory
+ uint32 baseDirLen, // IN: length of the baseDir
+ HgfsSessionInfo *session, // IN: session info
+ HgfsHandle *handle) // OUT: search handle
{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
- HgfsRequest *header;
- HgfsHandle *replySearch;
- uint32 extra;
- size_t baseDirLen;
- char *baseDir;
- HgfsHandle handle;
- HgfsInternalStatus status;
- HgfsNameStatus nameStatus;
- char *dirName;
- uint32 dirNameLength;
- HgfsCaseType caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
- size_t replySize;
- size_t replyPacketSize;
- char *packetOut;
- HgfsShareInfo shareInfo;
-
- ASSERT(packetIn);
- ASSERT(session);
- header = (HgfsRequest *)packetIn;
-
- if (header->op == HGFS_OP_SEARCH_OPEN_V3) {
- HgfsRequestSearchOpenV3 *requestV3;
- HgfsReplySearchOpenV3 *replyV3;
-
- replySize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
- replyPacketSize = replySize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, exit);
-
- requestV3 = (HgfsRequestSearchOpenV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
- replyV3 = (HgfsReplySearchOpenV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
-
- /* Enforced by the dispatch function */
- ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(requestV3));
- extra = packetSize - HGFS_REQ_PAYLOAD_SIZE_V3(requestV3);
-
- caseFlags = requestV3->dirName.caseType;
- dirName = requestV3->dirName.name;
- dirNameLength = requestV3->dirName.length;
- replySearch = &replyV3->search;
- replyV3->reserved = 0;
- LOG(4, ("%s: HGFS_OP_SEARCH_OPEN_V3\n", __FUNCTION__));
- } else {
- HgfsRequestSearchOpen *request = (HgfsRequestSearchOpen *)packetIn;
-
- replySize = sizeof (HgfsReplySearchOpen);
- replyPacketSize = replySize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, exit);
-
- /* Enforced by the dispatch function */
- ASSERT(packetSize >= sizeof *request);
- extra = packetSize - sizeof *request;
-
- dirName = request->dirName.name;
- dirNameLength = request->dirName.length;
- replySearch = &((HgfsReplySearchOpen *)packetOut)->search;
- }
-
- /*
- * request->dirName.length is user-provided, so this test must be carefully
- * written to prevent wraparounds.
- */
- if (dirNameLength > extra) {
- /* The input packet is smaller than the request */
- status = EPROTO;
- goto exit;
- }
-
- /* It is now safe to read the file name. */
- nameStatus = HgfsServerGetShareInfo(dirName,
- dirNameLength,
- caseFlags,
- &shareInfo,
- &baseDir,
- &baseDirLen);
+ HgfsInternalStatus status = 0;
switch (nameStatus) {
case HGFS_NAME_STATUS_COMPLETE:
{
/* Get the first component. */
len = CPName_GetComponent(dirName, inEnd, (char const **) &next);
- if (len < 0) {
+ if (len >= 0) {
+ if (*inEnd != '\0') {
+ /*
+ * NT4 clients can send the name without a nul-terminator.
+ * The space for the nul is included and tested for in the size
+ * calculations above. Size of structure (includes a single
+ * character of the name) and the full dirname length.
+ */
+ *inEnd = '\0';
+ }
+
+ LOG(4, ("%s: dirName: %s.\n", __FUNCTION__, dirName));
+ status = HgfsServerSearchRealDir(baseDir,
+ baseDirLen,
+ dirName,
+ shareInfo->rootDir,
+ session,
+ handle);
+ } else {
LOG(4, ("%s: get first component failed\n", __FUNCTION__));
status = ENOENT;
- goto exit;
- }
-
- if (*inEnd != '\0') {
- /*
- * NT4 clients can send the name without a nul-terminator.
- * The space for the nul is included and tested for in the size
- * calculations above. Size of structure (includes a single
- * character of the name) and the full dirname length.
- */
- *inEnd = '\0';
}
-
- LOG(4, ("%s: dirName: %s.\n", __FUNCTION__, dirName));
- status = HgfsServerSearchRealDir(baseDir,
- baseDirLen,
- dirName,
- shareInfo.rootDir,
- session,
- &handle);
- free(baseDir);
/*
* If the directory exists but shared folder is write only
* then return access denied, otherwise preserve the original
* error code.
*/
- if (!shareInfo.readPermissions && HGFS_NAME_STATUS_COMPLETE == status) {
+ if (!shareInfo->readPermissions && HGFS_NAME_STATUS_COMPLETE == status) {
status = HGFS_NAME_STATUS_ACCESS_DENIED;
}
if (status != 0) {
LOG(4, ("%s: couldn't scandir\n", __FUNCTION__));
- goto exit;
}
break;
}
HgfsServerPolicy_GetSharesCleanup,
DIRECTORY_SEARCH_TYPE_BASE,
session,
- &handle);
+ handle);
if (status != 0) {
LOG(4, ("%s: couldn't enumerate shares\n", __FUNCTION__));
- goto exit;
}
break;
default:
LOG(4, ("%s: access check failed\n", __FUNCTION__));
- status = HgfsConvertFromNameStatus(nameStatus);
- goto exit;
+ status = HgfsPlatformConvertFromNameStatus(nameStatus);
}
if (DOLOG(4)) {
- HgfsServerDumpDents(handle, session);
+ HgfsServerDumpDents(*handle, session);
}
- /*
- * Return handle to the search object as the reply to the search
- * open.
- */
- *replySearch = handle;
-
- if (!HgfsPackAndSendPacket(input->packet, packetOut, replySize,
- 0, header->id, session, 0)) {
- status = 0;
- goto exit;
- }
- return 0;
-
-exit:
- HSPU_PutReplyPacket(input->packet, session);
return status;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerSearchRead --
+ * HgfsPlatformHandleIncompleteName --
*
- * Handle a "Search Read" request.
+ * Returns platform error that matches HgfsNameStatus.
*
* Results:
- * Zero on success.
- * Non-zero on failure.
+ * Non-zero error code.
*
* Side effects:
* None
*/
HgfsInternalStatus
-HgfsServerSearchRead(HgfsInputParam *input) // IN: Input params
+HgfsPlatformHandleIncompleteName(HgfsNameStatus nameStatus, // IN: name status
+ HgfsFileAttrInfo *attr) // OUT: unused
{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
- uint32 requestedOffset;
- HgfsFileAttrInfo attr;
- HgfsInternalStatus status;
- HgfsNameStatus nameStatus;
- HgfsHandle hgfsSearchHandle;
- DirectoryEntry *dent;
- HgfsSearch search;
- HgfsShareOptions configOptions = 0;
- char *packetOut;
- size_t packetOutSize;
-
- ASSERT(packetIn);
- ASSERT(session);
-
- if (!HgfsUnpackSearchReadRequest(packetIn, packetSize, &attr,
- &hgfsSearchHandle, &requestedOffset)) {
- return EPROTO;
- }
-
- LOG(4, ("%s: read search #%u, offset %u\n", __FUNCTION__,
- hgfsSearchHandle, requestedOffset));
-
- if (!HgfsGetSearchCopy(hgfsSearchHandle, session, &search)) {
- LOG(4, ("%s: handle %u is invalid\n", __FUNCTION__, hgfsSearchHandle));
- return EBADF;
- }
-
- /* Get the config options. */
- if (search.utf8ShareNameLen != 0) {
- nameStatus = HgfsServerPolicy_GetShareOptions(search.utf8ShareName,
- search.utf8ShareNameLen,
- &configOptions);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__,
- search.utf8ShareName));
- free(search.utf8Dir);
- free(search.utf8ShareName);
- return ENOENT;
- }
- }
-
- while ((dent = HgfsGetSearchResult(hgfsSearchHandle, session,
- requestedOffset, FALSE)) != NULL) {
- unsigned int length;
- char *fullName;
- char *sharePath;
- size_t sharePathLen;
- size_t fullNameLen;
- size_t entryNameLen;
- char *entryName = NULL;
- Bool freeEntryName = FALSE;
-
- length = strlen(dent->d_name);
-
- /* Each type of search gets a dent's attributes in a different way. */
- switch (search.type) {
- case DIRECTORY_SEARCH_TYPE_DIR:
-
- /*
- * Construct the UTF8 version of the full path to the file, and call
- * HgfsGetattrFromName to get the attributes of the file.
- */
- fullNameLen = search.utf8DirLen + 1 + length;
- fullName = (char *)malloc(fullNameLen + 1);
- if (!fullName) {
- LOG(4, ("%s: could not allocate space for \"%s\\%s\"\n",
- __FUNCTION__, search.utf8Dir, dent->d_name));
- free(search.utf8Dir);
- free(search.utf8ShareName);
- free(dent);
- return ENOMEM;
- }
- memcpy(fullName, search.utf8Dir, search.utf8DirLen);
- fullName[search.utf8DirLen] = DIRSEPC;
- memcpy(&fullName[search.utf8DirLen + 1], dent->d_name, length + 1);
-
- LOG(4, ("%s: about to stat \"%s\"\n", __FUNCTION__, fullName));
-
- status = HgfsGetattrFromName(fullName, configOptions,
- search.utf8ShareName, &attr, NULL);
- if (status != 0) {
- HgfsOp savedOp = attr.requestType;
- LOG(4, ("%s: stat FAILED %s (%d)\n", __FUNCTION__,
- fullName, status));
- memset(&attr, 0, sizeof attr);
- attr.requestType = savedOp;
- attr.type = HGFS_FILE_TYPE_REGULAR;
- attr.mask = 0;
- }
-
- free(fullName);
-
-#if defined(__APPLE__)
- /*
- * HGFS clients receive names in unicode normal form C,
- * (precomposed) so Mac hosts must convert from normal form D
- * (decomposed).
- */
-
- if (!CodeSet_Utf8FormDToUtf8FormC((const char *)dent->d_name, length,
- &entryName, &entryNameLen)) {
- LOG(4, ("%s: Unable to normalize form C \"%s\"\n", __FUNCTION__,
- dent->d_name));
- /* Skip this entry and continue. */
- free(dent);
- continue;
- }
-
- freeEntryName = TRUE;
-#else /* defined(__APPLE__) */
- entryName = dent->d_name;
- entryNameLen = length;
-#endif /* defined(__APPLE__) */
- break;
- case DIRECTORY_SEARCH_TYPE_BASE:
-
- /*
- * For a search enumerating all shares, give the default attributes
- * for '.' and ".." (which aren't really shares anyway). Each real
- * share gets resolved into its full path, and gets its attributes
- * via HgfsGetattrFromName.
- */
- if (strcmp(dent->d_name, ".") == 0 ||
- strcmp(dent->d_name, "..") == 0) {
- LOG(4, ("%s: assigning %s default attributes\n",
- __FUNCTION__, dent->d_name));
- HgfsServerGetDefaultDirAttrs(&attr);
- } else {
- /* Check permission on the share and get the share path */
- nameStatus =
- HgfsServerPolicy_GetSharePath(dent->d_name, length,
- HGFS_OPEN_MODE_READ_ONLY,
- &sharePathLen,
- (char const **)&sharePath);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: No such share or access denied\n", __FUNCTION__));
- free(dent);
- free(search.utf8Dir);
- free(search.utf8ShareName);
- return HgfsConvertFromNameStatus(nameStatus);
- }
-
- /*
- * Server needs to produce list of shares that is consistent with
- * the list defined in UI. If a share can't be accessed because of
- * problems on the host, the server still enumerates it and
- * returns to the client.
- */
- status = HgfsGetattrFromName(sharePath, configOptions, dent->d_name,
- &attr, NULL);
- if (status != 0) {
- /*
- * The dent no longer exists. Log the event.
- */
-
- LOG(4, ("%s: stat FAILED\n", __FUNCTION__));
- }
- }
-
- /*
- * No conversion needed on OS X because dent->d_name is the shareName
- * that was converted to normal form C in hgfsServerPolicyHost.
- */
- entryName = dent->d_name;
- entryNameLen = length;
- break;
- case DIRECTORY_SEARCH_TYPE_OTHER:
-
- /*
- * The POSIX implementation of HgfsSearchOpen could not have created
- * this kind of search.
- */
- NOT_IMPLEMENTED();
- break;
- default:
- NOT_IMPLEMENTED();
- break;
- }
-
- free(search.utf8Dir);
- free(search.utf8ShareName);
- LOG(4, ("%s: dent name is \"%s\" len = %"FMTSZ"u\n", __FUNCTION__,
- entryName, entryNameLen));
-
- /*
- * We need to unescape the name before sending it back to the client
- */
- entryNameLen = HgfsEscape_Undo(entryName, entryNameLen + 1);
-
- /*
- * XXX: HgfsPackSearchReadReply will error out if the dent we
- * give it is too large for the packet. Prior to
- * HgfsPackSearchReadReply, we'd skip the dent and return the next
- * one with success. Now we return an error. This may be a non-issue
- * since what filesystems allow dent lengths as high as 6144 bytes?
- */
- status = 0;
- if (!HgfsPackSearchReadReply(input->packet, packetIn, status, entryName, entryNameLen,
- &attr, &packetOut, &packetOutSize, session)) {
- status = EPROTO;
- }
-
- if (freeEntryName) {
- free(entryName);
- }
- free(dent);
-
- if (status == 0 &&
- !HgfsPacketSend(input->packet,
- packetOut, packetOutSize, session, 0)) {
- HSPU_PutReplyPacket(input->packet, session);
- }
- return status;
- }
-
- /* No entry at this offset */
- free(search.utf8Dir);
- free(search.utf8ShareName);
- LOG(4, ("%s: no entry\n", __FUNCTION__));
- status = 0;
- if (!HgfsPackSearchReadReply(input->packet, packetIn, status, NULL, 0, &attr,
- &packetOut, &packetOutSize, session)) {
- status = EPROTO;
- }
- if (status == 0 &&
- !HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
- HSPU_PutReplyPacket(input->packet, session);
- }
- return status;
+ return HgfsPlatformConvertFromNameStatus(nameStatus);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerGetattr --
+ * HgfsPlatformDeleteFileByName --
+ *
+ * POSIX specific implementation of a delete file request which accepts
+ * utf8 file path as a parameter.
*
- * Handle a Getattr request.
+ * Simply calls Posix_Unlink.
*
* Results:
* Zero on success.
*/
HgfsInternalStatus
-HgfsServerGetattr(HgfsInputParam *input) // IN: Input params
+HgfsPlatformDeleteFileByName(char const *utf8Name) // IN: full file path in uf8 encoding
{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
- char *localName;
- HgfsAttrHint hints = 0;
- HgfsFileAttrInfo attr;
- HgfsInternalStatus status = 0;
- HgfsNameStatus nameStatus;
- char *cpName;
- size_t cpNameSize;
- char *targetName = NULL;
- uint32 targetNameLen;
- HgfsHandle file = HGFS_INVALID_HANDLE; /* file handle from driver */
- uint32 caseFlags = 0;
- HgfsShareOptions configOptions;
- char *packetOut;
- size_t packetOutSize;
- size_t localNameLen;
- HgfsShareInfo shareInfo;
-
- ASSERT(packetIn);
- ASSERT(session);
-
- if (!HgfsUnpackGetattrRequest(packetIn, packetSize, &attr, &hints, &cpName,
- &cpNameSize, &file, &caseFlags)) {
- status = EPROTO;
- goto exit;
- }
-
- /* Client wants us to reuse an existing handle. */
- if (hints & HGFS_ATTR_HINT_USE_FILE_DESC) {
- int fd;
- status = HgfsGetFd(file, session, FALSE, &fd);
-
- if (status != 0) {
- LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
- goto exit;
- }
- status = HgfsGetattrFromFd(fd, session, &attr);
- targetNameLen = 0;
-
- } else {
- /*
- * Depending on whether this file/dir is real or virtual, either
- * forge its attributes or look them up in the actual filesystem.
- */
- nameStatus = HgfsServerGetShareInfo(cpName,
- cpNameSize,
- caseFlags,
- &shareInfo,
- &localName,
- &localNameLen);
-
- switch (nameStatus) {
- case HGFS_NAME_STATUS_INCOMPLETE_BASE:
- /*
- * This is the base of our namespace; make up fake status for
- * this directory.
- */
-
- LOG(4, ("%s: getting attrs for base dir\n", __FUNCTION__));
- HgfsServerGetDefaultDirAttrs(&attr);
- break;
-
- case HGFS_NAME_STATUS_COMPLETE:
- /* This is a regular lookup; proceed as usual */
- ASSERT(localName);
-
- /* Get the config options. */
- nameStatus = HgfsServerPolicy_GetShareOptions(cpName, cpNameSize,
- &configOptions);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, cpName));
- free(localName);
- status = ENOENT;
- goto exit;
- }
-
- status = HgfsGetattrFromName(localName, configOptions, cpName, &attr,
- &targetName);
- free(localName);
- if (status == 0 &&
- !HgfsServerPolicy_CheckMode(HGFS_OPEN_MODE_READ_ONLY,
- shareInfo.writePermissions,
- shareInfo.readPermissions)) {
- status = EACCES;
- } else if (status != 0) {
- /*
- * If it is a dangling share server should not return ENOENT
- * to the client because it causes confusion: a name that is returned
- * by directory enumeration should not produce "name not found"
- * error.
- * Replace it with a more appropriate error code: no such device.
- */
- if (status == ENOENT && HgfsIsShareRoot(cpName, cpNameSize)) {
- status = ENXIO;
- }
- goto exit;
- }
- break;
-
- default:
- status = HgfsConvertFromNameStatus(nameStatus);
- goto exit;
- }
- targetNameLen = targetName ? strlen(targetName) : 0;
- }
- status = HgfsPackGetattrReply(input->packet, packetIn, status, &attr, targetName,
- targetNameLen, &packetOut, &packetOutSize, session) ? 0 : EPROTO;
- free(targetName);
+ HgfsInternalStatus status;
- if (status == 0 &&
- !HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
- HSPU_PutReplyPacket(input->packet, session);
+ LOG(4, ("%s: unlinking \"%s\"\n", __FUNCTION__, utf8Name));
+ status = Posix_Unlink(utf8Name);
+ if (status) {
+ status = errno;
+ LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(status)));
}
-
-exit:
return status;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerSetattr --
+ * HgfsPlatformDeleteFileByHandle --
+ *
+ * POSIX specific implementation of a delete file request which accepts
+ * HgfsHandle as a parameter.
*
- * Handle a Setattr request.
+ * File handle must have appropriate access mode to allow file deletion.
+ * Shared folder restrictions are enforced here as well.
*
* Results:
* Zero on success.
*/
HgfsInternalStatus
-HgfsServerSetattr(HgfsInputParam *input) // IN: Input params
+HgfsPlatformDeleteFileByHandle(HgfsHandle file, // IN: File being deleted
+ HgfsSessionInfo *session) // IN: session info
{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
HgfsInternalStatus status;
- HgfsFileAttrInfo attr;
- char *cpName;
- size_t cpNameSize = 0;
- HgfsAttrHint hints = 0;
- HgfsHandle file = HGFS_INVALID_HANDLE;
- uint32 caseFlags = 0;
- char *packetOut;
- size_t packetOutSize;
-
- ASSERT(packetIn);
- ASSERT(session);
-
- LOG(4, ("NEW LIB! HgfsServerSetAttr Called!\n"));
-
- if (!HgfsUnpackSetattrRequest(packetIn, packetSize, &attr, &hints,
- &cpName, &cpNameSize, &file, &caseFlags)) {
- status = EPROTO;
- goto exit;
- }
+ Bool readPermissions;
+ Bool writePermissions;
+ char *localName;
+ size_t localNameSize;
- if (file != HGFS_INVALID_HANDLE) {
- status = HgfsSetattrFromFd(file, session, &attr, hints);
+ if (!HgfsHandle2FileNameMode(file, session, &writePermissions,
+ &readPermissions, &localName, &localNameSize)) {
+ if (writePermissions && readPermissions) {
+ status = HgfsPlatformDeleteFileByName(localName);
+ } else {
+ status = EPERM;
+ }
+ free(localName);
} else {
- status = HgfsSetattrFromName(cpName, cpNameSize, &attr, hints,
- caseFlags, session);
- }
- if (!HgfsPackSetattrReply(input->packet, packetIn, status, attr.requestType,
- &packetOut, &packetOutSize, session)) {
- status = EPROTO;
- goto exit;
- }
- if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
- HSPU_PutReplyPacket(input->packet, session);
- /* We can't send the packet, ignore the error if any. */
+ LOG(4, ("%s: could not map cached file handle %u\n", __FUNCTION__, file));
+ status = EBADF;
}
- status = 0;
-
-exit:
return status;
}
+
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerCreateDir --
+ * HgfsPlatformDeleteDirByName --
*
- * Handle a CreateDir request.
+ * POSIX specific implementation of a delete directory request which accepts
+ * utf8 file path as a parameter.
*
- * Simply converts to the local filename, calls mkdir on the
- * file, and returns an appropriate response to the driver.
+ * Simply calls Posix_Rmdir.
*
* Results:
* Zero on success.
*/
HgfsInternalStatus
-HgfsServerCreateDir(HgfsInputParam *input) // IN: Input params
+HgfsPlatformDeleteDirByName(char const *utf8Name) // IN: full file path in uf8 encoding
{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
- HgfsNameStatus nameStatus;
- HgfsCreateDirInfo info;
- char *localName;
- int error;
- mode_t permissions;
- char *packetOut;
- size_t packetOutSize;
- size_t localNameLen;
- HgfsShareInfo shareInfo;
-
- ASSERT(packetIn);
- ASSERT(session);
-
- if (!HgfsUnpackCreateDirRequest(packetIn, packetSize, &info)) {
- return EPROTO;
- }
-
- nameStatus = HgfsServerGetShareInfo(info.cpName,
- info.cpNameSize,
- info.caseFlags,
- &shareInfo,
- &localName,
- &localNameLen);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: access check failed\n", __FUNCTION__));
-
- return HgfsConvertFromNameStatus(nameStatus);
- }
-
- ASSERT(localName);
-
- /*
- * For read-only shares we must never attempt to create a directory.
- * However the error code must be different depending on the existence
- * of the file or directory with the same name.
- */
- if (!shareInfo.writePermissions) {
- int error = HgfsAccess(localName, info.cpName, info.cpNameSize);
- if (error != 0) {
- if (error == ENOENT) {
- error = EACCES;
- }
- } else {
- error = EEXIST;
- }
- LOG(4, ("HgfsServerCreateDir: failed access check, error %d\n", error));
- free(localName);
- return error;
- }
-
- /*
- * Create mode_t for use in mkdir(). If owner permissions are missing, use
- * read/write/execute for the owner permissions. If group or other
- * permissions are missing, use the owner permissions.
- *
- * This sort of makes sense. If the Windows driver wants to make a dir
- * read-only, it probably intended for the dir to be 666. Since creating
- * a directory requires a valid mode, it's highly unlikely that we'll ever
- * be creating a directory without owner permissions.
- */
- permissions = ~ALLPERMS;
- permissions |= info.mask & HGFS_CREATE_DIR_VALID_SPECIAL_PERMS ?
- info.specialPerms << 9 : 0;
- permissions |= info.mask & HGFS_CREATE_DIR_VALID_OWNER_PERMS ?
- info.ownerPerms << 6 : S_IRWXU;
- permissions |= info.mask & HGFS_CREATE_DIR_VALID_GROUP_PERMS ?
- info.groupPerms << 3 : (permissions & S_IRWXU) >> 3;
- permissions |= info.mask & HGFS_CREATE_DIR_VALID_OTHER_PERMS ?
- info.otherPerms : (permissions & S_IRWXU) >> 6;
-
- LOG(4, ("%s: making dir \"%s\", mode %"FMTMODE"\n", __FUNCTION__,
- localName, permissions));
-
- error = Posix_Mkdir(localName, permissions);
- if ((info.mask & HGFS_CREATE_DIR_VALID_FILE_ATTR) &&
- (info.fileAttr & HGFS_ATTR_HIDDEN)) {
- /*
- * Set hidden attribute when requested.
- * Do not fail directory creation if setting hidden attribute fails.
- */
- HgfsSetHiddenXAttr(localName, TRUE);
- }
+ HgfsInternalStatus status;
- free(localName);
- if (error) {
- error = errno;
- LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(error)));
- return error;
- }
- if (!HgfsPackCreateDirReply(input->packet, packetIn, 0, info.requestType,
- &packetOut, &packetOutSize, session)) {
- return EPROTO;
- }
- if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
- HSPU_PutReplyPacket(input->packet, session);
+ LOG(4, ("%s: removing \"%s\"\n", __FUNCTION__, utf8Name));
+ status = Posix_Rmdir(utf8Name);
+ if (status) {
+ status = errno;
+ LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(status)));
}
- return 0;
+ return status;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerDeleteFile --
+ * HgfsPlatformDeleteDirByHandle --
*
- * Handle a Delete File request.
+ * POSIX specific implementation of a Delete directory request which accepts
+ * HgfsHandle as a parameter.
*
- * Simply converts to the local filename, calls unlink on the
- * file, and returns an appropriate response to the driver.
+ * File handle must have appropriate access mode to allow file deletion.
+ * Shared folder restrictions are enforced here as well.
*
* Results:
* Zero on success.
*/
HgfsInternalStatus
-HgfsServerDeleteFile(HgfsInputParam *input) // IN: Input params
+HgfsPlatformDeleteDirByHandle(HgfsHandle file, // IN: File being deleted
+ HgfsSessionInfo *session) // IN: session info
{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
- HgfsNameStatus nameStatus;
+ HgfsInternalStatus status;
+ Bool readPermissions;
+ Bool writePermissions;
char *localName;
- int error;
- HgfsHandle file = HGFS_INVALID_HANDLE;
- HgfsDeleteHint hints = 0;
- char *cpName;
- size_t cpNameSize;
- uint32 caseFlags;
- char *packetOut;
- size_t packetOutSize;
- size_t localNameLen;
- HgfsShareInfo shareInfo;
- HgfsOp op;
-
- ASSERT(packetIn);
- ASSERT(session);
+ size_t localNameSize;
- if (!HgfsUnpackDeleteRequest(packetIn, packetSize, &op, &cpName, &cpNameSize,
- &hints, &file, &caseFlags)) {
- return EPROTO;
- }
-
- if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) {
- if (!HgfsHandle2FileNameMode(file, session, &shareInfo.writePermissions,
- &shareInfo.readPermissions, &cpName, &cpNameSize)) {
- LOG(4, ("%s: could not map cached file handle %u\n", __FUNCTION__,
- file));
- return EBADF;
- }
- localName = cpName;
-
- } else {
- nameStatus = HgfsServerGetShareInfo(cpName,
- cpNameSize,
- caseFlags,
- &shareInfo,
- &localName,
- &localNameLen);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: access check failed\n", __FUNCTION__));
-
- return HgfsConvertFromNameStatus(nameStatus);
- }
- }
-
- ASSERT(localName);
-
- /*
- * Deleting a file needs both read and write permssions.
- * However the error code must be different depending on the existence
- * of the file with the same name.
- */
- if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
- int error = HgfsAccess(localName, cpName, cpNameSize);
- if (error == 0) {
- error = EACCES;
+ if (!HgfsHandle2FileNameMode(file, session, &writePermissions,
+ &readPermissions, &localName, &localNameSize)) {
+ if (writePermissions && readPermissions) {
+ status = HgfsPlatformDeleteDirByName(localName);
+ } else {
+ status = EPERM;
}
- LOG(4, ("HgfsServerDeleteFile: failed access check, error %d\n", error));
free(localName);
- return error;
- }
-
- LOG(4, ("%s: unlinking \"%s\"\n", __FUNCTION__, localName));
- error = Posix_Unlink(localName);
- free(localName);
- if (error) {
- error = errno;
- LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(error)));
-
- return error;
- }
- if (!HgfsPackDeleteReply(input->packet, packetIn, 0, op, &packetOut,
- &packetOutSize, session)) {
- return EPROTO;
- }
- if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
- HSPU_PutReplyPacket(input->packet, session);
+ } else {
+ LOG(4, ("%s: could not map cached file handle %u\n", __FUNCTION__, file));
+ status = EBADF;
}
- return 0;
+ return status;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerDeleteDir --
- *
- * Handle a Delete Dir request.
+ * HgfsPlatformFileExists --
*
- * Simply converts to the local filename, calls rmdir on the
- * file, and returns an appropriate response to the driver.
+ * Platform specific function that that verifies if a file or directory exists.
*
* Results:
- * Zero on success.
- * Non-zero on failure.
+ * 0 if user has permissions to traverse the parent directory and
+ * the file exists, POSIX error code otherwise.
*
* Side effects:
* None
*/
HgfsInternalStatus
-HgfsServerDeleteDir(HgfsInputParam *input) // IN: Input params
+HgfsPlatformFileExists(char *localTargetName) // IN: Full file path utf8 encoding
{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
- HgfsNameStatus nameStatus;
- char *localName = NULL;
- int error;
- HgfsHandle file = HGFS_INVALID_HANDLE;
- HgfsDeleteHint hints = 0;
- char *cpName;
- size_t cpNameSize;
- uint32 caseFlags;
- char *packetOut;
- size_t packetOutSize;
- size_t localNameLen;
- HgfsShareInfo shareInfo;
- HgfsOp op;
-
- ASSERT(packetIn);
- ASSERT(session);
-
- if (!HgfsUnpackDeleteRequest(packetIn, packetSize, &op, &cpName, &cpNameSize,
- &hints, &file, &caseFlags)) {
- return EPROTO;
- }
-
- if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) {
- if (!HgfsHandle2FileNameMode(file, session, &shareInfo.writePermissions,
- &shareInfo.readPermissions, &cpName, &cpNameSize)) {
- LOG(4, ("%s: could not map cached file handle %u\n", __FUNCTION__,
- file));
- return EBADF;
- }
- localName = cpName;
-
- } else {
- nameStatus = HgfsServerGetShareInfo(cpName,
- cpNameSize,
- caseFlags,
- &shareInfo,
- &localName,
- &localNameLen);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: access check failed\n", __FUNCTION__));
-
- return HgfsConvertFromNameStatus(nameStatus);
- }
- }
-
- /* Guest OS is not allowed to delete shared folder. */
- if (HgfsServerIsSharedFolderOnly(cpName, cpNameSize)){
- LOG(4, ("%s: Cannot delete shared folder\n", __FUNCTION__));
- free(localName);
- return EPERM;
- }
-
- /*
- * Deleting a directory needs both read and write permssions.
- * However the error code must be different depending on the existence
- * of the file with the same name.
- */
- if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
- int error = HgfsAccess(localName, cpName, cpNameSize);
- if (error == 0) {
- error = EACCES;
- }
- LOG(4, ("%s: : failed access check, error %d\n", __FUNCTION__, error));
- free(localName);
- return error;
- }
-
- ASSERT(localName);
-
- LOG(4, ("%s: removing \"%s\"\n", __FUNCTION__, localName));
- error = Posix_Rmdir(localName);
- free(localName);
- if (error) {
- error = errno;
- LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(error)));
-
- return error;
- }
-
- if (!HgfsPackDeleteReply(input->packet, packetIn, 0, op, &packetOut,
- &packetOutSize, session)) {
- return EPROTO;
- }
- if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
- HSPU_PutReplyPacket(input->packet, session);
- }
- return 0;
+ return Posix_Access(localTargetName, F_OK);
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerRename --
+ * HgfsPlatformRename --
*
- * Handle a Rename request.
- *
- * Simply converts the new and old names to local filenames, calls
- * rename(2), and returns an appropriate response to the driver.
+ * POSIX version of the function that renames a file or directory.
*
* Results:
- * Zero on success.
- * Non-zero on failure.
- *
- * Side effects:
- * None
+ * 0 on success, POSIX error code otherwise.
*
- *-----------------------------------------------------------------------------
- */
-
-HgfsInternalStatus
-HgfsServerRename(HgfsInputParam *input) // IN: Input params
-{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
- HgfsNameStatus nameStatus;
- char *localOldName = NULL;
- size_t localOldNameLen;
- char *localNewName = NULL;
- size_t localNewNameLen;
- char *cpOldName;
- size_t cpOldNameLen;
- char *cpNewName;
- size_t cpNewNameLen;
- HgfsHandle srcFile = HGFS_INVALID_HANDLE;
- HgfsHandle targetFile = HGFS_INVALID_HANDLE;
- HgfsRenameHint hints = 0;
- int error;
- HgfsInternalStatus status;
- Bool sharedFolderOpen = FALSE;
- uint32 oldCaseFlags = 0;
- uint32 newCaseFlags = 0;
- char *packetOut;
- size_t packetOutSize;
- HgfsShareInfo shareInfo;
- HgfsOp op;
-
- ASSERT(packetIn);
- ASSERT(session);
-
- if (!HgfsUnpackRenameRequest(packetIn, packetSize, &op, &cpOldName, &cpOldNameLen,
- &cpNewName, &cpNewNameLen, &hints, &srcFile,
- &targetFile, &oldCaseFlags, &newCaseFlags)) {
- return EPROTO;
- }
-
- if (hints & HGFS_RENAME_HINT_USE_SRCFILE_DESC) {
- size_t localOldNameLen;
-
- if (!HgfsHandle2FileNameMode(srcFile, session, &shareInfo.writePermissions,
- &shareInfo.readPermissions, &localOldName,
- &localOldNameLen)) {
- LOG(4, ("%s: could not map cached source file handle %u\n",
- __FUNCTION__, srcFile));
- return EBADF;
- }
-
- /* Guest OS is not allowed to rename shared folder. */
- if (HgfsHandleIsSharedFolderOpen(srcFile, session, &sharedFolderOpen) &&
- sharedFolderOpen) {
- LOG(4, ("%s: Cannot rename shared folder\n", __FUNCTION__));
- status = EPERM;
- goto exit;
- }
-
- } else {
-
- nameStatus = HgfsServerGetShareInfo(cpOldName,
- cpOldNameLen,
- oldCaseFlags,
- &shareInfo,
- &localOldName,
- &localOldNameLen);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- return HgfsConvertFromNameStatus(nameStatus);
- }
-
- ASSERT(localOldName);
-
- /* Guest OS is not allowed to rename shared folder. */
- if (HgfsServerIsSharedFolderOnly(cpOldName, cpOldNameLen)) {
- LOG(4, ("%s: Cannot rename shared folder\n", __FUNCTION__));
- status = EPERM;
- goto exit;
- }
-
- /*
- * Renaming a file requires both read and write permissions for the original file.
- * However the error code must be different depending on the existence
- * of the file with the same name.
- */
- if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
- status = HgfsAccess(localOldName, cpOldName, cpOldNameLen);
- if (status == 0) {
- status = EACCES;
- }
- LOG(4, ("HgfsServerRename: failed access check, error %d\n", status));
- goto exit;
- }
- }
-
- if (hints & HGFS_RENAME_HINT_USE_TARGETFILE_DESC) {
- size_t localNewNameLen;
-
- if (!HgfsHandle2FileNameMode(targetFile, session, &shareInfo.writePermissions,
- &shareInfo.readPermissions, &localNewName,
- &localNewNameLen)) {
- LOG(4, ("%s: could not map cached target file handle %u\n",
- __FUNCTION__, targetFile));
- status = EBADF;
- goto exit;
- }
-
- /* Guest OS is not allowed to rename shared folder. */
- if (HgfsHandleIsSharedFolderOpen(targetFile, session, &sharedFolderOpen) &&
- sharedFolderOpen) {
- LOG(4, ("%s: Cannot rename shared folder\n", __FUNCTION__));
- status = EPERM;
- goto exit;
- }
-
- } else {
-
- nameStatus = HgfsServerGetShareInfo(cpNewName,
- cpNewNameLen,
- newCaseFlags,
- &shareInfo,
- &localNewName,
- &localNewNameLen);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: new name access check failed\n", __FUNCTION__));
- status = HgfsConvertFromNameStatus(nameStatus);
- goto exit;
- }
- }
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
- ASSERT(localNewName);
+HgfsInternalStatus
+HgfsPlatformRename(char *localSrcName, // IN: local path to source file
+ fileDesc srcFile, // IN: source file handle
+ char *localTargetName, // IN: local path to target file
+ fileDesc targetFile, // IN: target file handle
+ HgfsRenameHint hints) // IN: rename hints
+{
+ HgfsInternalStatus status = 0;
+ int error;
if (hints & HGFS_RENAME_HINT_NO_REPLACE_EXISTING) {
- HgfsFileAttrInfo attr;
- HgfsShareOptions configOptions;
-
- /* Get the config options. */
- nameStatus = HgfsServerPolicy_GetShareOptions(cpNewName, cpNewNameLen,
- &configOptions);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, cpNewName));
- status = ENOENT;
- goto exit;
- }
-
- /*
- * We were asked to avoid replacing an existing file,
- * so fail if the target exists.
- */
-
- status = HgfsGetattrFromName(localNewName, configOptions, cpNewName,
- &attr, NULL);
- if (status == 0) {
- /* The target exists, and so must fail the rename. */
- LOG(4, ("%s: error: target %s exists\n", __FUNCTION__, localNewName));
+ status = HgfsPlatformFileExists(localTargetName);
+ if (0 == status) {
status = EEXIST;
- goto exit;
}
}
- /*
- * Renaming a file requires both read and write permssions for the target file.
- * However the error code must be different depending on the existence
- * of the file with the same name.
- */
- if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
- status = HgfsAccess(localNewName, cpNewName, cpNewNameLen);
- if (status == 0 || status == ENOENT) {
- status = EACCES;
+ if (0 == status) {
+ LOG(4, ("%s: renaming \"%s\" to \"%s\"\n", __FUNCTION__,
+ localSrcName, localTargetName));
+ error = Posix_Rename(localSrcName, localTargetName);
+ if (error) {
+ status = errno;
+ LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(status)));
}
- LOG(4, ("HgfsServerRename: failed access check, error %d\n", status));
- goto exit;
- }
-
- LOG(4, ("%s: renaming \"%s\" to \"%s\"\n", __FUNCTION__,
- localOldName, localNewName));
- error = Posix_Rename(localOldName, localNewName);
- if (error) {
- error = errno;
- LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(error)));
- status = error;
- goto exit;
- }
-
- /*
- * Update all file nodes referring to this filename to the new name.
- *
- * XXX: Note that this operation can fail (out of memory), but we'd like
- * the client to see success anyway, because the rename succeeded.
- */
- status = 0;
- HgfsUpdateNodeNames(localOldName, localNewName, session);
- if (!HgfsPackRenameReply(input->packet, packetIn, status, op, &packetOut,
- &packetOutSize, session)) {
- status = EPROTO;
- goto exit;
- }
- if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
- HSPU_PutReplyPacket(input->packet, session);
}
-
- exit:
- free(localOldName);
- free(localNewName);
return status;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerQueryVolume --
+ * HgfsPlatformCreateDir --
*
- * Handle a Query Volume request.
+ * POSIX specific code that implements create directory request.
*
- * Right now we only handle the volume space request. Call Wiper library
- * to get the volume information.
- * It is possible that shared folders can belong to different volumes on
- * the server. If this is the case, default to return the space information
- * of the volume that has the least amount of the available space, but it's
- * configurable with a config option (tools.hgfs.volumeInfoType). 2 possible
- * options, min and max.
+ * It invokes POSIX to create the directory and then assigns
+ * file attributes to the new directory if attributes are specified
+ * by the guest.
*
* Results:
* Zero on success.
*/
HgfsInternalStatus
-HgfsServerQueryVolume(HgfsInputParam *input) // IN: Input params
+HgfsPlatformCreateDir(HgfsCreateDirInfo *info, // IN: direcotry properties
+ char *utf8Name) // IN: full path for the new directory
{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
- HgfsRequest *header;
- uint32 extra;
- char *utf8Name = NULL;
- size_t utf8NameLen;
- HgfsHandle handle;
- int offset = 0;
- uint64 outFreeBytes = 0;
- uint64 outTotalBytes = 0;
- VolumeInfoType infoType;
- DirectoryEntry *dent;
+ mode_t permissions;
HgfsInternalStatus status;
- Bool firstShare = TRUE;
- Bool success;
- HgfsNameStatus nameStatus;
- size_t failed = 0;
- size_t shares = 0;
- HgfsInternalStatus firstErr = 0;
- char *fileName;
- uint32 fileNameLength;
- uint32 caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
- uint64 *freeBytes;
- uint64 *totalBytes;
- char *packetOut;
- size_t packetOutSize;
- size_t replyPacketSize;
- HgfsShareInfo shareInfo;
-
- ASSERT(packetIn);
- ASSERT(session);
-
- header = (HgfsRequest *)packetIn;
-
- if (header->op == HGFS_OP_QUERY_VOLUME_INFO_V3) {
- HgfsRequestQueryVolumeV3 *requestV3 =
- (HgfsRequestQueryVolumeV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
- HgfsReplyQueryVolumeV3 *replyV3;
-
- packetOutSize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
- replyPacketSize = packetOutSize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
-
- replyV3 = (HgfsReplyQueryVolumeV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
-
- /*
- * We don't yet support file handle for this operation.
- * Clients should retry using the file name.
- */
- if (requestV3->fileName.flags & HGFS_FILE_NAME_USE_FILE_DESC) {
- LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
- status = EPARAMETERNOTSUPPORTED;
- goto exit;
- }
-
- freeBytes = &replyV3->freeBytes;
- totalBytes = &replyV3->totalBytes;
- replyV3->reserved = 0;
-
- /* Enforced by the dispatch function. */
- ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(requestV3));
- extra = packetSize - HGFS_REQ_PAYLOAD_SIZE_V3(requestV3);
-
- caseFlags = requestV3->fileName.caseType;
- fileName = requestV3->fileName.name;
- fileNameLength = requestV3->fileName.length;
- LOG(4, ("%s: HGFS_OP_QUERY_VOLUME_INFO_V3\n", __FUNCTION__));
- } else {
- HgfsRequestQueryVolume *request = (HgfsRequestQueryVolume *)packetIn;
- HgfsReplyQueryVolume *reply;
-
- packetOutSize = sizeof *reply;
- replyPacketSize = packetOutSize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
-
- reply = (HgfsReplyQueryVolume *)packetOut;
-
- freeBytes = &reply->freeBytes;
- totalBytes = &reply->totalBytes;
-
- /* Enforced by the dispatch function. */
- ASSERT(packetSize >= sizeof *request);
- extra = packetSize - sizeof *request;
- fileName = request->fileName.name;
- fileNameLength = request->fileName.length;
- }
/*
- * request->fileName.length is user-provided, so this test must be carefully
- * written to prevent wraparounds.
+ * Create mode_t for use in mkdir(). If owner permissions are missing, use
+ * read/write/execute for the owner permissions. If group or other
+ * permissions are missing, use the owner permissions.
+ *
+ * This sort of makes sense. If the Windows driver wants to make a dir
+ * read-only, it probably intended for the dir to be 666. Since creating
+ * a directory requires a valid mode, it's highly unlikely that we'll ever
+ * be creating a directory without owner permissions.
*/
- if (fileNameLength > extra) {
- /* The input packet is smaller than the request. */
- status = EPROTO;
- goto exit;
- }
-
- /* It is now safe to read the file name field. */
- nameStatus = HgfsServerGetShareInfo(fileName,
- fileNameLength,
- caseFlags,
- &shareInfo,
- &utf8Name,
- &utf8NameLen);
- switch (nameStatus) {
- case HGFS_NAME_STATUS_INCOMPLETE_BASE:
- /*
- * This is the base of our namespace. Clients can request a
- * QueryVolumeInfo on it, on individual shares, or on just about
- * any pathname.
- */
-
- LOG(4,("%s: opened search on base\n", __FUNCTION__));
- status = HgfsServerSearchVirtualDir(HgfsServerPolicy_GetShares,
- HgfsServerPolicy_GetSharesInit,
- HgfsServerPolicy_GetSharesCleanup,
- DIRECTORY_SEARCH_TYPE_BASE,
- session,
- &handle);
- if (status != 0) {
- goto exit;
- }
+ permissions = ~ALLPERMS;
+ permissions |= info->mask & HGFS_CREATE_DIR_VALID_SPECIAL_PERMS ?
+ info->specialPerms << 9 : 0;
+ permissions |= info->mask & HGFS_CREATE_DIR_VALID_OWNER_PERMS ?
+ info->ownerPerms << 6 : S_IRWXU;
+ permissions |= info->mask & HGFS_CREATE_DIR_VALID_GROUP_PERMS ?
+ info->groupPerms << 3 : (permissions & S_IRWXU) >> 3;
+ permissions |= info->mask & HGFS_CREATE_DIR_VALID_OTHER_PERMS ?
+ info->otherPerms : (permissions & S_IRWXU) >> 6;
- /*
- * If we're outside the Tools, find out if we're to compute the minimum
- * values across all shares, or the maximum values.
- */
- infoType = VOLUME_INFO_TYPE_MIN;
-#ifndef VMX86_TOOLS
- {
- char *volumeInfoType = Config_GetString("min",
- "tools.hgfs.volumeInfoType");
- if (!Str_Strcasecmp(volumeInfoType, "max")) {
- infoType = VOLUME_INFO_TYPE_MAX;
- }
- free(volumeInfoType);
- }
-#endif
+ LOG(4, ("%s: making dir \"%s\", mode %"FMTMODE"\n", __FUNCTION__,
+ utf8Name, permissions));
+ status = Posix_Mkdir(utf8Name, permissions);
+ if ((info->mask & HGFS_CREATE_DIR_VALID_FILE_ATTR) &&
+ (info->fileAttr & HGFS_ATTR_HIDDEN) && 0 == status) {
/*
- * Now go through all shares and get share paths on the server.
- * Then retrieve space info for each share's volume.
+ * Set hidden attribute when requested.
+ * Do not fail directory creation if setting hidden attribute fails.
*/
- offset = 0;
- while ((dent = HgfsGetSearchResult(handle, session, offset,
- TRUE)) != NULL) {
- char const *sharePath;
- size_t sharePathLen;
- uint64 freeBytes = 0;
- uint64 totalBytes = 0;
- unsigned int length;
-
- length = strlen(dent->d_name);
-
- /*
- * Now that the server is passing '.' and ".." around as dents, we
- * need to make sure to handle them properly. In particular, they
- * should be ignored within QueryVolume, as they're not real shares.
- */
- if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {
- LOG(4, ("%s: Skipping fake share %s\n", __FUNCTION__,
- dent->d_name));
- free(dent);
- continue;
- }
-
- /*
- * The above check ignores '.' and '..' so we do not include them in
- * the share count here.
- */
- shares++;
-
- /*
- * Check permission on the share and get the share path. It is not
- * fatal if these do not succeed. Instead we ignore the failures
- * (apart from logging them) until we have processed all shares. Only
- * then do we check if there were any failures; if all shares failed
- * to process then we bail out with an error code.
- */
-
- nameStatus = HgfsServerPolicy_GetSharePath(dent->d_name, length,
- HGFS_OPEN_MODE_READ_ONLY,
- &sharePathLen,
- &sharePath);
- free(dent);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: No such share or access denied\n", __FUNCTION__));
- if (0 == firstErr) {
- firstErr = HgfsConvertFromNameStatus(nameStatus);
- }
- failed++;
- continue;
- }
-
- if (!HgfsServerStatFs(sharePath, sharePathLen,
- &freeBytes, &totalBytes)) {
- LOG(4, ("%s: error getting volume information\n",
- __FUNCTION__));
- if (0 == firstErr) {
- firstErr = EIO;
- }
- failed++;
- continue;
- }
-
- /*
- * Pick the drive with amount of space available and return that
- * according to different volume info type.
- */
- switch (infoType) {
- case VOLUME_INFO_TYPE_MIN:
- if ((outFreeBytes > freeBytes) || firstShare) {
- firstShare = FALSE;
- outFreeBytes = freeBytes;
- outTotalBytes = totalBytes;
- }
- break;
- case VOLUME_INFO_TYPE_MAX:
- if ((outFreeBytes < freeBytes)) {
- outFreeBytes = freeBytes;
- outTotalBytes = totalBytes;
- }
- break;
- default:
- NOT_IMPLEMENTED();
- }
- }
- if (!HgfsRemoveSearch(handle, session)) {
- LOG(4, ("%s: could not close search on base\n", __FUNCTION__));
- }
- break;
- case HGFS_NAME_STATUS_COMPLETE:
- ASSERT(utf8Name);
- LOG(4,("%s: querying path %s\n", __FUNCTION__, utf8Name));
- success = HgfsServerStatFs(utf8Name, utf8NameLen,
- &outFreeBytes, &outTotalBytes);
- free(utf8Name);
- if (!success) {
- LOG(4, ("%s: error getting volume information\n", __FUNCTION__));
- status = EIO;
- goto exit;
- }
- break;
- default:
- LOG(4,("%s: file access check failed\n", __FUNCTION__));
- status = HgfsConvertFromNameStatus(nameStatus);
- goto exit;
+ HgfsSetHiddenXAttr(utf8Name, TRUE);
}
- *freeBytes = outFreeBytes;
- *totalBytes = outTotalBytes;
- status = 0;
-
- if (!HgfsPackAndSendPacket(input->packet, packetOut, packetOutSize,
- status, header->id, session, 0)) {
- goto exit;
+ if (status) {
+ status = errno;
+ LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(status)));
}
return status;
-
-exit:
- HSPU_PutReplyPacket(input->packet, session);
- return status;
}
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerSymlinkCreate --
+ * HgfsPlatformSymlinkCreate --
*
- * Handle a SymlinkCreate request.
+ * Platform specific function that actually creates the symbolic link.
*
* Results:
* Zero on success.
*/
HgfsInternalStatus
-HgfsServerSymlinkCreate(HgfsInputParam *input) // IN: Input params
-{
- const char *packetIn = input->metaPacket;
- size_t packetSize = input->metaPacketSize;
- HgfsSessionInfo *session = input->session;
- HgfsRequest *header;
- uint32 extra;
- char *localSymlinkName = NULL;
- char localTargetName[HGFS_PACKET_MAX];
- int error;
- HgfsNameStatus nameStatus;
- uint32 caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
- char *symlinkName;
- uint32 symlinkNameLength;
- char *targetName;
- uint32 targetNameLength;
- HgfsShareOptions configOptions;
- char *packetOut = NULL;
- size_t packetOutSize;
- size_t replyPacketSize;
+HgfsPlatformSymlinkCreate(char *localSymlinkName, // IN: symbolic link file name
+ char *localTargetName) // IN: symlink target name
+{
HgfsInternalStatus status = 0;
- size_t localSymlinkNameLen;
- HgfsShareInfo shareInfo;
-
- ASSERT(packetIn);
- ASSERT(session);
- header = (HgfsRequest *)packetIn;
-
- if (header->op == HGFS_OP_CREATE_SYMLINK_V3) {
- HgfsRequestSymlinkCreateV3 *requestV3;
- HgfsReplySymlinkCreateV3 *replyV3;
- HgfsFileNameV3 *targetNameP;
- requestV3 = (HgfsRequestSymlinkCreateV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
- LOG(4, ("%s: HGFS_OP_CREATE_SYMLINK_V3\n", __FUNCTION__));
-
- /* Enforced by the dispatch function. */
- ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(requestV3));
- extra = packetSize - HGFS_REQ_PAYLOAD_SIZE_V3(requestV3);
-
- caseFlags = requestV3->symlinkName.caseType;
- symlinkName = requestV3->symlinkName.name;
- symlinkNameLength = requestV3->symlinkName.length;
-
- /*
- * targetName starts after symlinkName + the variable length array
- * in symlinkName.
- */
- targetNameP = (HgfsFileNameV3 *)(symlinkName + 1 + symlinkNameLength);
- targetName = targetNameP->name;
- targetNameLength = targetNameP->length;
-
- /*
- * We don't yet support file handle for this operation.
- * Clients should retry using the file name.
- */
- if (requestV3->symlinkName.flags & HGFS_FILE_NAME_USE_FILE_DESC ||
- targetNameP->flags & HGFS_FILE_NAME_USE_FILE_DESC) {
- LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
- return EPARAMETERNOTSUPPORTED;
- }
-
- packetOutSize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
- replyPacketSize = packetOutSize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
-
- replyV3 = (HgfsReplySymlinkCreateV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
- replyV3->reserved = 0;
-
- } else {
- HgfsRequestSymlinkCreate *request;
- HgfsFileName *targetNameP;
- request = (HgfsRequestSymlinkCreate *)packetIn;
-
- /* Enforced by the dispatch function. */
- ASSERT(packetSize >= sizeof *request);
- extra = packetSize - sizeof *request;
-
- symlinkName = request->symlinkName.name;
- symlinkNameLength = request->symlinkName.length;
-
- /*
- * targetName starts after symlinkName + the variable length array
- * in symlinkName.
- */
-
- targetNameP = (HgfsFileName *)(symlinkName + 1 + symlinkNameLength);
- targetName = targetNameP->name;
- targetNameLength = targetNameP->length;
- packetOutSize = sizeof(struct HgfsReplySymlinkCreate);
- replyPacketSize = packetOutSize;
- packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
- HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
- }
-
- /*
- * request->symlinkName.length is user-provided, so this test must
- * be carefully written to prevent wraparounds.
- */
-
- if (symlinkNameLength > extra) {
- /* The input packet is smaller than the request */
- status = EPROTO;
- goto exit;
- }
-
- /*
- * It is now safe to read the symlink file name and the
- * "targetName" field
- */
-
- nameStatus = HgfsServerGetShareInfo(symlinkName,
- symlinkNameLength,
- caseFlags,
- &shareInfo,
- &localSymlinkName,
- &localSymlinkNameLen);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: symlink name access check failed\n",
- __FUNCTION__));
- status = HgfsConvertFromNameStatus(nameStatus);
- goto exit;
- }
-
- if (!shareInfo.writePermissions ) {
- status = HgfsAccess(localSymlinkName, symlinkName, symlinkNameLength);
- if (status != 0) {
- if (status == ENOENT) {
- status = EACCES;
- }
- } else {
- status = EEXIST;
- }
- LOG(4, ("HgfsServerCreateDir: failed access check, error %d\n", status));
- goto exit;
- }
-
- ASSERT(localSymlinkName);
- extra -= symlinkNameLength;
-
- /*
- * targetNameLength is user-provided, so this test must be carefully
- * written to prevent wraparounds.
- */
- if (targetNameLength > extra) {
- /* The input packet is smaller than the request */
- status = EPROTO;
- goto exit;
- }
-
- /* It is now safe to read the target file name */
-
- /* Get the config options. */
- nameStatus = HgfsServerPolicy_GetShareOptions(symlinkName, symlinkNameLength,
- &configOptions);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, symlinkName));
- status = HgfsConvertFromNameStatus(nameStatus);
- goto exit;
- }
-
- /* Convert from CPName-lite to normal and NUL-terminate. */
- memcpy(localTargetName, targetName, targetNameLength);
- CPNameLite_ConvertFrom(localTargetName, targetNameLength, DIRSEPC);
- localTargetName[targetNameLength] = '\0';
-
- /* Prohibit symlink ceation if symlink following is enabled. */
- if (HgfsServerPolicy_IsShareOptionSet(configOptions,
- HGFS_SHARE_FOLLOW_SYMLINKS)) {
- status = EPERM;
- goto exit;
- }
-
- LOG(4, ("%s: creating \"%s\" linked to \"%s\"\n", __FUNCTION__,
- localSymlinkName, localTargetName));
+ int error;
/* XXX: Should make use of targetNameP->flags? */
error = Posix_Symlink(localTargetName, localSymlinkName);
if (error) {
status = errno;
LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(errno)));
- goto exit;
- }
-
- status = 0;
- if (!HgfsPackAndSendPacket(input->packet, packetOut, packetOutSize,
- status, header->id,
- session, 0)) {
- goto exit;
}
- free(localSymlinkName);
- return status;
-
-exit:
- free(localSymlinkName);
- HSPU_PutReplyPacket(input->packet, session);
return status;
}
*/
HgfsInternalStatus
-HgfsServerWriteWin32Stream(HgfsInputParam *input) // IN: Input params
-{
- return EOPNOTSUPP;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsServerServerLockChange --
- *
- * Called by the client when it wants to either acquire an oplock on a file
- * that was previously opened, or when it wants to release/downgrade an
- * oplock on a file that was previously oplocked.
- *
- * Results:
- * EOPNOTSUPP, because this is unimplemented.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-HgfsInternalStatus
-HgfsServerServerLockChange(HgfsInputParam *input) // IN: Input params
+HgfsServerWriteWin32Stream(char const *packetIn, // IN: incoming packet
+ HgfsOp op, // IN: request type
+ const void *payload, // IN: HGFS operational packet (without header)
+ size_t payloadSize, // IN: size of HGFS operational packet
+ HgfsSessionInfo *session) // IN: session info
{
return EOPNOTSUPP;
}
}
#endif
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsIsShareRoot --
- *
- * Checks if the cpName represents the root directory for a share.
- * Components in CPName format are separated by NUL characters.
- * CPName for the root of a share contains only one component thus
- * it does not have any embedded '\0' characters in the name.
- *
- * Results:
- * TRUE if it is the root directory, FALSE otherwise.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-HgfsIsShareRoot(char const *cpName, // IN: name to test
- size_t cpNameSize) // IN: length of the name
-{
- size_t i;
- for (i = 0; i < cpNameSize; i++) {
- if (cpName[i] == '\0') {
- return FALSE;
- }
- }
- return TRUE;
-}
-
#if defined(__APPLE__)
/*
*-----------------------------------------------------------------------------
ASSERT_DEVEL(*replyPacketSize <= packet->replyPacketSize);
} else if (session->channelCbTable && session->channelCbTable->getWriteVa) {
/* Can we write directly into guest memory ? */
+ ASSERT_DEVEL(packet->metaPacket);
if (packet->metaPacket) {
LOG(10, ("%s Using meta packet for reply packet\n", __FUNCTION__));
ASSERT_DEVEL(*replyPacketSize <= packet->metaPacketSize);
packet->replyPacket = packet->metaPacket;
packet->replyPacketSize = packet->metaPacketSize;
- } else {
- /* This should really never happen in existing scenarios */
- ASSERT_DEVEL(0);
LOG(10, ("%s Mapping meta packet for reply packet\n", __FUNCTION__));
- packet->replyPacket = HSPU_GetBuf(packet, 0, &packet->metaPacket,
+ packet->replyPacket = HSPU_GetBuf(packet,
+ 0,
+ &packet->metaPacket,
packet->metaPacketSize,
&packet->metaPacketIsAllocated,
BUF_WRITEABLE,
uint32 startIndex, // IN: Start of iov
void **buf, // IN/OUT: Buffer to be freed
size_t *bufSize, // IN: Size of the buffer
- Bool *isAllocated, // IN: Was buffer allocated ?
- uint32 mappingType, // IN: Readable / Writeable ?
- HgfsSessionInfo *session) // IN: Session info
+ Bool *isAllocated, // IN: Was buffer allocated ?
+ MappingType mappingType, // IN: Readable / Writeable ?
+ HgfsSessionInfo *session) // IN: Session info
{
uint32 iovCount = 0;
int size = *bufSize;
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "vmware.h"
+#include "str.h"
+#include "cpName.h"
+#include "cpNameLite.h"
+#include "hgfsServerInt.h"
+#include "hgfsServerPolicy.h"
+#include "codeset.h"
+#include "config.h"
+#include "file.h"
+#include "util.h"
+#include "wiper.h"
+#include "vm_basic_asm.h"
+
+#define LOGLEVEL_MODULE hgfs
+#include "loglevel_user.h"
+
+#ifdef _WIN32
+#define HGFS_REQUEST_WIN32_SUPPORTED HGFS_REQUEST_SUPPORTED
+#define HGFS_REQUEST_POSIX_SUPPORTED HGFS_REQUEST_NOT_SUPPORTED
+#else
+#define HGFS_REQUEST_WIN32_SUPPORTED HGFS_REQUEST_NOT_SUPPORTED
+#define HGFS_REQUEST_POSIX_SUPPORTED HGFS_REQUEST_SUPPORTED
+#endif
+
+#define HGFS_ASSERT_PACK_PARAMS \
+ do { \
+ ASSERT(packet); \
+ ASSERT(packetHeader); \
+ ASSERT(session); \
+ ASSERT(payloadSize); \
+ } while(0)
+
+/* Capabilities of the HGFS server. */
+static HgfsCapability hgfsServerCapabilities[] =
+{
+ {HGFS_OP_OPEN, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_READ, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_WRITE, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_CLOSE, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_SEARCH_OPEN, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_SEARCH_READ, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_SEARCH_CLOSE, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_GETATTR, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_SETATTR, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_CREATE_DIR, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_DELETE_FILE, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_DELETE_DIR, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_RENAME, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_QUERY_VOLUME_INFO, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_OPEN_V2, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_GETATTR_V2, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_SETATTR_V2, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_SEARCH_READ_V2, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_CREATE_SYMLINK, HGFS_REQUEST_POSIX_SUPPORTED},
+ {HGFS_OP_SERVER_LOCK_CHANGE, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_CREATE_DIR_V2, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_DELETE_FILE_V2, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_DELETE_DIR_V2, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_RENAME_V2, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_OPEN_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_READ_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_WRITE_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_CLOSE_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_SEARCH_OPEN_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_SEARCH_READ_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_SEARCH_CLOSE_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_GETATTR_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_SETATTR_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_CREATE_DIR_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_DELETE_FILE_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_DELETE_DIR_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_RENAME_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_QUERY_VOLUME_INFO_V3, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_CREATE_SYMLINK_V3, HGFS_REQUEST_POSIX_SUPPORTED},
+ {HGFS_OP_SERVER_LOCK_CHANGE_V3, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_WRITE_WIN32_STREAM_V3, HGFS_REQUEST_WIN32_SUPPORTED},
+ {HGFS_OP_CREATE_SESSION_V4, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_DESTROY_SESSION_V4, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_READ_FAST_V4, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_WRITE_FAST_V4, HGFS_REQUEST_SUPPORTED},
+ {HGFS_OP_OPEN_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_DIRECTORY_READ_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_ENUMERATE_STREAMS_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_GETATTR_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_SETATTR_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_DELETE_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_LINKMOVE_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_FSCTL_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_ACCESS_CHECK_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_FSYNC_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_QUERY_VOLUME_INFO_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_OPLOCK_ACQUIRE_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_OPLOCK_BREAK_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_LOCK_BYTE_RANGE_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_UNLOCK_BYTE_RANGE_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_QUERY_EAS_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_SET_EAS_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_SET_WATCH_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_REMOVE_WATCH_V4, HGFS_REQUEST_NOT_SUPPORTED},
+ {HGFS_OP_NOTIFY_V4, HGFS_REQUEST_NOT_SUPPORTED},
+};
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsValidatePacket --
+ *
+ * Validates that packet is not malformed. Checks consistency of various
+ * fields and sizes.
+ *
+ * Results:
+ * TRUE if the packet is correct.
+ * FALSE if the packet is malformed.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsValidatePacket(char const *packetIn, // IN: request packet
+ size_t packetSize, // IN: request packet size
+ Bool v4header) // IN: HGFS header type
+{
+ HgfsRequest *request = (HgfsRequest *)packetIn;
+ Bool result = TRUE;
+ if (packetSize < sizeof *request) {
+ LOG(4, ("%s: Malformed HGFS packet received - packet too small!\n", __FUNCTION__));
+ return FALSE;
+ }
+ if (v4header) {
+ HgfsHeader *header = (HgfsHeader *)packetIn;
+ ASSERT(packetSize >= header->packetSize);
+ ASSERT(header->packetSize >= header->headerSize);
+ result = packetSize >= offsetof(HgfsHeader, requestId) &&
+ header->headerSize >= offsetof(HgfsHeader, reserved) &&
+ header->packetSize >= header->headerSize &&
+ packetSize >= header->packetSize;
+ } else {
+ result = packetSize >= sizeof *request;
+ }
+ if (!result) {
+ LOG(4, ("%s: Malformed HGFS packet received!\n", __FUNCTION__));
+ }
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsValidateReplySize --
+ *
+ * Verify if the size of a reply does not exceed maximum supported size.
+ *
+ * Results:
+ * TRUE if the packet size is acceptable, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsValidateReplySize(char const *packetIn,
+ HgfsOp op,
+ size_t packetSize)
+{
+ Bool result;
+ HgfsRequest *request = (HgfsRequest *)packetIn;
+
+ if (HGFS_V4_LEGACY_OPCODE != request->op) {
+ if (HGFS_OP_READ_V3 == op) {
+ result = packetSize <= HGFS_LARGE_PACKET_MAX;
+ } else {
+ result = packetSize <= HGFS_PACKET_MAX;
+ }
+ } else {
+ result = TRUE;
+ }
+ if (!result) {
+ LOG(4, ("%s: Reply exceeded maximum support size!\n", __FUNCTION__));
+ }
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsGetPayloadSize --
+ *
+ * Returns size of the payload based on incoming packet and total
+ * packet size.
+ *
+ * Results:
+ * Size of the payload in bytes.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+size_t
+HgfsGetPayloadSize(char const *packetIn, // IN: request packet
+ size_t packetSize) // IN: request packet size
+{
+ HgfsRequest *request = (HgfsRequest *)packetIn;
+ size_t result;
+ ASSERT(packetSize >= sizeof *request);
+ if (request->op < HGFS_OP_CREATE_SESSION_V4) {
+ result = packetSize - sizeof *request;
+ } else {
+ HgfsHeader *header = (HgfsHeader *)packetIn;
+ ASSERT(packetSize >= header->packetSize);
+ ASSERT(header->packetSize >= header->headerSize);
+ result = header->packetSize - header->headerSize;
+ }
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsParseRequest --
+ *
+ * Returns requested operation and pointer to the payload based on
+ * incoming packet and total packet size.
+ *
+ * Results:
+ * TRUE if a reply can be sent.
+ * FALSE if incoming packet does not allow sending any response.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsParseRequest(HgfsPacket *packet, // IN: request packet
+ HgfsSessionInfo *session, // IN: current session
+ HgfsInputParam **input, // OUT: request parameters
+ HgfsInternalStatus *status) // OUT: error code
+{
+ HgfsRequest *request;
+ size_t packetSize;
+ HgfsInternalStatus result = HGFS_ERROR_SUCCESS;
+ HgfsInputParam *localInput;
+
+ request = (HgfsRequest *) HSPU_GetMetaPacket(packet, &packetSize, session);
+ ASSERT_DEVEL(request);
+
+ if (!request) {
+ /*
+ * How can I return error back to the client, clearly the client is either broken or
+ * malicious? We cannot continue from here.
+ */
+ return FALSE;
+ }
+
+ *input = Util_SafeMalloc(sizeof *localInput);
+ localInput = *input;
+
+ memset(localInput, 0, sizeof *localInput);
+ localInput->metaPacket = (char *)request;
+ localInput->metaPacketSize = packetSize;
+ localInput->session = session;
+ localInput->packet = packet;
+
+ /*
+ * Error out if less than HgfsRequest size.
+ */
+ if (packetSize < sizeof *request) {
+ if (packetSize >= sizeof request->id) {
+ localInput->id = request->id;
+ }
+ ASSERT_DEVEL(0);
+ return HGFS_ERROR_PROTOCOL;
+ }
+
+ if (request->op < HGFS_OP_OPEN_V3) {
+ /* Legacy requests do not have a separate header. */
+ localInput->payload = request;
+ localInput->op = request->op;
+ localInput->payloadSize = packetSize;
+ localInput->id = request->id;
+ } else if (request->op < HGFS_OP_CREATE_SESSION_V4) {
+ /* V3 header. */
+ if (packetSize > sizeof *request) {
+ localInput->payload = HGFS_REQ_GET_PAYLOAD_V3(request);
+ localInput->payloadSize = packetSize -
+ ((char *)localInput->payload - (char *)request);
+ }
+ localInput->op = request->op;
+ localInput->id = request->id;
+ } else if (HGFS_V4_LEGACY_OPCODE == request->op) {
+ /* V4 header. */
+ HgfsHeader *header = (HgfsHeader *)request;
+ localInput->v4header = TRUE;
+ localInput->id = header->requestId;
+
+ if (packetSize >= offsetof(HgfsHeader, sessionId) + sizeof header->sessionId) {
+ if (header->sessionId != session->sessionId &&
+ header->op != HGFS_OP_CREATE_SESSION_V4) {
+ LOG(4, ("%s: HGFS packet with invalid session id!\n", __FUNCTION__));
+ result = HGFS_ERROR_STALE_SESSION;
+ } else if (packetSize < header->packetSize ||
+ header->packetSize < header->headerSize) {
+ LOG(4, ("%s: Malformed HGFS packet received - inconsistent header"
+ " and packet sizes!\n", __FUNCTION__));
+ result = HGFS_ERROR_PROTOCOL;
+ }
+ } else {
+ LOG(4, ("%s: Malformed HGFS packet received - header is too small!\n",
+ __FUNCTION__));
+ result = HGFS_ERROR_PROTOCOL;
+ }
+
+ if (HGFS_ERROR_SUCCESS == result) { // Passed all tests
+ localInput->op = header->op;
+ localInput->payload = (char *)request + header->headerSize;
+ localInput->payloadSize = header->packetSize - header->headerSize;
+ }
+ } else {
+ LOG(4, ("%s: Malformed HGFS packet received - invalid legacy opcode!\n",
+ __FUNCTION__));
+ result = HGFS_ERROR_PROTOCOL;
+ }
+ if (HGFS_ERROR_SUCCESS != result) {
+ LOG(4, ("%s: Malformed HGFS packet received!\n", __FUNCTION__));
+ }
+ *status = result;
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackOpenPayloadV1 --
+ *
+ * Unpack and validate payload for hgfs open request V1 to the HgfsFileOpenInfo
+ * structure that is used to pass around open request information.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackOpenPayloadV1(HgfsRequestOpen *requestV1, // IN: request payload
+ size_t payloadSize, // IN: request payload size
+ HgfsFileOpenInfo *openInfo) // IN/OUT: open info struct
+{
+ size_t extra;
+
+ /* Enforced by the dispatch function. */
+ if (payloadSize < sizeof *requestV1) {
+ LOG(4, ("%s: Malformed HGFS packet received - payload too small\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ extra = payloadSize - sizeof *requestV1;
+
+ /*
+ * The request file name length is user-provided, so this test must be
+ * carefully written to prevent wraparounds.
+ */
+ if (requestV1->fileName.length > extra) {
+ /* The input packet is smaller than the request. */
+ LOG(4, ("%s: Malformed HGFS packet received - payload too small to hold file name\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ /* For OpenV1 requests, we know exactly what fields we expect. */
+ openInfo->mask = HGFS_OPEN_VALID_MODE |
+ HGFS_OPEN_VALID_FLAGS |
+ HGFS_OPEN_VALID_OWNER_PERMS |
+ HGFS_OPEN_VALID_FILE_NAME;
+ openInfo->mode = requestV1->mode;
+ openInfo->cpName = requestV1->fileName.name;
+ openInfo->cpNameSize = requestV1->fileName.length;
+ openInfo->flags = requestV1->flags;
+ openInfo->ownerPerms = requestV1->permissions;
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackOpenPayloadV2 --
+ *
+ * Unpack and validate payload for hgfs open request V2 to the HgfsFileOpenInfo
+ * structure that is used to pass around open request information.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackOpenPayloadV2(HgfsRequestOpenV2 *requestV2, // IN: request payload
+ size_t payloadSize, // IN: request payload size
+ HgfsFileOpenInfo *openInfo) // IN/OUT: open info struct
+{
+ size_t extra;
+
+ /* Enforced by the dispatch function. */
+ if (payloadSize < sizeof *requestV2) {
+ LOG(4, ("%s: Malformed HGFS packet received - payload too small\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ extra = payloadSize - sizeof *requestV2;
+
+ if (!(requestV2->mask & HGFS_OPEN_VALID_FILE_NAME)) {
+ /* We do not support open requests without a valid file name. */
+ LOG(4, ("%s: Malformed HGFS packet received - invalid mask\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ /*
+ * The request file name length is user-provided, so this test must be
+ * carefully written to prevent wraparounds.
+ */
+ if (requestV2->fileName.length > extra) {
+ /* The input packet is smaller than the request. */
+ LOG(4, ("%s: Malformed HGFS packet received - payload too small to hold file name\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ /*
+ * Copy all the fields into our carrier struct. Some will probably be
+ * garbage, but it's simpler to copy everything now and check the
+ * valid bits before reading later.
+ */
+
+ openInfo->mask = requestV2->mask;
+ openInfo->mode = requestV2->mode;
+ openInfo->cpName = requestV2->fileName.name;
+ openInfo->cpNameSize = requestV2->fileName.length;
+ openInfo->flags = requestV2->flags;
+ openInfo->specialPerms = requestV2->specialPerms;
+ openInfo->ownerPerms = requestV2->ownerPerms;
+ openInfo->groupPerms = requestV2->groupPerms;
+ openInfo->otherPerms = requestV2->otherPerms;
+ openInfo->attr = requestV2->attr;
+ openInfo->allocationSize = requestV2->allocationSize;
+ openInfo->desiredAccess = requestV2->desiredAccess;
+ openInfo->shareAccess = requestV2->shareAccess;
+ openInfo->desiredLock = requestV2->desiredLock;
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackOpenPayloadV3 --
+ *
+ * Unpack and validate payload for hgfs open request V3 to the HgfsFileOpenInfo
+ * structure that is used to pass around open request information.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackOpenPayloadV3(HgfsRequestOpenV3 *requestV3, // IN: request payload
+ size_t payloadSize, // IN: request payload size
+ HgfsFileOpenInfo *openInfo) // IN/OUT: open info struct
+{
+ size_t extra;
+
+ /* Enforced by the dispatch function. */
+ if (payloadSize < sizeof *requestV3) {
+ LOG(4, ("%s: Malformed HGFS packet received - payload too small\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ extra = payloadSize - sizeof *requestV3;
+
+ if (!(requestV3->mask & HGFS_OPEN_VALID_FILE_NAME)) {
+ /* We do not support open requests without a valid file name. */
+ LOG(4, ("%s: Malformed HGFS packet received - incorrect mask\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ /*
+ * The request file name length is user-provided, so this test must be
+ * carefully written to prevent wraparounds.
+ */
+ if (requestV3->fileName.length > extra) {
+ /* The input packet is smaller than the request. */
+ LOG(4, ("%s: Malformed HGFS packet received - payload too small to hold file name\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ /*
+ * Copy all the fields into our carrier struct. Some will probably be
+ * garbage, but it's simpler to copy everything now and check the
+ * valid bits before reading later.
+ */
+ openInfo->mask = requestV3->mask;
+ openInfo->mode = requestV3->mode;
+ openInfo->cpName = requestV3->fileName.name;
+ openInfo->cpNameSize = requestV3->fileName.length;
+ openInfo->caseFlags = requestV3->fileName.caseType;
+ openInfo->flags = requestV3->flags;
+ openInfo->specialPerms = requestV3->specialPerms;
+ openInfo->ownerPerms = requestV3->ownerPerms;
+ openInfo->groupPerms = requestV3->groupPerms;
+ openInfo->otherPerms = requestV3->otherPerms;
+ openInfo->attr = requestV3->attr;
+ openInfo->allocationSize = requestV3->allocationSize;
+ openInfo->desiredAccess = requestV3->desiredAccess;
+ openInfo->shareAccess = requestV3->shareAccess;
+ openInfo->desiredLock = requestV3->desiredLock;
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackOpenRequest --
+ *
+ * Unpack hgfs open request to the HgfsFileOpenInfo structure that is used
+ * to pass around open request information.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackOpenRequest(void const *packet, // IN: HGFS packet
+ size_t packetSize, // IN: packet size
+ HgfsOp op, // IN: requested operation
+ HgfsFileOpenInfo *openInfo) // IN/OUT: open info structure
+{
+ Bool result;
+
+ ASSERT(packet);
+ ASSERT(openInfo);
+
+ openInfo->requestType = op;
+ openInfo->caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+
+ switch (op) {
+ case HGFS_OP_OPEN_V3: {
+ HgfsRequestOpenV3 *requestV3 = (HgfsRequestOpenV3 *)packet;
+ LOG(4, ("%s: HGFS_OP_OPEN_V3\n", __FUNCTION__));
+
+ result = HgfsUnpackOpenPayloadV3(requestV3, packetSize, openInfo);
+ break;
+ }
+ case HGFS_OP_OPEN_V2: {
+ HgfsRequestOpenV2 *requestV2 = (HgfsRequestOpenV2 *)packet;
+ LOG(4, ("%s: HGFS_OP_OPEN_V2\n", __FUNCTION__));
+
+ result = HgfsUnpackOpenPayloadV2(requestV2, packetSize, openInfo);
+ break;
+ }
+ case HGFS_OP_OPEN: {
+ HgfsRequestOpen *requestV1 = (HgfsRequestOpen *)packet;
+ LOG(4, ("%s: HGFS_OP_OPEN\n", __FUNCTION__));
+
+ result = HgfsUnpackOpenPayloadV1(requestV1, packetSize, openInfo);
+ break;
+ }
+ default:
+ NOT_REACHED();
+ result = FALSE;
+ }
+
+ if (!result) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ }
+ return result;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackReplyHeaderV4 --
+ *
+ * Pack hgfs header that corresponds an incoming packet.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsPackReplyHeaderV4(HgfsInternalStatus status, // IN: reply status
+ uint32 payloadSize, // IN: size of the reply payload
+ HgfsOp op, // IN: request type
+ uint64 sessionId, // IN: session id
+ uint32 requestId, // IN: request id
+ HgfsHeader *header) // OUT: outgoing packet header
+{
+ memset(header, 0, sizeof *header);
+ header->version = 1;
+ header->dummy = HGFS_V4_LEGACY_OPCODE;
+ header->packetSize = payloadSize + sizeof *header;
+ header->headerSize = sizeof *header;
+ header->requestId = requestId;
+ header->op = op;
+ header->status = HgfsConvertFromInternalStatus(status);
+ header->flags = 0;
+ header->information = status;
+ header->sessionId = sessionId;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackLegacyReplyHeader --
+ *
+ * Pack pre-V4 reply header.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsPackLegacyReplyHeader(HgfsInternalStatus status, // IN: reply status
+ HgfsHandle id, // IN: original packet id
+ HgfsReply *header) // OUT: outgoing packet header
+{
+ memset(header, 0, sizeof *header);
+ header->status = HgfsConvertFromInternalStatus(status);
+ header->id = id;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackOpenReplyV3 --
+ *
+ * Pack hgfs open V3 reply payload to the HgfsReplyOpenV3 structure.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HgfsPackOpenReplyV3(HgfsFileOpenInfo *openInfo, // IN: open info struct
+ HgfsReplyOpenV3 *reply) // OUT: size of packet
+{
+ reply->file = openInfo->file;
+ reply->reserved = 0;
+ if (openInfo->mask & HGFS_OPEN_VALID_SERVER_LOCK) {
+ reply->acquiredLock = openInfo->acquiredLock;
+ } else {
+ reply->acquiredLock = HGFS_LOCK_NONE;
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackOpenV2Reply --
+ *
+ * Pack hgfs open V2 reply payload to the HgfsReplyOpenV3 structure.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HgfsPackOpenV2Reply(HgfsFileOpenInfo *openInfo, // IN: open info struct
+ HgfsReplyOpenV2 *reply) // OUT: reply payload
+{
+ reply->file = openInfo->file;
+ if (openInfo->mask & HGFS_OPEN_VALID_SERVER_LOCK) {
+ reply->acquiredLock = openInfo->acquiredLock;
+ } else {
+ reply->acquiredLock = HGFS_LOCK_NONE;
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackOpenV1Reply --
+ *
+ * Pack hgfs open V1 reply payload to the HgfsReplyOpenV3 structure.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HgfsPackOpenV1Reply(HgfsFileOpenInfo *openInfo, // IN: open info struct
+ HgfsReplyOpen *reply) // OUT: reply payload
+{
+ reply->file = openInfo->file;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackOpenReply --
+ *
+ * Pack hgfs open reply to the HgfsReplyOpen{V2} structure.
+ *
+ * Results:
+ * Always TRUE.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsFileOpenInfo *openInfo, // IN: open info struct
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ ASSERT(openInfo);
+ HGFS_ASSERT_PACK_PARAMS;
+
+ *payloadSize = 0;
+
+ switch (openInfo->requestType) {
+ case HGFS_OP_OPEN_V3: {
+ HgfsReplyOpenV3 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ HgfsPackOpenReplyV3(openInfo, reply);
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_OPEN_V2: {
+ HgfsReplyOpenV2 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ HgfsPackOpenV2Reply(openInfo, reply);
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_OPEN: {
+ HgfsReplyOpen *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ HgfsPackOpenV1Reply(openInfo, reply);
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ default:
+ NOT_REACHED();
+ result = FALSE;
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackClosePayload --
+ *
+ * Unpack hgfs close payload to get the handle which need to be closed.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackClosePayload(HgfsRequestClose *request, // IN: payload
+ size_t payloadSize, // IN: payload size
+ HgfsHandle* file) // OUT: HGFS handle to close
+{
+ LOG(4, ("%s: HGFS_OP_CLOSE\n", __FUNCTION__));
+ if (payloadSize >= sizeof *request) {
+ *file = request->file;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackClosePayloadV3 --
+ *
+ * Unpack hgfs close payload V3 to get the handle which need to be closed.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackClosePayloadV3(HgfsRequestCloseV3 *requestV3, // IN: payload
+ size_t payloadSize, // IN: payload size
+ HgfsHandle* file) // OUT: HGFS handle to close
+{
+ LOG(4, ("%s: HGFS_OP_CLOSE_V3\n", __FUNCTION__));
+ if (payloadSize >= sizeof *requestV3) {
+ *file = requestV3->file;
+ return TRUE;
+ }
+ LOG(4, ("%s: Too small HGFS packet\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackCloseRequest --
+ *
+ * Unpack hgfs close request to get the handle to close.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackCloseRequest(void const *packet, // IN: request packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ HgfsHandle *file) // OUT: Handle to close
+{
+ ASSERT(packet);
+
+ switch (op) {
+ case HGFS_OP_CLOSE_V3: {
+ HgfsRequestCloseV3 *requestV3 = (HgfsRequestCloseV3 *)packet;
+
+ if (!HgfsUnpackClosePayloadV3(requestV3, packetSize, file)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ case HGFS_OP_CLOSE: {
+ HgfsRequestClose *requestV1 = (HgfsRequestClose *)packet;
+
+ if (!HgfsUnpackClosePayload(requestV1, packetSize, file)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ default:
+ NOT_REACHED();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackCloseReply --
+ *
+ * Pack hgfs close reply to the HgfsReplyClose(V3) structure.
+ *
+ * Results:
+ * Always TRUE.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ size_t *payloadSize, // OUT: size of packet excluding header
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ HGFS_ASSERT_PACK_PARAMS;
+
+ *payloadSize = 0;
+
+ switch (op) {
+ case HGFS_OP_CLOSE_V3: {
+ HgfsReplyCloseV3 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_CLOSE: {
+ HgfsReplyClose *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ default:
+ NOT_REACHED();
+ result = FALSE;
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSearchClosePayload --
+ *
+ * Unpack hgfs search close payload to get the search handle which need to be closed.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSearchClosePayload(HgfsRequestSearchClose *request, // IN: payload
+ size_t payloadSize, // IN: payload size
+ HgfsHandle* search) // OUT: search to close
+{
+ LOG(4, ("%s: HGFS_OP_SEARCH_CLOSE\n", __FUNCTION__));
+ if (payloadSize >= sizeof *request) {
+ *search = request->search;
+ return TRUE;
+ }
+ LOG(4, ("%s: Too small HGFS packet\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackClosePayloadV3 --
+ *
+ * Unpack hgfs search close payload V3 to get the search handle which need to
+ * be closed.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSearchClosePayloadV3(HgfsRequestSearchCloseV3 *requestV3, // IN: payload
+ size_t payloadSize, // IN: payload size
+ HgfsHandle* search) // OUT: search
+{
+ LOG(4, ("%s: HGFS_OP_SEARCH_CLOSE_V3\n", __FUNCTION__));
+ if (payloadSize >= sizeof *requestV3) {
+ *search = requestV3->search;
+ return TRUE;
+ }
+ LOG(4, ("%s: Too small HGFS packet\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSearchCloseRequest --
+ *
+ * Unpack hgfs search close request to get the search handle.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSearchCloseRequest(void const *packet, // IN: request packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ HgfsHandle *search) // OUT: search to close
+{
+ ASSERT(packet);
+
+ switch (op) {
+ case HGFS_OP_SEARCH_CLOSE_V3: {
+ HgfsRequestSearchCloseV3 *requestV3 = (HgfsRequestSearchCloseV3 *)packet;
+
+ if (!HgfsUnpackSearchClosePayloadV3(requestV3, packetSize, search)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ case HGFS_OP_SEARCH_CLOSE: {
+ HgfsRequestSearchClose *requestV1 = (HgfsRequestSearchClose *)packet;
+
+ if (!HgfsUnpackSearchClosePayload(requestV1, packetSize, search)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ default:
+ NOT_REACHED();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackSearchCloseReply --
+ *
+ * Pack hgfs SearchClose reply into a HgfsReplySearchClose(V3) structure.
+ *
+ * Results:
+ * Always TRUE, except when it is called with a
+ * wrong op or insufficient output buffer (which is a programming error).
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackSearchCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ HGFS_ASSERT_PACK_PARAMS;
+
+ *payloadSize = 0;
+
+ switch (op) {
+ case HGFS_OP_SEARCH_CLOSE_V3: {
+ HgfsReplyCloseV3 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_SEARCH_CLOSE: {
+ HgfsReplyClose *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ default:
+ NOT_REACHED();
+ result = FALSE;
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackFileName --
+ *
+ * Unpack HgfsFileName into a pointer to a CPName and size of the name.
+ * Verifies that input buffer has enough space to hold the name.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure (buffer too small).
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackFileName(HgfsFileName *name, // IN: file name
+ size_t maxNameSize, // IN: space allocated for the name
+ char **cpName, // OUT: CP name
+ size_t *cpNameSize) // OUT: CP name size
+{
+ /*
+ * The request file name length is user-provided, so this test must be
+ * carefully written to prevent wraparounds.
+ */
+ if (name->length > maxNameSize) {
+ /* The input packet is smaller than the request. */
+ return FALSE;
+ }
+ *cpName = name->name;
+ *cpNameSize = name->length;
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackFileNameV3 --
+ *
+ * Unpack HgfsFileNameV3 into a pointer to a CPName and size of the name
+ * or into file handle.
+ * Verifies that input buffer has enough space to hold the name.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure (buffer too small).
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackFileNameV3(HgfsFileNameV3 *name, // IN: file name
+ size_t maxNameSize, // IN: space allocated for the name
+ Bool *useHandle, // OUT: file name or handle returned?
+ char **cpName, // OUT: CP name
+ size_t *cpNameSize, // OUT: CP name size
+ HgfsHandle *file, // OUT: HGFS file handle
+ uint32 *caseFlags) // OUT: case-sensitivity flags
+{
+ /*
+ * If we've been asked to reuse a handle, we don't need to look at, let
+ * alone test the filename or its length.
+ */
+ if (name->flags & HGFS_FILE_NAME_USE_FILE_DESC) {
+ *file = name->fid;
+ *cpName = NULL;
+ *cpNameSize = 0;
+ *caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+ *useHandle = TRUE;
+ } else {
+ /*
+ * The request file name length is user-provided, so this test must be
+ * carefully written to prevent wraparounds.
+ */
+ if (name->length > maxNameSize) {
+ /* The input packet is smaller than the request */
+ LOG(4, ("%s: Error unpacking file name - buffer too small\n", __FUNCTION__));
+ return FALSE;
+ }
+ *file = HGFS_INVALID_HANDLE;
+ *cpName = name->name;
+ *cpNameSize = name->length;
+ *caseFlags = name->caseType;
+ *useHandle = FALSE;
+ }
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackDeletePayloadV3 --
+ *
+ * Unpack hgfs delete request V3 payload and initialize a corresponding
+ * HgfsHandle or file name to tell us which to delete. Hints
+ * holds flags to specify a handle or name for the file or
+ * directory to delete.
+ *
+ * Since the structure of the get delete request packet is the same
+ * for Delete File or Directory of the protocol, code is identical for
+ * both operations.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackDeletePayloadV3(HgfsRequestDeleteV3 *requestV3, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize, // OUT: cpName size
+ HgfsDeleteHint *hints, // OUT: delete hints
+ HgfsHandle *file, // OUT: file handle
+ uint32 *caseFlags) // OUT: case-sensitivity flags
+{
+ Bool result;
+ Bool useHandle;
+
+ if (payloadSize < sizeof *requestV3) {
+ return FALSE;
+ }
+
+ *hints = requestV3->hints;
+
+ result = HgfsUnpackFileNameV3(&requestV3->fileName,
+ payloadSize - sizeof *requestV3,
+ &useHandle,
+ cpName,
+ cpNameSize,
+ file,
+ caseFlags);
+ if (useHandle) {
+ *hints |= HGFS_DELETE_HINT_USE_FILE_DESC;
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackDeletePayloadV2 --
+ *
+ * Unpack hgfs delete request V2 payload and initialize a corresponding
+ * HgfsHandle or file name to tell us which to delete. Hints
+ * holds flags to specify a handle or name for the file or
+ * directory to delete.
+ *
+ * Since the structure of the get delete request packet is the same
+ * for Delete File or Directory of the protocol, code is identical for
+ * both operations.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackDeletePayloadV2(HgfsRequestDeleteV2 *requestV2, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize, // OUT: cpName size
+ HgfsDeleteHint *hints, // OUT: delete hints
+ HgfsHandle *file) // OUT: file handle
+{
+ Bool result = TRUE;
+
+ /* Enforced by the dispatch function. */
+ ASSERT(payloadSize >= sizeof *requestV2);
+
+ *file = HGFS_INVALID_HANDLE;
+ *hints = requestV2->hints;
+
+ /*
+ * If we've been asked to reuse a handle, we don't need to look at, let
+ * alone test the filename or its length.
+ */
+
+ if (requestV2->hints & HGFS_DELETE_HINT_USE_FILE_DESC) {
+ *file = requestV2->file;
+ *cpName = NULL;
+ *cpNameSize = 0;
+ } else {
+ result = HgfsUnpackFileName(&requestV2->fileName,
+ payloadSize - sizeof *requestV2,
+ cpName,
+ cpNameSize);
+ }
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackDeletePayloadV1 --
+ *
+ * Unpack hgfs delete request V1 payload and initialize a corresponding
+ * file name to tell us which to delete.
+ *
+ * Since the structure of the get delete request packet is the same
+ * for Delete File or Directory of the protocol, code is identical for
+ * both operations.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackDeletePayloadV1(HgfsRequestDelete *requestV1, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize) // OUT: cpName size
+{
+ return HgfsUnpackFileName(&requestV1->fileName,
+ payloadSize - sizeof *requestV1,
+ cpName,
+ cpNameSize);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackDeleteRequest --
+ *
+ * Unpack hgfs delete request and initialize a corresponding
+ * HgfsHandle or file name to tell us which to delete. Hints
+ * holds flags to specify a handle or name for the file or
+ * directory to delete.
+ *
+ * Since the structure of the get delete request packet is the same
+ * for Delete File or Directory of the protocol, code is identical for
+ * both operations.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackDeleteRequest(void const *packet, // IN: HGFS packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: requested operation
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize, // OUT: cpName size
+ HgfsDeleteHint *hints, // OUT: delete hints
+ HgfsHandle *file, // OUT: file handle
+ uint32 *caseFlags) // OUT: case-sensitivity flags
+{
+ ASSERT(packet);
+ ASSERT(cpName);
+ ASSERT(cpNameSize);
+ ASSERT(file);
+ ASSERT(hints);
+ ASSERT(caseFlags);
+
+ *caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+ *hints = 0;
+ *file = HGFS_INVALID_HANDLE;
+
+ switch (op) {
+ case HGFS_OP_DELETE_FILE_V3:
+ case HGFS_OP_DELETE_DIR_V3: {
+ HgfsRequestDeleteV3 *requestV3 = (HgfsRequestDeleteV3 *)packet;
+
+ if (!HgfsUnpackDeletePayloadV3(requestV3,
+ packetSize,
+ cpName,
+ cpNameSize,
+ hints,
+ file,
+ caseFlags)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ case HGFS_OP_DELETE_FILE_V2:
+ case HGFS_OP_DELETE_DIR_V2: {
+ HgfsRequestDeleteV2 *requestV2 = (HgfsRequestDeleteV2 *)packet;
+
+ if (!HgfsUnpackDeletePayloadV2(requestV2,
+ packetSize,
+ cpName,
+ cpNameSize,
+ hints,
+ file)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ case HGFS_OP_DELETE_FILE:
+ case HGFS_OP_DELETE_DIR: {
+ HgfsRequestDelete *requestV1 = (HgfsRequestDelete *)packet;
+
+ if (!HgfsUnpackDeletePayloadV1(requestV1,
+ packetSize,
+ cpName,
+ cpNameSize)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ default:
+ NOT_REACHED();
+ LOG(4, ("%s: Invalid opcode\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackDeleteReply --
+ *
+ * Pack hgfs delete reply.
+ * Since the structure of the delete reply packet hasn't changed in
+ * version 2 of the protocol, HgfsReplyDeleteV2 is identical to
+ * HgfsReplyDelete. So use HgfsReplyDelete type to access packetIn to
+ * keep the code simple.
+ *
+ * Results:
+ * TRUE if valid op version reply filled, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackDeleteReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: requested operation
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ HGFS_ASSERT_PACK_PARAMS;
+
+ *payloadSize = 0;
+
+ /* No reply payload, just header. */
+ switch (op) {
+ case HGFS_OP_DELETE_FILE_V3:
+ case HGFS_OP_DELETE_DIR_V3: {
+ HgfsReplyDeleteV3 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_DELETE_FILE_V2:
+ case HGFS_OP_DELETE_FILE:
+ case HGFS_OP_DELETE_DIR_V2:
+ case HGFS_OP_DELETE_DIR: {
+ HgfsReplyDelete *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ default:
+ LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, op));
+ result = FALSE;
+ NOT_REACHED();
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackRenamePayloadV3 --
+ *
+ * Unpack hgfs rename request V3 payload and initialize a corresponding
+ * HgfsHandles or file names to tell us old and new names/handles. Hints
+ * holds flags to specify a handle or name for the file or
+ * directory to rename.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackRenamePayloadV3(HgfsRequestRenameV3 *requestV3, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ char **cpOldName, // OUT: rename src
+ size_t *cpOldNameLen, // OUT: rename src size
+ char **cpNewName, // OUT: rename dst
+ size_t *cpNewNameLen, // OUT: rename dst size
+ HgfsRenameHint *hints, // OUT: rename hints
+ HgfsHandle *srcFile, // OUT: src file handle
+ HgfsHandle *targetFile, // OUT: target file handle
+ uint32 *oldCaseFlags, // OUT: source case flags
+ uint32 *newCaseFlags) // OUT: dest. case flags
+{
+ size_t extra;
+ HgfsFileNameV3 *newName;
+ Bool useHandle;
+
+ LOG(4, ("%s: HGFS_OP_RENAME_V3\n", __FUNCTION__));
+
+ if (payloadSize < sizeof *requestV3) {
+ return FALSE;
+ }
+ extra = payloadSize - sizeof *requestV3;
+
+ *hints = requestV3->hints;
+
+ /*
+ * Get the old and new filenames from the request.
+ *
+ * Getting the new filename is somewhat inconvenient, because we
+ * don't know where request->newName actually starts, thanks to the
+ * fact that request->oldName is of variable length. We get around
+ * this by using an HgfsFileName*, assigning it to the correct address
+ * just after request->oldName ends, and using that to access the
+ * new name.
+ */
+
+ /*
+ * If we've been asked to reuse a handle, we don't need to look at, let
+ * alone test the filename or its length. This applies to the source
+ * and the target.
+ */
+ if (!HgfsUnpackFileNameV3(&requestV3->oldName,
+ extra,
+ &useHandle,
+ cpOldName,
+ cpOldNameLen,
+ srcFile,
+ oldCaseFlags)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ if (useHandle) {
+ *hints |= HGFS_RENAME_HINT_USE_SRCFILE_DESC;
+ newName = &requestV3->newName;
+ } else {
+ newName = (HgfsFileNameV3 *)(requestV3->oldName.name + 1 + *cpOldNameLen);
+ extra -= *cpOldNameLen;
+ }
+ if (!HgfsUnpackFileNameV3(newName,
+ extra,
+ &useHandle,
+ cpNewName,
+ cpNewNameLen,
+ targetFile,
+ newCaseFlags)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ if (useHandle) {
+ *hints |= HGFS_RENAME_HINT_USE_TARGETFILE_DESC;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackRenamePayloadV2 --
+ *
+ * Unpack hgfs rename request V2 payload and initialize a corresponding
+ * HgfsHandle or file name to tell us which to delete. Hints
+ * holds flags to specify a handle or name for the file or
+ * directory to rename.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackRenamePayloadV2(HgfsRequestRenameV2 *requestV2, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ char **cpOldName, // OUT: rename src
+ size_t *cpOldNameLen, // OUT: rename src size
+ char **cpNewName, // OUT: rename dst
+ size_t *cpNewNameLen, // OUT: rename dst size
+ HgfsRenameHint *hints, // OUT: rename hints
+ HgfsHandle *srcFile, // OUT: src file handle
+ HgfsHandle *targetFile) // OUT: target file handle
+{
+ HgfsFileName *newName;
+ size_t extra;
+
+ /* Enforced by the dispatch function. */
+ if (payloadSize < sizeof *requestV2) {
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+ }
+ extra = payloadSize - sizeof *requestV2;
+
+ *hints = requestV2->hints;
+
+ /*
+ * If we've been asked to reuse a handle, we don't need to look at, let
+ * alone test the filename or its length. This applies to the source
+ * and the target.
+ */
+
+ if (*hints & HGFS_RENAME_HINT_USE_SRCFILE_DESC) {
+ *srcFile = requestV2->srcFile;
+ *cpOldName = NULL;
+ *cpOldNameLen = 0;
+ } else {
+ if (!HgfsUnpackFileName(&requestV2->oldName,
+ extra,
+ cpOldName,
+ cpOldNameLen)) {
+ LOG(4, ("%s: Error decoding HGFS packet - not enough room for file name\n", __FUNCTION__));
+ return FALSE;
+ }
+ extra -= *cpOldNameLen;
+ }
+
+ if (*hints & HGFS_RENAME_HINT_USE_TARGETFILE_DESC) {
+ *targetFile = requestV2->targetFile;
+ *cpNewName = NULL;
+ *cpNewNameLen = 0;
+ } else {
+ newName = (HgfsFileName *)((char *)(&requestV2->oldName + 1)
+ + *cpOldNameLen);
+ if (!HgfsUnpackFileName(newName,
+ extra,
+ cpNewName,
+ cpNewNameLen)) {
+ LOG(4, ("%s: Error decoding HGFS packet - not enough room for file name\n", __FUNCTION__));
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackRenamePayloadV1 --
+ *
+ * Unpack hgfs rename request V1 payload and initialize a corresponding
+ * old and new file names.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackRenamePayloadV1(HgfsRequestRename *requestV1, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ char **cpOldName, // OUT: rename src
+ size_t *cpOldNameLen, // OUT: rename src size
+ char **cpNewName, // OUT: rename dst
+ size_t *cpNewNameLen) // OUT: rename dst size
+{
+ HgfsFileName *newName;
+ uint32 extra;
+
+ if (payloadSize < sizeof *requestV1) {
+ return FALSE;
+ }
+
+ extra = payloadSize - sizeof *requestV1;
+
+ if (!HgfsUnpackFileName(&requestV1->oldName,
+ extra,
+ cpOldName,
+ cpOldNameLen)) {
+ LOG(4, ("%s: Error decoding HGFS packet - not enough room for file name\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ extra -= requestV1->oldName.length;
+ newName = (HgfsFileName *)((char *)(&requestV1->oldName + 1)
+ + requestV1->oldName.length);
+
+ return HgfsUnpackFileName(newName, extra, cpNewName, cpNewNameLen);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackRenameRequest --
+ *
+ * Unpack hgfs rename request and initialize a corresponding
+ * HgfsHandle or file name to tell us which to rename. Hints
+ * holds flags to specify a handle or name for the file or
+ * directory to rename.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackRenameRequest(void const *packet, // IN: HGFS packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: requested operation
+ char **cpOldName, // OUT: rename src
+ size_t *cpOldNameLen, // OUT: rename src size
+ char **cpNewName, // OUT: rename dst
+ size_t *cpNewNameLen, // OUT: rename dst size
+ HgfsRenameHint *hints, // OUT: rename hints
+ HgfsHandle *srcFile, // OUT: src file handle
+ HgfsHandle *targetFile, // OUT: target file handle
+ uint32 *oldCaseFlags, // OUT: source case-sensitivity flags
+ uint32 *newCaseFlags) // OUT: dest. case-sensitivity flags
+{
+ ASSERT(packet);
+ ASSERT(cpOldName);
+ ASSERT(cpOldNameLen);
+ ASSERT(cpNewName);
+ ASSERT(cpNewNameLen);
+ ASSERT(srcFile);
+ ASSERT(targetFile);
+ ASSERT(hints);
+ ASSERT(oldCaseFlags);
+ ASSERT(newCaseFlags);
+
+ /* Default values for legacy requests. */
+ *oldCaseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+ *newCaseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+ *hints = 0;
+
+ switch (op) {
+ case HGFS_OP_RENAME_V3:
+ {
+ HgfsRequestRenameV3 *requestV3 = (HgfsRequestRenameV3 *)packet;
+
+ if (!HgfsUnpackRenamePayloadV3(requestV3,
+ packetSize,
+ cpOldName,
+ cpOldNameLen,
+ cpNewName,
+ cpNewNameLen,
+ hints,
+ srcFile,
+ targetFile,
+ oldCaseFlags,
+ newCaseFlags)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ case HGFS_OP_RENAME_V2:
+ {
+ HgfsRequestRenameV2 *requestV2 = (HgfsRequestRenameV2 *)packet;
+
+ if (!HgfsUnpackRenamePayloadV2(requestV2,
+ packetSize,
+ cpOldName,
+ cpOldNameLen,
+ cpNewName,
+ cpNewNameLen,
+ hints,
+ srcFile,
+ targetFile)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+
+ case HGFS_OP_RENAME:
+ {
+ HgfsRequestRename *requestV1 = (HgfsRequestRename *)packet;
+
+ if (!HgfsUnpackRenamePayloadV1(requestV1,
+ packetSize,
+ cpOldName,
+ cpOldNameLen,
+ cpNewName,
+ cpNewNameLen)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+
+ default:
+ LOG(4, ("%s: Invalid opcode %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackRenameReply --
+ *
+ * Pack hgfs rename reply.
+ * Since the structure of the rename reply packet hasn't changed in
+ * version 2 of the protocol, HgfsReplyRenameV2 is identical to
+ * HgfsReplyRename. So use HgfsReplyRename type to access packetIn to
+ * keep the code simple.
+ *
+ * Results:
+ * TRUE if valid op and reply set, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackRenameReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: requested operation
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ HGFS_ASSERT_PACK_PARAMS;
+
+ *payloadSize = 0;
+
+ switch (op) {
+ case HGFS_OP_RENAME_V3: {
+ HgfsReplyRenameV3 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_RENAME_V2:
+ case HGFS_OP_RENAME: {
+ HgfsReplyRename *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ default:
+ LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, op));
+ result = FALSE;
+ NOT_REACHED();
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackGetattrPayloadV3 --
+ *
+ * Unpack hgfs get attr request V3 payload and initialize a corresponding
+ * HgfsHandle or file name to tell us which file to get attributes. Hints
+ * holds flags to specify a handle or name for the file or
+ * directory to get attributes.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackGetattrPayloadV3(HgfsRequestGetattrV3 *requestV3,// IN: request payload
+ size_t payloadSize, // IN: payload size
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize, // OUT: cpName size
+ HgfsAttrHint *hints, // OUT: getattr hints
+ HgfsHandle *file, // OUT: file handle
+ uint32 *caseFlags) // OUT: case-sensitivity flags
+{
+ Bool result;
+ Bool useHandle;
+
+ if (payloadSize < sizeof *requestV3) {
+ return FALSE;
+ }
+
+ *hints = requestV3->hints;
+
+ result = HgfsUnpackFileNameV3(&requestV3->fileName,
+ payloadSize - sizeof *requestV3,
+ &useHandle,
+ cpName,
+ cpNameSize,
+ file,
+ caseFlags);
+ if (useHandle) {
+ *hints |= HGFS_ATTR_HINT_USE_FILE_DESC;
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackGetattrPayloadV2 --
+ *
+ * Unpack hgfs Getattr request V2 payload and initialize a corresponding
+ * HgfsHandle or file name to tell us which to get attributes. Hints
+ * holds flags to specify a handle or name for the file or
+ * directory to get attributes.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackGetattrPayloadV2(HgfsRequestGetattrV2 *requestV2,// IN: request payload
+ size_t payloadSize, // IN: payload size
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize, // OUT: cpName size
+ HgfsAttrHint *hints, // OUT: delete hints
+ HgfsHandle *file) // OUT: file handle
+{
+ Bool result = TRUE;
+
+ if (payloadSize < sizeof *requestV2) {
+ return FALSE;
+ }
+
+
+ *file = HGFS_INVALID_HANDLE;
+ *hints = requestV2->hints;
+
+ /*
+ * If we've been asked to reuse a handle, we don't need to look at, let
+ * alone test the filename or its length.
+ */
+
+ if (requestV2->hints & HGFS_ATTR_HINT_USE_FILE_DESC) {
+ *file = requestV2->file;
+ *cpName = NULL;
+ *cpNameSize = 0;
+ } else {
+ result = HgfsUnpackFileName(&requestV2->fileName,
+ payloadSize - sizeof *requestV2,
+ cpName,
+ cpNameSize);
+ }
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackGetattrPayloadV1 --
+ *
+ * Unpack hgfs getattr request V1 payload and initialize a corresponding
+ * file name to tell us which to get attributes.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackGetattrPayloadV1(HgfsRequestGetattr *requestV1, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize) // OUT: cpName size
+{
+ return HgfsUnpackFileName(&requestV1->fileName,
+ payloadSize - sizeof *requestV1,
+ cpName,
+ cpNameSize);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackAttrV2 --
+ *
+ * Packs attr version 2 reply structure.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsPackAttrV2(HgfsFileAttrInfo *attr, // IN: attr stucture
+ HgfsAttrV2 *attr2) // OUT: attr in payload
+{
+ attr2->mask = attr->mask;
+ attr2->type = attr->type;
+ attr2->size = attr->size;
+ attr2->creationTime = attr->creationTime;
+ attr2->accessTime = attr->accessTime;
+ attr2->writeTime = attr->writeTime;
+ attr2->attrChangeTime = attr->attrChangeTime;
+ attr2->specialPerms = attr->specialPerms;
+ attr2->ownerPerms = attr->ownerPerms;
+ attr2->groupPerms = attr->groupPerms;
+ attr2->otherPerms = attr->otherPerms;
+ attr2->flags = attr->flags;
+ attr2->allocationSize = attr->allocationSize;
+ attr2->userId = attr->userId;
+ attr2->groupId = attr->groupId;
+ attr2->hostFileId = attr->hostFileId;
+ attr2->volumeId = attr->volumeId;
+ attr2->effectivePerms = attr->effectivePerms;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackAttrV2 --
+ *
+ * Unpacks attr version 2 reply structure.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsUnpackAttrV2(HgfsAttrV2 *attr2, // IN: attr in payload
+ HgfsFileAttrInfo *attr) // OUT: attr stucture
+{
+ attr->mask = attr2->mask;
+ attr->type = attr2->type;
+ attr->size = attr2->size;
+ attr->creationTime = attr2->creationTime;
+ attr->accessTime = attr2->accessTime;
+ attr->writeTime = attr2->writeTime;
+ attr->attrChangeTime = attr2->attrChangeTime;
+ attr->specialPerms = attr2->specialPerms;
+ attr->ownerPerms = attr2->ownerPerms;
+ attr->groupPerms = attr2->groupPerms;
+ attr->otherPerms = attr2->otherPerms;
+ attr->flags = attr2->flags;
+ attr->allocationSize = attr2->allocationSize;
+ attr->userId = attr2->userId;
+ attr->groupId = attr2->groupId;
+ attr->hostFileId = attr2->hostFileId;
+ attr->volumeId = attr2->volumeId;
+ attr->effectivePerms = attr2->effectivePerms;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsInitFileAttr --
+ *
+ * Initializes HgfsFileAttrInfo structure.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsInitFileAttr(HgfsOp op, // IN: request type
+ HgfsFileAttrInfo *attr) // OUT: attr stucture
+{
+ /* Initialize all fields with 0. */
+ memset(attr, 0, sizeof *attr);
+
+ /* Explicitly initialize fields which need it. */
+ attr->requestType = op;
+ attr->mask = HGFS_ATTR_VALID_NONE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackGetattrReplyPayloadV3 --
+ *
+ * Packs Getattr V3 reply payload.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsPackGetattrReplyPayloadV3(HgfsFileAttrInfo *attr, // IN: attr stucture
+ const char *utf8TargetName, // IN: optional target name
+ uint32 utf8TargetNameLen, // IN: file name length
+ HgfsReplyGetattrV3 *reply) // OUT: payload
+{
+ LOG(4, ("%s: attr type: %u\n", __FUNCTION__, reply->attr.type));
+
+ HgfsPackAttrV2(attr, &reply->attr);
+ reply->reserved = 0;
+
+ if (utf8TargetName) {
+ memcpy(reply->symlinkTarget.name, utf8TargetName, utf8TargetNameLen);
+ CPNameLite_ConvertTo(reply->symlinkTarget.name, utf8TargetNameLen,
+ DIRSEPC);
+ } else {
+ ASSERT(utf8TargetNameLen == 0);
+ }
+ reply->symlinkTarget.length = utf8TargetNameLen;
+ reply->symlinkTarget.name[utf8TargetNameLen] = '\0';
+ reply->symlinkTarget.flags = 0;
+ reply->symlinkTarget.fid = 0;
+ reply->symlinkTarget.caseType = HGFS_FILE_NAME_DEFAULT_CASE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackGetattrReplyPayloadV2 --
+ *
+ * Packs rename reply payload V2 requests.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsPackGetattrReplyPayloadV2(HgfsFileAttrInfo *attr, // IN: attr stucture
+ const char *utf8TargetName, // IN: optional target name
+ uint32 utf8TargetNameLen, // IN: file name length
+ HgfsReplyGetattrV2 *reply) // OUT: payload
+{
+ HgfsPackAttrV2(attr, &reply->attr);
+
+ if (utf8TargetName) {
+ memcpy(reply->symlinkTarget.name, utf8TargetName, utf8TargetNameLen);
+ CPNameLite_ConvertTo(reply->symlinkTarget.name, utf8TargetNameLen,
+ DIRSEPC);
+ } else {
+ ASSERT(utf8TargetNameLen == 0);
+ }
+ reply->symlinkTarget.length = utf8TargetNameLen;
+ reply->symlinkTarget.name[utf8TargetNameLen] = '\0';
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackGetattrReplyPayloadV1 --
+ *
+ * Packs rename reply payload for V1 requests.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsPackGetattrReplyPayloadV1(HgfsFileAttrInfo *attr, // IN: attr stucture
+ HgfsReplyGetattr *reply) // OUT: reply info
+{
+ /* In GetattrV1, symlinks are treated as regular files. */
+ if (attr->type == HGFS_FILE_TYPE_SYMLINK) {
+ reply->attr.type = HGFS_FILE_TYPE_REGULAR;
+ } else {
+ reply->attr.type = attr->type;
+ }
+
+ reply->attr.size = attr->size;
+ reply->attr.creationTime = attr->creationTime;
+ reply->attr.accessTime = attr->accessTime;
+ reply->attr.writeTime = attr->writeTime;
+ reply->attr.attrChangeTime = attr->attrChangeTime;
+ reply->attr.permissions = attr->ownerPerms;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackGetattrRequest --
+ *
+ * Unpack hgfs getattr request and initialize a corresponding
+ * HgfsFileAttrInfo structure that is used to pass around getattr request
+ * information.
+ *
+ * Since the structure of the get attributes request packet hasn't changed
+ * in version 2 of the protocol, HgfsRequestGetattrV2 is identical to
+ * HgfsRequestGetattr. So use HgfsRequestGetattr type to access packetIn to
+ * keep the code simple.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackGetattrRequest(void const *packet, // IN: HGFS packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN request type
+ HgfsFileAttrInfo *attrInfo, // IN/OUT: getattr info
+ HgfsAttrHint *hints, // OUT: getattr hints
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize, // OUT: cpName size
+ HgfsHandle *file, // OUT: file handle
+ uint32 *caseType) // OUT: case-sensitivity flags
+{
+ ASSERT(packet);
+ ASSERT(attrInfo);
+ ASSERT(cpName);
+ ASSERT(cpNameSize);
+ ASSERT(file);
+ ASSERT(caseType);
+
+ HgfsInitFileAttr(op, attrInfo);
+
+ /* Default values for legacy requests. */
+ *caseType = HGFS_FILE_NAME_DEFAULT_CASE;
+ *hints = 0;
+ *file = HGFS_INVALID_HANDLE;
+
+ switch (op) {
+ case HGFS_OP_GETATTR_V3: {
+ HgfsRequestGetattrV3 *requestV3 = (HgfsRequestGetattrV3 *)packet;
+
+ if (!HgfsUnpackGetattrPayloadV3(requestV3,
+ packetSize,
+ cpName,
+ cpNameSize,
+ hints,
+ file,
+ caseType)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ LOG(4, ("%s: HGFS_OP_GETATTR_V3: %u\n", __FUNCTION__, *caseType));
+ break;
+ }
+
+ case HGFS_OP_GETATTR_V2: {
+ HgfsRequestGetattrV2 *requestV2 = (HgfsRequestGetattrV2 *)packet;
+
+ if (!HgfsUnpackGetattrPayloadV2(requestV2,
+ packetSize,
+ cpName,
+ cpNameSize,
+ hints,
+ file)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+
+ case HGFS_OP_GETATTR: {
+ HgfsRequestGetattr *requestV1 = (HgfsRequestGetattr *)packet;
+
+ if (!HgfsUnpackGetattrPayloadV1(requestV1, packetSize, cpName, cpNameSize)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackGetattrReply --
+ *
+ * Pack hgfs getattr reply to the HgfsReplyGetattr structure.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackGetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsFileAttrInfo *attr, // IN: attr stucture
+ const char *utf8TargetName, // IN: optional target name
+ uint32 utf8TargetNameLen, // IN: file name length
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ HGFS_ASSERT_PACK_PARAMS;
+
+ *payloadSize = 0;
+
+ switch (attr->requestType) {
+ case HGFS_OP_GETATTR_V3: {
+ HgfsReplyGetattrV3 *reply;
+
+ *payloadSize = sizeof *reply + utf8TargetNameLen;
+ result = HgfsAllocInitReply(packet, packetHeader, *payloadSize,
+ (void **)&reply, session);
+ if (result) {
+ HgfsPackGetattrReplyPayloadV3(attr, utf8TargetName, utf8TargetNameLen, reply);
+ }
+ break;
+ }
+
+ case HGFS_OP_GETATTR_V2: {
+ HgfsReplyGetattrV2 *reply;
+ *payloadSize = sizeof *reply + utf8TargetNameLen;
+
+ result = HgfsAllocInitReply(packet, packetHeader, *payloadSize,
+ (void **)&reply, session);
+ if (result) {
+ HgfsPackGetattrReplyPayloadV2(attr,
+ utf8TargetName,
+ utf8TargetNameLen,
+ reply);
+ }
+ break;
+ }
+
+ case HGFS_OP_GETATTR: {
+ HgfsReplyGetattr *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ HgfsPackGetattrReplyPayloadV1(attr, reply);
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+
+ default:
+ LOG(4, ("%s: Invalid GetAttr op.\n", __FUNCTION__));
+ NOT_REACHED();
+
+ result = FALSE;
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackSearchReadReplyPayloadV3 --
+ *
+ * Packs SearchRead V3 reply payload.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsPackSearchReadReplyPayloadV3(HgfsFileAttrInfo *attr, // IN: attr stucture
+ const char *utf8Name, // IN: file name
+ uint32 utf8NameLen, // IN: file name length
+ HgfsReplySearchReadV3 *reply) // OUT: payload
+{
+ HgfsDirEntry *dirent = (HgfsDirEntry *)reply->payload;
+
+ reply->count = 1;
+ reply->reserved = 0;
+
+ dirent->fileName.length = (uint32)utf8NameLen;
+ dirent->fileName.flags = 0;
+ dirent->fileName.fid = 0;
+ dirent->fileName.caseType = HGFS_FILE_NAME_DEFAULT_CASE;
+ dirent->nextEntry = 0;
+
+ if (utf8NameLen != 0) {
+ memcpy(dirent->fileName.name, utf8Name, utf8NameLen);
+ dirent->fileName.name[utf8NameLen] = 0;
+
+ HgfsPackAttrV2(attr, &dirent->attr);
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackSearchReadReplyPayloadV2 --
+ *
+ * Packs SearchRead V2 reply payload.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsPackSearchReadReplyPayloadV2(HgfsFileAttrInfo *attr, // IN: attr stucture
+ const char *utf8Name, // IN: file name
+ uint32 utf8NameLen, // IN: file name length
+ HgfsReplySearchReadV2 *reply) // OUT: payload
+{
+ reply->fileName.length = (uint32)utf8NameLen;
+
+ if (utf8NameLen != 0) {
+ memcpy(reply->fileName.name, utf8Name, utf8NameLen);
+ reply->fileName.name[utf8NameLen] = 0;
+ HgfsPackAttrV2(attr, &reply->attr);
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackSearchReadReplyPayloadV1 --
+ *
+ * Packs SearchRead V1 reply payload.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsPackSearchReadReplyPayloadV1(HgfsFileAttrInfo *attr, // IN: attr stucture
+ const char *utf8Name, // IN: file name
+ uint32 utf8NameLen, // IN: file name length
+ HgfsReplySearchRead *reply) // OUT: payload
+{
+ reply->fileName.length = (uint32)utf8NameLen;
+
+ if (utf8NameLen != 0) {
+ memcpy(reply->fileName.name, utf8Name, utf8NameLen);
+ reply->fileName.name[utf8NameLen] = 0;
+
+ /* In SearchReadV1, symlinks are treated as regular files. */
+ if (attr->type == HGFS_FILE_TYPE_SYMLINK) {
+ reply->attr.type = HGFS_FILE_TYPE_REGULAR;
+ } else {
+ reply->attr.type = attr->type;
+ }
+ reply->attr.size = attr->size;
+ reply->attr.creationTime = attr->creationTime;
+ reply->attr.accessTime = attr->accessTime;
+ reply->attr.writeTime = attr->writeTime;
+ reply->attr.attrChangeTime = attr->attrChangeTime;
+ reply->attr.permissions = attr->ownerPerms;
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSearchReadRequest --
+ *
+ * Unpack hgfs search read request and initialize a corresponding
+ * HgfsFileAttrInfo structure that is used to pass around attribute
+ * information.
+ *
+ * Since the structure of the search read request packet hasn't changed in
+ * version 2 of the protocol, HgfsRequestSearchReadV2 is identical to
+ * HgfsRequestSearchRead. So use HgfsRequestSearchRead type to access
+ * packetIn to keep the code simple.
+ *
+ * Results:
+ * Always TRUE.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSearchReadRequest(const void *packet, // IN: request packet
+ size_t packetSize, // IN: packet size
+ HgfsOp op, // IN: reqest type
+ HgfsFileAttrInfo *attr, // OUT: unpacked attr struct
+ HgfsHandle *hgfsSearchHandle, // OUT: hgfs search handle
+ uint32 *offset) // OUT: entry offset
+{
+ ASSERT(packet);
+ ASSERT(attr);
+ ASSERT(hgfsSearchHandle);
+ ASSERT(offset);
+
+ HgfsInitFileAttr(op, attr);
+
+
+ if (op == HGFS_OP_SEARCH_READ_V3) {
+ HgfsRequestSearchReadV3 *request = (HgfsRequestSearchReadV3 *)packet;
+
+ /* Enforced by the dispatch function. */
+ ASSERT(packetSize >= sizeof *request);
+
+ *hgfsSearchHandle = request->search;
+ *offset = request->offset;
+
+ LOG(4, ("%s: HGFS_OP_SEARCH_READ_V3\n", __FUNCTION__));
+ } else {
+ HgfsRequestSearchRead *request = (HgfsRequestSearchRead *)packet;
+
+ /* Enforced by the dispatch function. */
+ ASSERT(packetSize >= sizeof *request);
+
+ *hgfsSearchHandle = request->search;
+ *offset = request->offset;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackSearchReadReply --
+ *
+ * Pack hgfs search read reply to the HgfsReplySearchRead{V2} structure.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackSearchReadReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ const char *utf8Name, // IN: file name
+ size_t utf8NameLen, // IN: file name length
+ HgfsFileAttrInfo *attr, // IN: file attr struct
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ switch (attr->requestType) {
+ case HGFS_OP_SEARCH_READ_V3: {
+ HgfsReplySearchReadV3 *reply;
+ *payloadSize = sizeof *reply + utf8NameLen + sizeof(HgfsDirEntry);
+
+ result = HgfsAllocInitReply(packet, packetHeader, *payloadSize,
+ (void **)&reply, session);
+ if (result) {
+ HgfsPackSearchReadReplyPayloadV3(attr, utf8Name, utf8NameLen, reply);
+ }
+ break;
+ }
+
+ case HGFS_OP_SEARCH_READ_V2: {
+ HgfsReplySearchReadV2 *reply;
+ *payloadSize = sizeof *reply + utf8NameLen;
+
+ result = HgfsAllocInitReply(packet, packetHeader, *payloadSize,
+ (void **)&reply, session);
+ if (result) {
+ HgfsPackSearchReadReplyPayloadV2(attr,
+ utf8Name,
+ utf8NameLen,
+ reply);
+ }
+ break;
+ }
+
+ case HGFS_OP_SEARCH_READ: {
+ HgfsReplySearchRead *reply;
+ *payloadSize = sizeof *reply + utf8NameLen;
+
+ result = HgfsAllocInitReply(packet, packetHeader, *payloadSize,
+ (void **)&reply, session);
+ if (result) {
+ HgfsPackSearchReadReplyPayloadV1(attr, utf8Name, utf8NameLen, reply);
+ }
+ break;
+ }
+
+ default: {
+ LOG(4, ("%s: Invalid SearchRead Op.", __FUNCTION__));
+ NOT_REACHED();
+ result = FALSE;
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSetattrPayloadV3 --
+ *
+ * Unpack hgfs set attr request V3 payload and initialize a corresponding
+ * HgfsHandle or file name to tell us which file to set attributes. Hints
+ * holds flags to specify a handle or name for the file or
+ * directory to set attributes.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSetattrPayloadV3(HgfsRequestSetattrV3 *requestV3,// IN: request payload
+ size_t payloadSize, // IN: payload size
+ HgfsFileAttrInfo *attr, // OUT: setattr info
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize, // OUT: cpName size
+ HgfsAttrHint *hints, // OUT: getattr hints
+ HgfsHandle *file, // OUT: file handle
+ uint32 *caseFlags) // OUT: case-sensitivity flags
+{
+ Bool result;
+ Bool useHandle;
+
+ if (payloadSize < sizeof *requestV3) {
+ return FALSE;
+ }
+
+ *hints = requestV3->hints;
+
+ HgfsUnpackAttrV2(&requestV3->attr, attr);
+
+ result = HgfsUnpackFileNameV3(&requestV3->fileName,
+ payloadSize - sizeof *requestV3,
+ &useHandle,
+ cpName,
+ cpNameSize,
+ file,
+ caseFlags);
+ if (useHandle) {
+ *hints |= HGFS_ATTR_HINT_USE_FILE_DESC;
+ }
+
+ LOG(4, ("%s: unpacking HGFS_OP_SETATTR_V3, %u\n", __FUNCTION__,
+ *caseFlags));
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSetattrPayloadV2 --
+ *
+ * Unpack hgfs Setattr request V2 payload and initialize a corresponding
+ * HgfsHandle or file name to tell us which to set attributes. Hints
+ * holds flags to specify a handle or name for the file or
+ * directory to set attributes.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSetattrPayloadV2(HgfsRequestSetattrV2 *requestV2,// IN: request payload
+ size_t payloadSize, // IN: payload size
+ HgfsFileAttrInfo *attr, // OUT: setattr info
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize, // OUT: cpName size
+ HgfsAttrHint *hints, // OUT: delete hints
+ HgfsHandle *file) // OUT: file handle
+{
+ Bool result = TRUE;
+
+ /* Enforced by the dispatch function. */
+ if (payloadSize < sizeof *requestV2) {
+ return FALSE;
+ }
+
+ LOG(4, ("%s: unpacking HGFS_OP_SETATTR_V2\n", __FUNCTION__));
+
+ *file = HGFS_INVALID_HANDLE;
+ *hints = requestV2->hints;
+
+ HgfsUnpackAttrV2(&requestV2->attr, attr);
+
+ if (requestV2->hints & HGFS_ATTR_HINT_USE_FILE_DESC) {
+ *file = requestV2->file;
+ *cpName = NULL;
+ *cpNameSize = 0;
+ } else {
+ result = HgfsUnpackFileName(&requestV2->fileName,
+ payloadSize - sizeof *requestV2,
+ cpName,
+ cpNameSize);
+ }
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSetattrPayloadV1 --
+ *
+ * Unpack hgfs setattr request V1 payload and initialize a corresponding
+ * file name to tell us which to set attributes.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSetattrPayloadV1(HgfsRequestSetattr *requestV1, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ HgfsFileAttrInfo *attr, // OUT: setattr info
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize, // OUT: cpName size
+ HgfsAttrHint *hints) // OUT: setattr hints
+{
+ LOG(4, ("%s: unpacking HGFS_OP_SETATTR\n", __FUNCTION__));
+
+ attr->mask = 0;
+ attr->mask |= requestV1->update & HGFS_ATTR_SIZE ? HGFS_ATTR_VALID_SIZE : 0;
+ attr->mask |= requestV1->update & HGFS_ATTR_CREATE_TIME ?
+ HGFS_ATTR_VALID_CREATE_TIME : 0;
+ attr->mask |= requestV1->update & HGFS_ATTR_ACCESS_TIME ?
+ HGFS_ATTR_VALID_ACCESS_TIME : 0;
+ attr->mask |= requestV1->update & HGFS_ATTR_WRITE_TIME ?
+ HGFS_ATTR_VALID_WRITE_TIME : 0;
+ attr->mask |= requestV1->update & HGFS_ATTR_CHANGE_TIME ?
+ HGFS_ATTR_VALID_CHANGE_TIME : 0;
+ attr->mask |= requestV1->update & HGFS_ATTR_PERMISSIONS ?
+ HGFS_ATTR_VALID_OWNER_PERMS : 0;
+ *hints |= requestV1->update & HGFS_ATTR_ACCESS_TIME_SET ?
+ HGFS_ATTR_HINT_SET_ACCESS_TIME : 0;
+ *hints |= requestV1->update & HGFS_ATTR_WRITE_TIME_SET ?
+ HGFS_ATTR_HINT_SET_WRITE_TIME : 0;
+
+ attr->type = requestV1->attr.type;
+ attr->size = requestV1->attr.size;
+ attr->creationTime = requestV1->attr.creationTime;
+ attr->accessTime = requestV1->attr.accessTime;
+ attr->writeTime = requestV1->attr.writeTime;
+ attr->attrChangeTime = requestV1->attr.attrChangeTime;
+ attr->ownerPerms = requestV1->attr.permissions;
+ return HgfsUnpackFileName(&requestV1->fileName,
+ payloadSize - sizeof *requestV1,
+ cpName,
+ cpNameSize);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSetattrRequest --
+ *
+ * Unpack hgfs setattr request and initialize a corresponding
+ * HgfsFileAttrInfo structure that is used to pass around setattr request
+ * information.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSetattrRequest(void const *packet, // IN: HGFS packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ HgfsFileAttrInfo *attr, // OUT: setattr info
+ HgfsAttrHint *hints, // OUT: setattr hints
+ char **cpName, // OUT: cpName
+ size_t *cpNameSize, // OUT: cpName size
+ HgfsHandle *file, // OUT: server file ID
+ uint32 *caseType) // OUT: case-sensitivity flags
+{
+ ASSERT(packet);
+ ASSERT(attr);
+ ASSERT(cpName);
+ ASSERT(cpNameSize);
+ ASSERT(file);
+ ASSERT(caseType);
+
+ attr->requestType = op;
+
+ /* Default values for legacy requests. */
+ *caseType = HGFS_FILE_NAME_DEFAULT_CASE;
+ *hints = 0;
+ *file = HGFS_INVALID_HANDLE;
+
+ switch (op) {
+ case HGFS_OP_SETATTR_V3:
+ {
+ HgfsRequestSetattrV3 *requestV3 = (HgfsRequestSetattrV3 *)packet;
+ if (!HgfsUnpackSetattrPayloadV3(requestV3,
+ packetSize,
+ attr,
+ cpName,
+ cpNameSize,
+ hints,
+ file,
+ caseType)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+
+ case HGFS_OP_SETATTR_V2:
+ {
+ HgfsRequestSetattrV2 *requestV2 = (HgfsRequestSetattrV2 *)packet;
+ if (!HgfsUnpackSetattrPayloadV2(requestV2,
+ packetSize,
+ attr,
+ cpName,
+ cpNameSize,
+ hints,
+ file)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ case HGFS_OP_SETATTR:
+ {
+ HgfsRequestSetattr *requestV1 = (HgfsRequestSetattr *)packet;
+ if (!HgfsUnpackSetattrPayloadV1(requestV1,
+ packetSize,
+ attr,
+ cpName,
+ cpNameSize,
+ hints)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ default:
+ LOG(4, ("%s: Incorrect opcode %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackSetattrReply --
+ *
+ * Pack hgfs setattr reply.
+ * Since the structure of the set attributes reply packet hasn't changed in
+ * version 2 of the protocol, HgfsReplySetattrV2 is identical to
+ * HgfsReplySetattr. So use HgfsReplySetattr type to access packetIn to
+ * keep the code simple.
+ *
+ * Results:
+ * TRUE if valid op and reply set, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackSetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ *payloadSize = 0;
+
+ switch (op) {
+ case HGFS_OP_SETATTR_V3: {
+ HgfsReplySetattrV3 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_SETATTR_V2:
+ case HGFS_OP_SETATTR: {
+ HgfsReplySetattr *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ default:
+ result = FALSE;
+ LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackCreateDirPayloadV3 --
+ *
+ * Unpack hgfs create directory request V3 payload and initialize a corresponding
+ * file name to tell us which directory to create.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackCreateDirPayloadV3(HgfsRequestCreateDirV3 *requestV3, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ HgfsCreateDirInfo *info) // IN/OUT: info struct
+{
+ /*
+ * The request file name length is user-provided, so this test must be
+ * carefully written to prevent wraparounds.
+ */
+
+ LOG(4, ("%s: HGFS_OP_CREATE_DIR_V3\n", __FUNCTION__));
+ ASSERT(payloadSize >= sizeof *requestV3);
+ if (requestV3->fileName.length > payloadSize - sizeof *requestV3) {
+ /* The input packet is smaller than the request. */
+ return FALSE;
+ }
+ if (!(requestV3->mask & HGFS_CREATE_DIR_VALID_FILE_NAME)) {
+ /* We do not support requests without a valid file name. */
+ LOG(4, ("%s: Incorrect mask %x\n", __FUNCTION__, (uint32)requestV3->mask));
+ return FALSE;
+ }
+
+ /*
+ * Copy all the fields into our carrier struct. Some will probably be
+ * garbage, but it's simpler to copy everything now and check the
+ * valid bits before reading later.
+ */
+
+ info->mask = requestV3->mask;
+ info->cpName = requestV3->fileName.name;
+ info->cpNameSize = requestV3->fileName.length;
+ info->caseFlags = requestV3->fileName.caseType;
+ info->specialPerms = requestV3->specialPerms;
+ info->fileAttr = requestV3->fileAttr;
+ info->ownerPerms = requestV3->ownerPerms;
+ info->groupPerms = requestV3->groupPerms;
+ info->otherPerms = requestV3->otherPerms;
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackCreateDirPayloadV2 --
+ *
+ * Unpack hgfs create directory request V2 payload and initialize a corresponding
+ * file name to tell us which directory to create.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackCreateDirPayloadV2(HgfsRequestCreateDirV2 *requestV2, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ HgfsCreateDirInfo *info) // IN/OUT: info struct
+{
+ /*
+ * The request file name length is user-provided, so this test must be
+ * carefully written to prevent wraparounds.
+ */
+
+ LOG(4, ("%s: HGFS_OP_CREATE_DIR_V2\n", __FUNCTION__));
+ ASSERT(payloadSize >= sizeof *requestV2);
+ if (requestV2->fileName.length > payloadSize - sizeof *requestV2) {
+ /* The input packet is smaller than the request. */
+ return FALSE;
+ }
+ if (!(requestV2->mask & HGFS_CREATE_DIR_VALID_FILE_NAME)) {
+ /* We do not support requests without a valid file name. */
+ LOG(4, ("%s: Incorrect mask %x\n", __FUNCTION__, (uint32)requestV2->mask));
+ return FALSE;
+ }
+
+ /*
+ * Copy all the fields into our carrier struct. Some will probably be
+ * garbage, but it's simpler to copy everything now and check the
+ * valid bits before reading later.
+ */
+
+ info->mask = requestV2->mask;
+ info->cpName = requestV2->fileName.name;
+ info->cpNameSize = requestV2->fileName.length;
+ info->specialPerms = requestV2->specialPerms;
+ info->ownerPerms = requestV2->ownerPerms;
+ info->groupPerms = requestV2->groupPerms;
+ info->otherPerms = requestV2->otherPerms;
+ info->fileAttr = 0;
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackCreateDirPayloadV1 --
+ *
+ * Unpack hgfs create directory request V1 payload and initialize a corresponding
+ * file name to tell us which directory to create.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackCreateDirPayloadV1(HgfsRequestCreateDir *requestV1, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ HgfsCreateDirInfo *info) // IN/OUT: info struct
+{
+ /*
+ * The request file name length is user-provided, so this test must be
+ * carefully written to prevent wraparounds.
+ */
+
+ LOG(4, ("%s: HGFS_OP_CREATE_DIR_V1\n", __FUNCTION__));
+ ASSERT(payloadSize >= sizeof *requestV1);
+ if (requestV1->fileName.length > payloadSize - sizeof *requestV1) {
+ /* The input packet is smaller than the request. */
+ LOG(4, ("%s: HGFS packet too small for the file name\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ /* For CreateDirV1 requests, we know exactly what fields we expect. */
+ info->mask = HGFS_CREATE_DIR_VALID_OWNER_PERMS | HGFS_CREATE_DIR_VALID_FILE_NAME;
+ info->cpName = requestV1->fileName.name;
+ info->cpNameSize = requestV1->fileName.length;
+ info->ownerPerms = requestV1->permissions;
+ info->fileAttr = 0;
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackCreateDirRequest --
+ *
+ * Unpack hgfs CreateDir request and initialize a corresponding
+ * HgfsCreateDirInfo structure that is used to pass around CreateDir request
+ * information.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackCreateDirRequest(void const *packet, // IN: incoming packet
+ size_t packetSize, // IN: size of packet
+ HgfsOp op, // IN: request type
+ HgfsCreateDirInfo *info) // IN/OUT: info struct
+{
+ ASSERT(packet);
+ ASSERT(info);
+
+ info->requestType = op;
+ /* Default value for legacy requests. */
+ info->caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+
+ switch (op) {
+ case HGFS_OP_CREATE_DIR_V3:
+ {
+ HgfsRequestCreateDirV3 *requestV3 = (HgfsRequestCreateDirV3 *)packet;
+ if (!HgfsUnpackCreateDirPayloadV3(requestV3,
+ packetSize,
+ info)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+
+ case HGFS_OP_CREATE_DIR_V2:
+ {
+ HgfsRequestCreateDirV2 *requestV2 = (HgfsRequestCreateDirV2 *)packet;
+ if (!HgfsUnpackCreateDirPayloadV2(requestV2,
+ packetSize,
+ info)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ case HGFS_OP_CREATE_DIR:
+ {
+ HgfsRequestCreateDir *requestV1 = (HgfsRequestCreateDir *)packet;
+ if (!HgfsUnpackCreateDirPayloadV1(requestV1,
+ packetSize,
+ info)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ default:
+ LOG(4, ("%s: Incorrect opcode %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackCreateDirReply --
+ *
+ * Pack hgfs CreateDir reply.
+ *
+ * Results:
+ * TRUE if valid op and reply set, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackCreateDirReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ *payloadSize = 0;
+
+ switch (op) {
+ case HGFS_OP_CREATE_DIR_V3: {
+ HgfsReplyCreateDirV3 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_CREATE_DIR_V2: {
+ HgfsReplyCreateDirV2 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_CREATE_DIR: {
+ HgfsReplyCreateDir *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ default:
+ result = FALSE;
+ LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackWriteWin32StreamPayloadV3 --
+ *
+ * Unpack hgfs write stream request V3 payload and initialize a corresponding
+ * file name to tell us which directory to create.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackWriteWin32StreamPayloadV3(HgfsRequestWriteWin32StreamV3 *requestV3, // IN:
+ size_t payloadSize, // IN:
+ HgfsHandle *file, // OUT:
+ char **data, // OUT:
+ size_t *dataSize, // OUT:
+ Bool *doSecurity) // OUT:
+{
+ LOG(4, ("%s: HGFS_OP_WRITE_WIN32_STREAM_V3\n", __FUNCTION__));
+ if (payloadSize < sizeof *requestV3) {
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ if (payloadSize >= requestV3->requiredSize + sizeof *requestV3) {
+ *file = requestV3->file;
+ *data = requestV3->payload;
+ *dataSize = requestV3->requiredSize;
+ *doSecurity = (requestV3->flags & HGFS_WIN32_STREAM_IGNORE_SECURITY) == 0;
+ return TRUE;
+ }
+
+ LOG(4, ("%s: HGFS packet too small - user data do not fit\n", __FUNCTION__));
+ return FALSE;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackWriteWin32StreamRequest --
+ *
+ * Unpack hgfs SendFileUsingReader request. Returns file to write to, data
+ * and whether to restore the security stream.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackWriteWin32StreamRequest(void const *packet, // IN: incoming packet
+ size_t packetSize, // IN: size of packet
+ HgfsOp op, // IN: request type
+ HgfsHandle *file, // OUT: file to write to
+ char **data, // OUT: data to write
+ size_t *dataSize, // OUT: size of data
+ Bool *doSecurity) // OUT: restore sec.str.
+{
+ ASSERT(packet);
+ ASSERT(file);
+ ASSERT(data);
+ ASSERT(dataSize);
+ ASSERT(doSecurity);
+
+ if (op != HGFS_OP_WRITE_WIN32_STREAM_V3) {
+ /* The only supported version for the moment is V3. */
+ LOG(4, ("%s: Incorrect opcode %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ return FALSE;
+ }
+
+ return HgfsUnpackWriteWin32StreamPayloadV3((HgfsRequestWriteWin32StreamV3 *)packet,
+ packetSize,
+ file,
+ data,
+ dataSize,
+ doSecurity);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackWriteWin32StreamReply --
+ *
+ * Pack hgfs SendFileUsingReader reply.
+ * Returns the actual amount of data written in the reply.
+ *
+ * Results:
+ * TRUE if valid op and reply set, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackWriteWin32StreamReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ uint32 actualSize, // IN: amount written
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ HgfsReplyWriteWin32StreamV3 *reply;
+ Bool result;
+
+ *payloadSize = 0;
+
+ if (HGFS_OP_WRITE_WIN32_STREAM_V3 == op) {
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ reply->actualSize = actualSize;
+ *payloadSize = sizeof *reply;
+ }
+ } else {
+ LOG(4, ("%s: Incorrect opcode %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ result = FALSE;
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackReadPayload --
+ *
+ * Unpack hgfs read payload to get the file handle and file offset to read from and
+ * the length of data to read.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackReadPayload(HgfsRequestRead *request, // IN: payload
+ size_t payloadSize, // IN: payload size
+ HgfsHandle* file, // OUT: HGFS handle to close
+ uint64 *offset, // OUT: offset to read from
+ uint32 *length) // OUT: length of data to read
+{
+ LOG(4, ("%s: HGFS_OP_READ\n", __FUNCTION__));
+ if (payloadSize >= sizeof *request) {
+ *file = request->file;
+ *offset = request->offset;
+ *length = request->requiredSize;
+ return TRUE;
+ }
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackReadPayloadV3 --
+ *
+ * Unpack hgfs read payload V3 to get parameters needed to perform read.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackReadPayloadV3(HgfsRequestReadV3 *requestV3, // IN: payload
+ size_t payloadSize, // IN: payload size
+ HgfsHandle* file, // OUT: HGFS handle to close
+ uint64 *offset, // OUT: offset to read from
+ uint32 *length) // OUT: length of data to read
+{
+ LOG(4, ("%s: HGFS_OP_READ_V3\n", __FUNCTION__));
+ if (payloadSize >= sizeof *requestV3) {
+ *file = requestV3->file;
+ *offset = requestV3->offset;
+ *length = requestV3->requiredSize;
+ return TRUE;
+ }
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackReadRequest --
+ *
+ * Unpack hgfs read request.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackReadRequest(void const *packet, // IN: HGFS request
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ HgfsHandle *file, // OUT: Handle to close
+ uint64 *offset, // OUT: offset to read from
+ uint32 *length) // OUT: length of data to read
+{
+ Bool result;
+
+ ASSERT(packet);
+
+ switch (op) {
+ case HGFS_OP_READ_FAST_V4:
+ case HGFS_OP_READ_V3: {
+ HgfsRequestReadV3 *requestV3 = (HgfsRequestReadV3 *)packet;
+
+ result = HgfsUnpackReadPayloadV3(requestV3, packetSize, file, offset, length);
+ break;
+ }
+ case HGFS_OP_READ: {
+ HgfsRequestRead *requestV1 = (HgfsRequestRead *)packet;
+
+ result = HgfsUnpackReadPayload(requestV1, packetSize, file, offset, length);
+ break;
+ }
+ default:
+ NOT_REACHED();
+ result = FALSE;
+ }
+
+ if (!result) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackWritePayload --
+ *
+ * Unpack hgfs write payload to get the file handle, file offset, of data to write,
+ * write flags and pointer to the data to write.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackWritePayload(HgfsRequestWrite *request, // IN: request payload
+ size_t payloadSize, // IN: request payload size
+ HgfsHandle* file, // OUT: HGFS handle to write to
+ uint64 *offset, // OUT: offset to read from
+ uint32 *length, // OUT: length of data to write
+ HgfsWriteFlags *flags, // OUT: write flags
+ char **data) // OUT: data to be written
+{
+ LOG(4, ("%s: HGFS_OP_WRITE\n", __FUNCTION__));
+ if (payloadSize >= sizeof *request) {
+ if (sizeof *request + request->requiredSize - 1 <= payloadSize) {
+ *file = request->file;
+ *flags = request->flags;
+ *offset = request->offset;
+ *data = request->payload;
+ *length = request->requiredSize;
+ return TRUE;
+ }
+ }
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackWritePayloadV3 --
+ *
+ * Unpack hgfs write payload V3.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackWritePayloadV3(HgfsRequestWriteV3 *requestV3, // IN: payload
+ size_t payloadSize, // IN: request payload size
+ HgfsHandle* file, // OUT: HGFS handle write to
+ uint64 *offset, // OUT: offset to read from
+ uint32 *length, // OUT: length of data to write
+ HgfsWriteFlags *flags, // OUT: write flags
+ char **data) // OUT: data to be written
+{
+ LOG(4, ("%s: HGFS_OP_WRITE_V3\n", __FUNCTION__));
+ if (payloadSize >= sizeof *requestV3) {
+ if (sizeof *requestV3 + requestV3->requiredSize - 1 <= payloadSize) {
+ *file = requestV3->file;
+ *flags = requestV3->flags;
+ *offset = requestV3->offset;
+ *data = requestV3->payload;
+ *length = requestV3->requiredSize;
+ return TRUE;
+ }
+ }
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackWriteFastPayloadV4 --
+ *
+ * Unpack hgfs write fast payload V4.
+ * The only difference from V3 payload is that data to write are
+ * provided in the payload but located in a separate buffer.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackWriteFastPayloadV4(HgfsRequestWriteV3 *requestV3, // IN: payload
+ size_t payloadSize, // IN: request payload size
+ HgfsHandle* file, // OUT: HGFS handle write to
+ uint64 *offset, // OUT: offset to write to
+ uint32 *length, // OUT: size of data to write
+ HgfsWriteFlags *flags) // OUT: write flags
+{
+ LOG(4, ("%s: HGFS_OP_WRITE_V3\n", __FUNCTION__));
+ if (payloadSize >= sizeof *requestV3) {
+ *file = requestV3->file;
+ *flags = requestV3->flags;
+ *offset = requestV3->offset;
+ *length = requestV3->requiredSize;
+ return TRUE;
+ }
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackWriteRequest --
+ *
+ * Unpack hgfs write request to get parameters and data to write.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackWriteRequest(HgfsInputParam *input, // IN: Input params
+ HgfsHandle *file, // OUT: Handle to write to
+ uint64 *offset, // OUT: offset to write to
+ uint32 *length, // OUT: length of data to write
+ HgfsWriteFlags *flags, // OUT: write flags
+ char **data) // OUT: data to be written
+{
+ Bool result;
+
+ ASSERT(input);
+
+ switch (input->op) {
+ case HGFS_OP_WRITE_FAST_V4: {
+ HgfsRequestWriteV3 *requestV3 = (HgfsRequestWriteV3 *)input->payload;
+
+ result = HgfsUnpackWriteFastPayloadV4(requestV3, input->payloadSize, file,
+ offset, length, flags);
+ if (result) {
+ *data = HSPU_GetDataPacketBuf(input->packet,
+ BUF_READABLE,
+ input->session);
+ if (NULL == *data) {
+ LOG(4, ("%s: Failed to get data in guest memory\n", __FUNCTION__));
+ result = FALSE;
+ }
+ }
+ break;
+ }
+ case HGFS_OP_WRITE_V3: {
+ HgfsRequestWriteV3 *requestV3 = (HgfsRequestWriteV3 *)input->payload;
+
+ result = HgfsUnpackWritePayloadV3(requestV3, input->payloadSize, file, offset,
+ length, flags, data);
+ break;
+ }
+ case HGFS_OP_WRITE: {
+ HgfsRequestWrite *requestV1 = (HgfsRequestWrite *)input->payload;
+
+ result = HgfsUnpackWritePayload(requestV1, input->payloadSize, file, offset,
+ length, flags, data);
+ break;
+ }
+ default:
+ LOG(4, ("%s: Incorrect opcode %d\n", __FUNCTION__, input->op));
+ NOT_REACHED();
+ result = FALSE;
+ }
+
+ if (!result) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackWriteReply --
+ *
+ * Pack hgfs write reply to the HgfsReplyWrite structure.
+ *
+ * Results:
+ * TRUE is there are no bugs in the code.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackWriteReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ uint32 actualSize, // IN: number of bytes that were written
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ *payloadSize = 0;
+
+ switch (op) {
+ case HGFS_OP_WRITE_FAST_V4:
+ case HGFS_OP_WRITE_V3: {
+ HgfsReplyWriteV3 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ reply->actualSize = actualSize;
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_WRITE: {
+ HgfsReplyWrite *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ reply->actualSize = actualSize;
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ default:
+ NOT_REACHED();
+ result = FALSE;
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackQueryVolumePayload --
+ *
+ * Unpack hgfs query volume payload to get the file name which must be used to query
+ * volume information.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackQueryVolumePayload(HgfsRequestQueryVolume *request, // IN: request payload
+ size_t payloadSize, // IN: request payload size
+ char **fileName, // OUT: volume name
+ size_t *nameLength) // OUT: volume name length
+{
+ LOG(4, ("%s: HGFS_OP_QUERY_VOLUME_INFO\n", __FUNCTION__));
+ if (payloadSize >= sizeof *request) {
+ return HgfsUnpackFileName(&request->fileName,
+ payloadSize - sizeof *request + 1,
+ fileName,
+ nameLength);
+ }
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackQueryVolumePayloadV3 --
+ *
+ * Unpack hgfs query volume payload V3.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackQueryVolumePayloadV3(HgfsRequestQueryVolumeV3 *requestV3, // IN: payload
+ size_t payloadSize, // IN: payload size
+ Bool *useHandle, // OUT: use handle
+ HgfsHandle* file, // OUT: HGFS handle
+ char **fileName, // OUT: volume name
+ size_t *nameLength, // OUT: name length
+ uint32 * caseFlags) // OUT: case flags
+{
+ LOG(4, ("%s: HGFS_OP_QUERY_VOLUME_INFO_V3\n", __FUNCTION__));
+ if (payloadSize >= sizeof *requestV3) {
+ return HgfsUnpackFileNameV3(&requestV3->fileName,
+ payloadSize - sizeof *requestV3 + 1,
+ useHandle,
+ fileName,
+ nameLength,
+ file,
+ caseFlags);
+ }
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackQueryVolumeRequest --
+ *
+ * Unpack hgfs query volume information request to get parameters related to
+ * query volume operation.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackQueryVolumeRequest(void const *packet, // IN: HGFS packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ Bool *useHandle, // OUT: use handle
+ char **fileName, // OUT: file name
+ size_t *fileNameLength, // OUT: file name length
+ uint32 *caseFlags, // OUT: case sensitivity
+ HgfsHandle *file) // OUT: Handle to the volume
+{
+ ASSERT(packet);
+
+ switch (op) {
+ case HGFS_OP_QUERY_VOLUME_INFO_V3: {
+ HgfsRequestQueryVolumeV3 *requestV3 = (HgfsRequestQueryVolumeV3 *)packet;
+
+ if (!HgfsUnpackQueryVolumePayloadV3(requestV3, packetSize, useHandle, file,
+ fileName, fileNameLength, caseFlags)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ case HGFS_OP_QUERY_VOLUME_INFO: {
+ HgfsRequestQueryVolume *requestV1 = (HgfsRequestQueryVolume *)packet;
+
+ if (!HgfsUnpackQueryVolumePayload(requestV1, packetSize, fileName,
+ fileNameLength)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ *file = HGFS_INVALID_HANDLE;
+ *caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+ *useHandle = FALSE;
+ break;
+ }
+ default:
+ LOG(4, ("%s: Incorrect opcode %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackQueryVolumeReply --
+ *
+ * Pack hgfs query volume reply.
+ *
+ * Results:
+ * TRUE if valid op and reply set, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackQueryVolumeReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ uint64 freeBytes, // IN: volume free space
+ uint64 totalBytes, // IN: volume capacity
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ *payloadSize = 0;
+
+ switch (op) {
+ case HGFS_OP_QUERY_VOLUME_INFO_V3: {
+ HgfsReplyQueryVolumeV3 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ reply->freeBytes = freeBytes;
+ reply->totalBytes = totalBytes;
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_QUERY_VOLUME_INFO: {
+ HgfsReplyQueryVolume *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ reply->freeBytes = freeBytes;
+ reply->totalBytes = totalBytes;
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ default:
+ result = FALSE;
+ LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSymlinkCreatePayload --
+ *
+ * Unpack hgfs symbolic link payload to get symbolic link file name
+ * and symbolic link target.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSymlinkCreatePayload(HgfsRequestSymlinkCreate *request, // IN: request payload
+ size_t payloadSize, // IN: payload size
+ char **srcFileName, // OUT: link file name
+ size_t *srcNameLength, // OUT: file name length
+ char **tgFileName, // OUT: target file name
+ size_t *tgNameLength) // OUT: target name length
+{
+ uint32 prefixSize;
+
+ LOG(4, ("%s: HGFS_OP_CREATE_SYMLINK_V3\n", __FUNCTION__));
+ prefixSize = offsetof(HgfsRequestSymlinkCreate, symlinkName.name);
+ if (payloadSize >= prefixSize) {
+ if (HgfsUnpackFileName(&request->symlinkName,
+ payloadSize - prefixSize,
+ srcFileName,
+ srcNameLength)) {
+ HgfsFileName *targetName = (HgfsFileName *)(*srcFileName + 1 + *srcNameLength);
+ prefixSize = ((char *)targetName - (char *)request) + offsetof(HgfsFileName, name);
+
+ return HgfsUnpackFileName(targetName,
+ payloadSize - prefixSize,
+ tgFileName,
+ tgNameLength);
+ };
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSymlinkCreatePayloadV3 --
+ *
+ * Unpack hgfs create symbolic link payload V3.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSymlinkCreatePayloadV3(HgfsRequestSymlinkCreateV3 *requestV3, // IN:
+ size_t payloadSize, // IN:
+ Bool *srcUseHandle, // OUT:
+ HgfsHandle* srcFile, // OUT:
+ char **srcFileName, // OUT:
+ size_t *srcNameLength, // OUT:
+ uint32 *srcCaseFlags, // OUT:
+ Bool *tgUseHandle, // OUT:
+ HgfsHandle* tgFile, // OUT:
+ char **tgFileName, // OUT:
+ size_t *tgNameLength, // OUT:
+ uint32 * tgCaseFlags) // OUT:
+{
+ uint32 prefixSize;
+
+ LOG(4, ("%s: HGFS_OP_CREATE_SYMLINK_V3\n", __FUNCTION__));
+ prefixSize = offsetof(HgfsRequestSymlinkCreateV3, symlinkName.name);
+ if (payloadSize >= prefixSize) {
+ if (HgfsUnpackFileNameV3(&requestV3->symlinkName,
+ payloadSize - prefixSize,
+ srcUseHandle,
+ srcFileName,
+ srcNameLength,
+ srcFile,
+ srcCaseFlags)) {
+ HgfsFileNameV3 *targetName = (HgfsFileNameV3 *)(*srcFileName + 1 +
+ *srcNameLength);
+ prefixSize = ((char *)targetName - (char *)requestV3) +
+ offsetof(HgfsFileNameV3, name);
+
+ return HgfsUnpackFileNameV3(targetName,
+ payloadSize - prefixSize,
+ tgUseHandle,
+ tgFileName,
+ tgNameLength,
+ tgFile,
+ tgCaseFlags);
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSymlinkCreateRequest --
+ *
+ * Unpack hgfs symbolic link creation request to get parameters related to
+ * creating the symbolic link.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSymlinkCreateRequest(void const *packet, // IN: HGFS packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ Bool *srcUseHandle, // OUT: use source handle
+ char **srcFileName, // OUT: source file name
+ size_t *srcFileNameLength, // OUT: source file name length
+ uint32 *srcCaseFlags, // OUT: source case sensitivity
+ HgfsHandle *srcFile, // OUT: source file handle
+ Bool *tgUseHandle, // OUT: use target handle
+ char **tgFileName, // OUT: target file name
+ size_t *tgFileNameLength, // OUT: target file name length
+ uint32 *tgCaseFlags, // OUT: target case sensitivity
+ HgfsHandle *tgFile) // OUT: target file handle
+{
+ ASSERT(packet);
+
+ switch (op) {
+ case HGFS_OP_CREATE_SYMLINK_V3: {
+ HgfsRequestSymlinkCreateV3 *requestV3 = (HgfsRequestSymlinkCreateV3 *)packet;
+
+ if (!HgfsUnpackSymlinkCreatePayloadV3(requestV3, packetSize,
+ srcUseHandle, srcFile,
+ srcFileName, srcFileNameLength, srcCaseFlags,
+ tgUseHandle, tgFile,
+ tgFileName, tgFileNameLength, tgCaseFlags)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ case HGFS_OP_CREATE_SYMLINK: {
+ HgfsRequestSymlinkCreate *requestV1 = (HgfsRequestSymlinkCreate *)packet;
+
+ if (!HgfsUnpackSymlinkCreatePayload(requestV1, packetSize, srcFileName,
+ srcFileNameLength, tgFileName, tgFileNameLength)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ *srcFile = HGFS_INVALID_HANDLE;
+ *srcCaseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+ *srcUseHandle = FALSE;
+ *tgFile = HGFS_INVALID_HANDLE;
+ *tgCaseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+ *tgUseHandle = FALSE;
+ break;
+ }
+ default:
+ LOG(4, ("%s: Incorrect opcode %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackSymlinkCreateReply --
+ *
+ * Pack hgfs symbolic link creation reply.
+ *
+ * Results:
+ * TRUE if valid op and reply set, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackSymlinkCreateReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ HGFS_ASSERT_PACK_PARAMS;
+
+ *payloadSize = 0;
+
+ switch (op) {
+ case HGFS_OP_CREATE_SYMLINK_V3: {
+ HgfsReplyQueryVolumeV3 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_CREATE_SYMLINK: {
+ HgfsReplyQueryVolume *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ default:
+ result = FALSE;
+ LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSearchOpenPayload --
+ *
+ * Unpack hgfs search open payload to get name of directory to open.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSearchOpenPayload(HgfsRequestSearchOpen *request, // IN: payload
+ size_t payloadSize, // IN: payload size
+ char **dirName, // OUT: directory name
+ uint32 *dirNameLength) // OUT: name length
+{
+ LOG(4, ("%s: HGFS_OP_SEARCH_OPEN\n", __FUNCTION__));
+ if (payloadSize >= sizeof *request) {
+ if (sizeof *request + request->dirName.length - 1 <= payloadSize) {
+ *dirName = request->dirName.name;
+ *dirNameLength = request->dirName.length;
+ return TRUE;
+ }
+ }
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSearchOpenPayloadV3 --
+ *
+ * Unpack hgfs search open payload V3 to get name of directory to open and
+ * case flags.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSearchOpenPayloadV3(HgfsRequestSearchOpenV3 *requestV3, // IN: payload
+ size_t payloadSize, // IN: payload size
+ char **dirName, // OUT: directory name
+ uint32 *dirNameLength, // OUT: name length
+ uint32 *caseFlags) // OUT: case flags
+{
+ LOG(4, ("%s: HGFS_OP_SEARCH_OPEN_V3\n", __FUNCTION__));
+ if (payloadSize >= sizeof *requestV3) {
+ if (sizeof *requestV3 + requestV3->dirName.length - 1 <= payloadSize) {
+ *dirName = requestV3->dirName.name;
+ *dirNameLength = requestV3->dirName.length;
+ *caseFlags = requestV3->dirName.flags;
+ return TRUE;
+ }
+ }
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackSearchOpenRequest --
+ *
+ * Unpack hgfs search open request to get directory name and case flags.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackSearchOpenRequest(void const *packet, // IN: HGFS packet
+ size_t packetSize, // IN: request packet size
+ HgfsOp op, // IN: request type
+ char **dirName, // OUT: directory name
+ uint32 *dirNameLength, // OUT: name length
+ uint32 *caseFlags) // OUT: case flags
+{
+ ASSERT(packet);
+
+ switch (op) {
+ case HGFS_OP_SEARCH_OPEN_V3: {
+ HgfsRequestSearchOpenV3 *requestV3 = (HgfsRequestSearchOpenV3 *)packet;
+
+ if (!HgfsUnpackSearchOpenPayloadV3(requestV3, packetSize, dirName,
+ dirNameLength, caseFlags)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ break;
+ }
+ case HGFS_OP_SEARCH_OPEN: {
+ HgfsRequestSearchOpen *requestV1 = (HgfsRequestSearchOpen *)packet;
+
+ if (!HgfsUnpackSearchOpenPayload(requestV1, packetSize, dirName,
+ dirNameLength)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+ *caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
+ break;
+ }
+ default:
+ LOG(4, ("%s: Incorrect opcode %d\n", __FUNCTION__, op));
+ NOT_REACHED();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackSearchOpenReply --
+ *
+ * Pack hgfs search open reply.
+ *
+ * Results:
+ * TRUE unless it is invoked for a wrong op (which indicates a bug in the code).
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackSearchOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ HgfsOp op, // IN: request type
+ HgfsHandle search, // IN: search handle
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+
+ HGFS_ASSERT_PACK_PARAMS;
+
+ *payloadSize = 0;
+
+ switch (op) {
+ case HGFS_OP_SEARCH_OPEN_V3: {
+ HgfsReplySearchOpenV3 *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ reply->search = search;
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ case HGFS_OP_SEARCH_OPEN: {
+ HgfsReplySearchOpen *reply;
+
+ result = HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+ if (result) {
+ reply->search = search;
+ *payloadSize = sizeof *reply;
+ }
+ break;
+ }
+ default:
+ NOT_REACHED();
+ result = FALSE;
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackCreateSessionPayloadV4 --
+ *
+ * Unpack hgfs create session request V4 payload.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackCreateSessionPayloadV4(HgfsRequestCreateSessionV4 *requestV4, // IN: payload
+ size_t payloadSize, // IN:
+ HgfsCreateSessionInfo *info) // IN/OUT: info
+{
+ LOG(4, ("%s: HGFS_OP_CREATE_SESSION_V4\n", __FUNCTION__));
+ if (payloadSize < offsetof(HgfsRequestCreateSessionV4, reserved)) {
+ /* The input packet is smaller than the request. */
+ return FALSE;
+ }
+
+ if (requestV4->numCapabilities) {
+ if (payloadSize < offsetof(HgfsRequestCreateSessionV4, capabilities) +
+ requestV4->numCapabilities * sizeof(HgfsCapability)) {
+ LOG(4, ("%s: HGFS packet too small\n", __FUNCTION__));
+ return FALSE;
+ }
+ }
+
+ info->maxPacketSize = requestV4->maxPacketSize;
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackCreateSessionRequest --
+ *
+ * Unpack hgfs CreateSession request and initialize a corresponding
+ * HgfsCreateDirInfo structure that is used to pass around CreateDir request
+ * information.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackCreateSessionRequest(void const *packet, // IN: HGFS packet
+ size_t packetSize, // IN: size of packet
+ HgfsOp op, // IN: request type
+ HgfsCreateSessionInfo *info) // IN/OUT: info struct
+{
+ HgfsRequestCreateSessionV4 *requestV4;
+
+ ASSERT(packet);
+ ASSERT(info);
+
+ ASSERT(op == HGFS_OP_CREATE_SESSION_V4);
+
+ requestV4 = (HgfsRequestCreateSessionV4 *)packet;
+ if (!HgfsUnpackCreateSessionPayloadV4(requestV4, packetSize, info)) {
+ LOG(4, ("%s: Error decoding HGFS packet\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackCreateSessionReply --
+ *
+ * Pack hgfs CreateSession reply.
+ *
+ * Results:
+ * Always TRUE.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackCreateSessionReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ Bool result;
+ HgfsReplyCreateSessionV4 *reply;
+ uint32 numCapabilities = ARRAYSIZE(hgfsServerCapabilities);
+
+ HGFS_ASSERT_PACK_PARAMS;
+
+ *payloadSize = offsetof(HgfsReplyCreateSessionV4, capabilities) +
+ sizeof hgfsServerCapabilities;
+
+ result = HgfsAllocInitReply(packet, packetHeader, *payloadSize,
+ (void **)&reply, session);
+ if (result) {
+ reply->sessionId = session->sessionId;
+ reply->numCapabilities = numCapabilities;
+ reply->maxPacketSize = session->maxPacketSize;
+ reply->identityOffset = 0;
+ reply->reserved = 0;
+ memcpy(reply->capabilities, hgfsServerCapabilities,
+ sizeof hgfsServerCapabilities);
+ }
+
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackDestroySessionReply --
+ *
+ * Pack hgfs CreateSession reply.
+ *
+ * Results:
+ * Always TRUE.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackDestorySessionReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetHeader, // IN: packet header
+ size_t *payloadSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
+{
+ HgfsReplyDestroySessionV4 *reply;
+
+ HGFS_ASSERT_PACK_PARAMS;
+
+ *payloadSize = 0;
+
+ return HgfsAllocInitReply(packet, packetHeader, sizeof *reply,
+ (void **)&reply, session);
+}
HGFS_OP_CREATE_SYMLINK_V3, /* Create a symlink */
HGFS_OP_SERVER_LOCK_CHANGE_V3, /* Change the oplock on a file */
HGFS_OP_WRITE_WIN32_STREAM_V3, /* Write WIN32_STREAM_ID format data to file */
-
/*
* Operations for version 4, deprecating version 3 operations.
*/
#include "vmware_pack_end.h"
HgfsHeader;
+/*
+ * If no flags are set then the capability is not supported by the host.
+ */
+#define HGFS_REQUEST_NOT_SUPPORTED 0
/*
* Flag HGFS_REQUEST_SUPPORTED is set for every requests that are supported by the host.
*/
typedef
#include "vmware_pack_begin.h"
-struct HgfsRequestCreateSession {
+struct HgfsRequestCreateSessionV4 {
uint32 numCapabilities; /* Number of capabilities to follow. */
uint32 maxPacketSize; /* Maximum packet size supported. */
uint64 reserved; /* Reserved for future use. */
HgfsCapability capabilities[1]; /* Array of HgfsCapabilities. */
}
#include "vmware_pack_end.h"
-HgfsRequestCreateSession;
+HgfsRequestCreateSessionV4;
+#define HGFS_INVALID_SESSION_ID 0xffffffff
typedef
#include "vmware_pack_begin.h"
-struct HgfsReplyCreateSession {
+struct HgfsReplyCreateSessionV4 {
uint64 sessionId; /* Session ID. */
uint32 numCapabilities; /* Number of capabilities to follow. */
uint32 maxPacketSize; /* Maximum packet size supported. */
HgfsCapability capabilities[1]; /* Array of HgfsCapabilities. */
}
#include "vmware_pack_end.h"
-HgfsReplyCreateSession;
+HgfsReplyCreateSessionV4;
typedef
#include "vmware_pack_begin.h"
-struct HgfsRequestDestroySession {
- uint64 sessionId; /* Session ID. */
+struct HgfsRequestDestroySessionV4 {
uint64 reserved; /* Reserved for future use. */
}
#include "vmware_pack_end.h"
-HgfsRequestDestroySession;
+HgfsRequestDestroySessionV4;
typedef
#include "vmware_pack_begin.h"
-struct HgfsReplyDestroySession {
+struct HgfsReplyDestroySessionV4 {
uint64 reserved; /* Reserved for future use. */
}
#include "vmware_pack_end.h"
-HgfsReplyDestroySession;
+HgfsReplyDestroySessionV4;
/* Adds new error status: HGFS_STATUS_INVALID_SESSION. */
# include <errno.h>
# endif
typedef int HgfsInternalStatus;
+ /*
+ * There is no internal error in Linux.
+ * Define a const that is converted to HGFS_INTERNAL_STATUS_ERROR.
+ */
+# define EINTERNAL 1001
#else
# include <windows.h>
typedef DWORD HgfsInternalStatus;
#endif
+#if defined _WIN32
+#define HGFS_ERROR_SUCCESS ERROR_SUCCESS
+#define HGFS_ERROR_IO ERROR_IO_DEVICE
+#define HGFS_ERROR_ACCESS_DENIED ERROR_ACCESS_DENIED
+#define HGFS_ERROR_INVALID_PARAMETER ERROR_INVALID_PARAMETER
+#define HGFS_ERROR_INVALID_HANDLE ERROR_INVALID_HANDLE
+#define HGFS_ERROR_PROTOCOL RPC_S_PROTOCOL_ERROR
+#define HGFS_ERROR_STALE_SESSION ERROR_CONNECTION_INVALID
+#define HGFS_ERROR_BUSY ERROR_RETRY
+#define HGFS_ERROR_PATH_BUSY ERROR_RETRY
+#define HGFS_ERROR_FILE_NOT_FOUND ERROR_FILE_NOT_FOUND
+#define HGFS_ERROR_FILE_EXIST ERROR_ALREADY_EXISTS
+#define HGFS_ERROR_NOT_SUPPORTED ERROR_NOT_SUPPORTED
+#define HGFS_ERROR_NOT_ENOUGH_MEMORY ERROR_NOT_ENOUGH_MEMORY
+#define HGFS_ERROR_INTERNAL ERROR_INTERNAL_ERROR
+#else
+#define HGFS_ERROR_SUCCESS 0
+#define HGFS_ERROR_IO EIO
+#define HGFS_ERROR_ACCESS_DENIED EACCES
+#define HGFS_ERROR_INVALID_PARAMETER EINVAL
+#define HGFS_ERROR_INVALID_HANDLE EINVAL
+#define HGFS_ERROR_PROTOCOL EPROTO
+#define HGFS_ERROR_STALE_SESSION ENETRESET
+#define HGFS_ERROR_BUSY EBUSY
+#define HGFS_ERROR_PATH_BUSY EBUSY
+#define HGFS_ERROR_FILE_NOT_FOUND ENOENT
+#define HGFS_ERROR_FILE_EXIST EEXIST
+#define HGFS_ERROR_NOT_SUPPORTED EOPNOTSUPP
+#define HGFS_ERROR_NOT_ENOUGH_MEMORY ENOMEM
+#define HGFS_ERROR_INTERNAL EINTERNAL
+#endif // _WIN32
+
/*
* Unfortunately, we need a catch-all "generic error" to use with
* HgfsInternalStatus, because there are times when cross-platform code needs