]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Adding create/destroy session support.
authorVMware, Inc <>
Thu, 17 Jun 2010 22:03:49 +0000 (15:03 -0700)
committerMarcelo Vanzin <mvanzin@vmware.com>
Thu, 17 Jun 2010 22:03:49 +0000 (15:03 -0700)
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>
open-vm-tools/lib/hgfs/hgfsUtil.c
open-vm-tools/lib/hgfsServer/Makefile.am
open-vm-tools/lib/hgfsServer/hgfsServer.c
open-vm-tools/lib/hgfsServer/hgfsServerInt.h
open-vm-tools/lib/hgfsServer/hgfsServerLinux.c
open-vm-tools/lib/hgfsServer/hgfsServerPacketUtil.c
open-vm-tools/lib/hgfsServer/hgfsServerParameters.c [new file with mode: 0644]
open-vm-tools/lib/include/hgfsProto.h
open-vm-tools/lib/include/hgfsUtil.h

index 4ad5815e97ef8fd65735f1eb86377d80c415ff5c..c808509923a705d660f93f3effc4fd11651e49b5 100644 (file)
@@ -233,6 +233,7 @@ HgfsConvertFromInternalStatus(HgfsInternalStatus status) // IN
       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;
@@ -276,6 +277,7 @@ HgfsConvertFromInternalStatus(HgfsInternalStatus status) // IN
       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;
index d39942f0e50520541ef6f9b796aafadfb9d6ed1b..4455e5b23e4e6d6b4e53e0acacaa04eeca0f2dea 100644 (file)
@@ -22,6 +22,7 @@ libHgfsServer_la_SOURCES += hgfsServer.c
 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
index 0e9e67166a919c7d4d936aa46b03a5e1f7289d8c..c7029e98098323510d8e522418f0bc2395fa2696 100644 (file)
@@ -25,6 +25,9 @@
 #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"
@@ -35,6 +38,7 @@
 #include "userlock.h"
 #include "poll.h"
 #include "libMutexRank.h"
+#include "vm_basic_asm.h"
 
 #if defined(_WIN32)
 #include <io.h>
@@ -69,6 +73,9 @@
 #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
@@ -182,6 +189,12 @@ HgfsServerSessionCallbacks hgfsServerSessionCBTable = {
 
 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. */
 
@@ -225,17 +238,34 @@ static HgfsHandle HgfsFileNode2Handle(HgfsFileNode const *fileNode);
 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);
 
 
 /*
@@ -254,7 +284,7 @@ void HgfsServer_ReplyWithError(HgfsPacket *packet,
  *----------------------------------------------------------------------------
  */
 
-static void
+void
 HgfsServerSessionGet(HgfsSessionInfo *session)   // IN: session context
 {
    ASSERT(session);
@@ -2500,47 +2530,34 @@ HgfsUpdateNodeNames(const char *oldLocalName,  // IN: Name of file to look for
  *-----------------------------------------------------------------------------
  */
 
-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);
 }
 
 
@@ -2561,47 +2578,37 @@ error:
  *-----------------------------------------------------------------------------
  */
 
-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);
 }
 
 
@@ -2609,9 +2616,7 @@ error:
 
 /* Opcode handlers, indexed by opcode */
 static struct {
-   HgfsInternalStatus
-   (*handler)(HgfsInputParam *input);
-
+   void (*handler)(HgfsInputParam *input);
    /* Minimal size of the request packet */
    unsigned int minReqSize;
 
@@ -2663,19 +2668,112 @@ static struct {
    { 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);
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -2687,8 +2785,8 @@ static struct {
  *    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
@@ -2711,14 +2809,8 @@ HgfsServerSessionReceive(HgfsPacket *packet,      // IN: Hgfs Packet
                          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);
 
@@ -2728,235 +2820,65 @@ HgfsServerSessionReceive(HgfsPacket *packet,      // IN: Hgfs Packet
       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);
    }
 }
 
@@ -3056,6 +2978,29 @@ HgfsServer_ExitState(void)
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsGenerateSessionId --
+ *
+ *    Generates unique session id.
+ *
+ * Results:
+ *    Unique 64-bit value.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static uint64
+HgfsGenerateSessionId(void)
+{
+   return RDTSC();
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -3121,6 +3066,8 @@ HgfsServerSessionConnect(void *transportData,                         // IN: tra
       return FALSE;
    }
 
+   session->sessionId = HgfsGenerateSessionId();
+   session->maxPacketSize = MAX_SERVER_PACKET_SIZE_V4;
    /*
     * Initialize the node handling components.
     */
@@ -3474,6 +3421,7 @@ HgfsServerSessionSendComplete(HgfsPacket *packet,   // IN/OUT: Hgfs packet
    HgfsSessionInfo *session = (HgfsSessionInfo *)clientData;
    HSPU_PutMetaPacket(packet, session);
    HSPU_PutReplyPacket(packet, session);
+   HSPU_PutDataPacketBuf(packet, session);
 }
 
 
@@ -3520,51 +3468,10 @@ HgfsPacketSend(HgfsPacket *packet,            // IN/OUT: Hgfs Packet
 #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);
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -4363,7 +4270,7 @@ HgfsServerSearchRealDir(char const *baseDir,      // IN: Directory to search
                              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;
    }
 
@@ -4372,7 +4279,7 @@ HgfsServerSearchRealDir(char const *baseDir,      // IN: Directory to search
                                                  &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;
    }
@@ -4440,7 +4347,7 @@ HgfsServerSearchVirtualDir(HgfsGetNameFunc *getName,     // IN: Name enumerator
    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;
    }
 
@@ -4448,7 +4355,7 @@ HgfsServerSearchVirtualDir(HgfsGetNameFunc *getName,     // IN: Name enumerator
    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;
    }
 
@@ -4731,14 +4638,12 @@ HgfsCreateAndCacheFileNode(HgfsFileOpenInfo *openInfo, // IN: Open info struct
 /*
  *-----------------------------------------------------------------------------
  *
- * 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
@@ -4746,28 +4651,37 @@ HgfsCreateAndCacheFileNode(HgfsFileOpenInfo *openInfo, // IN: Open info struct
  *-----------------------------------------------------------------------------
  */
 
-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;
 }
 
@@ -4775,13 +4689,13 @@ HgfsValidatePacket(char const *packetIn,        // IN: request packet
 /*
  *-----------------------------------------------------------------------------
  *
- * 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
@@ -4789,37 +4703,89 @@ HgfsValidatePacket(char const *packetIn,        // IN: request packet
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -4827,187 +4793,273 @@ HgfsGetPayloadSize(char const *packetIn,        // IN: request packet
  *-----------------------------------------------------------------------------
  */
 
-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,
+                               &currentFreeBytes, &currentTotalBytes)) {
+            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
@@ -5015,69 +5067,62 @@ HgfsUnpackOpenPayloadV2(HgfsRequestOpenV2 *requestV2, // IN: request payload
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -5085,65 +5130,83 @@ HgfsUnpackOpenPayloadV3(HgfsRequestOpenV3 *requestV3, // IN: request payload
  *-----------------------------------------------------------------------------
  */
 
-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.
@@ -5155,31 +5218,60 @@ HgfsUnpackOpenRequest(char const *packetIn,        // IN: request packet
  */
 
 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.
@@ -5190,53 +5282,154 @@ HgfsPackReplyHeaderV4(HgfsInternalStatus status,    // IN: reply status
  *-----------------------------------------------------------------------------
  */
 
-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.
@@ -5248,24 +5441,122 @@ HgfsPackOpenReplyV3(HgfsFileOpenInfo *openInfo,   // IN: open info struct
  */
 
 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.
@@ -5277,2024 +5568,77 @@ HgfsPackOpenV2Reply(HgfsFileOpenInfo *openInfo,   // IN: open info struct
  */
 
 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.
@@ -7305,400 +5649,91 @@ HgfsPackSearchReadReplyPayloadV2(HgfsFileAttrInfo *attr,       // IN: attr stuct
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -7706,103 +5741,103 @@ HgfsUnpackSetattrPayloadV1(HgfsRequestSetattr *requestV1,  // IN: request payloa
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -7810,62 +5845,25 @@ HgfsUnpackSetattrRequest(char const *packetIn,       // IN: request packet
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -7873,57 +5871,47 @@ HgfsPackSetattrReply(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -7931,56 +5919,125 @@ HgfsUnpackCreateDirPayloadV3(HgfsRequestCreateDirV3 *requestV3, // IN: request p
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -7988,45 +6045,102 @@ HgfsUnpackCreateDirPayloadV2(HgfsRequestCreateDirV2 *requestV2, // IN: request p
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -8034,75 +6148,176 @@ HgfsUnpackCreateDirPayloadV1(HgfsRequestCreateDir *requestV1, // IN: request pay
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -8110,66 +6325,217 @@ HgfsUnpackCreateDirRequest(char const *packetIn,    // IN: incoming packet
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -8177,41 +6543,77 @@ HgfsPackCreateDirReply(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -8219,53 +6621,45 @@ HgfsUnpackWriteWin32StreamPayloadV3(HgfsRequestWriteWin32StreamV3 *requestV3, //
  *-----------------------------------------------------------------------------
  */
 
-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
@@ -8273,40 +6667,16 @@ HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet
  *-----------------------------------------------------------------------------
  */
 
-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);
 }
 
 
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -8439,6 +6809,39 @@ Hgfs_NotificationCallback(HgfsSharedFolderHandle sharedFolder,
             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
 /*
  *-----------------------------------------------------------------------------
index 1d982fa76642576d2ad04423d8033d72c7d2ea32..e978f82bff6117689fc472b5e8fd47f6bd79b5c0 100644 (file)
 #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)
 
 /*
@@ -114,8 +98,8 @@ typedef struct HgfsLocalId {
 } 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;
 
 
@@ -296,6 +280,12 @@ typedef enum {
 
 
 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;
 
@@ -430,6 +420,10 @@ typedef struct HgfsCreateDirInfo {
    HgfsAttrFlags fileAttr;       /* Various flags and Windows 'attributes' */
 } HgfsCreateDirInfo;
 
+typedef struct HgfsCreateSessionInfo {
+   uint32 maxPacketSize;
+} HgfsCreateSessionInfo;
+
 
 /* Server lock related structure */
 typedef struct {
@@ -438,16 +432,17 @@ 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
@@ -529,73 +524,42 @@ HgfsServerSearchVirtualDir(HgfsGetNameFunc *getName,     // IN: Name enumerator
                            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
@@ -604,9 +568,9 @@ HgfsUnpackGetattrRequest(char const *packetIn,       // IN: request packet
                          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
@@ -615,17 +579,15 @@ HgfsUnpackDeleteRequest(char const *packetIn,       // IN: request packet
 
 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
@@ -638,123 +600,193 @@ HgfsUnpackRenameRequest(char const *packetIn,       // IN: request packet
 
 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
@@ -928,7 +960,125 @@ HgfsPacketSend(HgfsPacket *packet,            // IN/OUT: Hgfs Packet
 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
@@ -951,16 +1101,16 @@ HSPU_GetDataPacketBuf(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
index 1e6cad5601457da7be057513572517f59372dfa1..7ee215427c966ac2c078bee8268f14daef163e3d 100644 (file)
@@ -270,24 +270,9 @@ static const int HgfsServerOpenMode[] = {
 };
 
 /* 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);
@@ -331,19 +316,6 @@ static HgfsInternalStatus HgfsSetattrTimes(struct stat *statBuf,
                                            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,
@@ -455,7 +427,7 @@ HgfsServerSigOplockBreak(int sigNum,       // IN: Signal number
 /*
  *-----------------------------------------------------------------------------
  *
- * HgfsConvertFromNameStatus --
+ * HgfsPlatformConvertFromNameStatus --
  *
  *    This function converts between a status code used in processing a cross
  *    platform filename, and a platform-specific status code.
@@ -473,8 +445,8 @@ HgfsServerSigOplockBreak(int sigNum,       // IN: Signal number
  *-----------------------------------------------------------------------------
  */
 
-static HgfsInternalStatus
-HgfsConvertFromNameStatus(HgfsNameStatus status) // IN
+HgfsInternalStatus
+HgfsPlatformConvertFromNameStatus(HgfsNameStatus status) // IN
 {
    switch(status) {
    case HGFS_NAME_STATUS_COMPLETE:
@@ -507,7 +479,7 @@ HgfsConvertFromNameStatus(HgfsNameStatus status) // IN
 /*
  *-----------------------------------------------------------------------------
  *
- * HgfsServerGetDefaultDirAttrs --
+ * HgfsPlatformGetDefaultDirAttrs --
  *
  *    Get default directory attributes. Permissions are Read and
  *    Execute permission only.
@@ -521,8 +493,8 @@ HgfsConvertFromNameStatus(HgfsNameStatus status) // IN
  *-----------------------------------------------------------------------------
  */
 
-static void
-HgfsServerGetDefaultDirAttrs(HgfsFileAttrInfo *attr) // OUT
+void
+HgfsPlatformGetDefaultDirAttrs(HgfsFileAttrInfo *attr) // OUT
 {
    struct timeval tv;
    uint64 hgfsTime;
@@ -798,7 +770,7 @@ HgfsCheckFileNode(char const *localName,      // IN
 /*
  *-----------------------------------------------------------------------------
  *
- * 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
@@ -815,11 +787,11 @@ HgfsCheckFileNode(char const *localName,      // IN
  *-----------------------------------------------------------------------------
  */
 
-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;
@@ -959,12 +931,12 @@ HgfsGetFd(HgfsHandle hgfsHandle,    // IN:  HGFS file handle
  *-----------------------------------------------------------------------------
  */
 
-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;
@@ -2143,7 +2115,7 @@ HgfsFStat(int fd,                 // IN: file descriptor
 /*
  *-----------------------------------------------------------------------------
  *
- * 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
@@ -2167,12 +2139,12 @@ HgfsFStat(int fd,                 // IN: file descriptor
  *-----------------------------------------------------------------------------
  */
 
-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;
@@ -2304,7 +2276,7 @@ HgfsGetattrFromName(char *fileName,                    // IN/OUT:  Input filenam
                                         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
@@ -2342,54 +2314,10 @@ exit:
    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
@@ -2405,10 +2333,10 @@ HgfsAccess(char *fileName,         // IN: local file path
  *-----------------------------------------------------------------------------
  */
 
-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;
@@ -2422,9 +2350,9 @@ HgfsGetattrFromFd(int fd,                     // IN:  file descriptor
    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;
@@ -2459,14 +2387,14 @@ HgfsGetattrFromFd(int fd,                     // IN:  file descriptor
     * 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;
    }
@@ -2846,7 +2774,7 @@ exit:
 /*
  *-----------------------------------------------------------------------------
  *
- * HgfsSetattrFromFd --
+ * HgfsPlatformSetattrFromFd --
  *
  *    Handle a Setattr request by file descriptor.
  *
@@ -2860,11 +2788,11 @@ exit:
  *-----------------------------------------------------------------------------
  */
 
-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;
@@ -2878,28 +2806,16 @@ HgfsSetattrFromFd(HgfsHandle file,          // IN: file descriptor
    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;
@@ -3024,7 +2940,7 @@ exit:
 /*
  *-----------------------------------------------------------------------------
  *
- * HgfsSetattrFromName --
+ * HgfsPlatformSetattrFromName --
  *
  *    Handle a Setattr request by name.
  *
@@ -3037,18 +2953,13 @@ exit:
  *
  *-----------------------------------------------------------------------------
  */
-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;
@@ -3057,32 +2968,10 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
    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)) {
@@ -3098,7 +2987,7 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
       if (File_IsSymLink(localName)) {
          LOG(4, ("%s: pathname contains a symlink\n", __FUNCTION__));
          status = EINVAL;
-         goto exit_free;
+         goto exit;
       }
    }
 
@@ -3110,14 +2999,7 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
       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;
    }
 
    /*
@@ -3160,17 +3042,7 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
    }
 
    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)));
@@ -3202,13 +3074,77 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
       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__) */
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -3295,13 +3231,25 @@ HgfsServerScandir(char const *baseDir,      // IN: Directory to search in
             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;
       }
    }
@@ -3383,176 +3331,9 @@ HgfsServerScandir(char const *baseDir,      // IN: Directory to search in
 /*
  *-----------------------------------------------------------------------------
  *
- * 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.
@@ -3565,131 +3346,35 @@ HgfsServerOpen(HgfsInputParam *input)  // IN: Input params
  */
 
 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__)
@@ -3707,7 +3392,9 @@ HgfsServerRead(HgfsInputParam *input)  // IN: Input params
 
    MXUser_AcquireExclLock(session->fileIOLock);
 
-   if (!sequentialOpen) {
+   if (sequentialOpen) {
+      error = 0; // No error from seek
+   } else {
 #   ifdef linux
       {
          uint64 res;
@@ -3720,45 +3407,26 @@ HgfsServerRead(HgfsInputParam *input)  // IN: Input params
 #   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;
 }
 
@@ -3766,9 +3434,9 @@ error:
 /*
  *-----------------------------------------------------------------------------
  *
- * HgfsServerWrite --
+ * HgfsPlatformWriteFile --
  *
- *    Handle a Write request.
+ *    Performs actual writing data to a file.
  *
  * Results:
  *    Zero on success.
@@ -3781,143 +3449,36 @@ error:
  */
 
 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. */
@@ -3947,42 +3508,25 @@ HgfsServerWrite(HgfsInputParam *input)  // IN: Input params
       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;
 }
 
@@ -3990,9 +3534,9 @@ error:
 /*
  *-----------------------------------------------------------------------------
  *
- * HgfsServerSearchOpen --
+ * HgfsPlatformSearchDir --
  *
- *    Handle a "Search Open" request.
+ *    Handle platform specific logic needed to perform search open request.
  *
  * Results:
  *    Zero on success.
@@ -4005,87 +3549,17 @@ error:
  */
 
 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:
    {
@@ -4101,41 +3575,38 @@ HgfsServerSearchOpen(HgfsInputParam *input)  // IN: Input params
 
       /* 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;
    }
@@ -4152,38 +3623,21 @@ HgfsServerSearchOpen(HgfsInputParam *input)  // IN: Input params
                                           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;
 }
 
@@ -4191,13 +3645,12 @@ exit:
 /*
  *-----------------------------------------------------------------------------
  *
- * 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
@@ -4206,249 +3659,22 @@ exit:
  */
 
 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.
@@ -4461,125 +3687,16 @@ HgfsServerSearchRead(HgfsInputParam *input)  // IN: Input params
  */
 
 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;
 }
 
@@ -4587,9 +3704,13 @@ exit:
 /*
  *-----------------------------------------------------------------------------
  *
- * 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.
@@ -4602,62 +3723,40 @@ exit:
  */
 
 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.
@@ -4670,120 +3769,30 @@ exit:
  */
 
 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.
@@ -4796,106 +3805,41 @@ HgfsServerCreateDir(HgfsInputParam *input)  // IN: Input params
  */
 
 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
@@ -4904,322 +3848,54 @@ HgfsServerDeleteFile(HgfsInputParam *input)  // IN: Input params
  */
 
 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;
 }
 
@@ -5227,17 +3903,13 @@ HgfsServerRename(HgfsInputParam *input)  // IN: Input params
 /*
  *-----------------------------------------------------------------------------
  *
- * 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.
@@ -5250,282 +3922,59 @@ HgfsServerRename(HgfsInputParam *input)  // IN: Input params
  */
 
 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.
@@ -5538,202 +3987,18 @@ exit:
  */
 
 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;
 }
 
@@ -5890,32 +4155,11 @@ exit:
  */
 
 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;
 }
@@ -5981,39 +4225,6 @@ HgfsAckOplockBreak(ServerLockData *lockData, // IN: server lock info
 }
 #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__)
 /*
  *-----------------------------------------------------------------------------
index 1e2889bafd3631c6fb94f7b2a37e8ef5249ea0fa..3b17f2f92caccd93c82ca4c068ce4ac2c916fc46 100644 (file)
@@ -71,16 +71,16 @@ HSPU_GetReplyPacket(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
       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,
@@ -436,9 +436,9 @@ 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 ?
-            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;
diff --git a/open-vm-tools/lib/hgfsServer/hgfsServerParameters.c b/open-vm-tools/lib/hgfsServer/hgfsServerParameters.c
new file mode 100644 (file)
index 0000000..813cf00
--- /dev/null
@@ -0,0 +1,4819 @@
+/*********************************************************
+ * 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);
+}
index 73bb61e802201d66a15ea4a43570ea5d3e44918c..f974c5f63847cbfde654f6b8abb9af2e445dcdb0 100644 (file)
@@ -118,7 +118,6 @@ typedef enum {
    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.
     */
@@ -1663,6 +1662,10 @@ struct HgfsHeader {
 #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.
  */
@@ -1761,18 +1764,19 @@ HgfsIdentity;
 
 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. */
@@ -1781,24 +1785,23 @@ struct HgfsReplyCreateSession {
    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. */
 
index e95894d80d5d4840080b519224eb2bcec554116d..ef9096d5ef3edeea45f8e0c5bcf39ec19755b454 100644 (file)
@@ -80,11 +80,48 @@ struct timespec {
 #      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