Beispiel #1
0
Bool
StrUtil_StrToSizet(size_t *out,     // OUT: The output value
                   const char *str) // IN : String to parse
{
   char *ptr;

   ASSERT(out);
   ASSERT(str);

   errno = 0;
#if defined VM_X86_64
   ASSERT_ON_COMPILE(sizeof *out == sizeof(uint64));
#   if defined(_WIN32)
   *out = _strtoui64(str, &ptr, 0);
#   elif defined(__FreeBSD__)
   *out = strtouq(str, &ptr, 0);
#   else
   *out = strtoull(str, &ptr, 0);
#   endif
#else
   ASSERT_ON_COMPILE(sizeof *out == sizeof(uint32));
   *out = strtoul(str, &ptr, 0);
#endif

   return *ptr == '\0' && errno != ERANGE;
}
int
Posix_Open(const char *pathName,  // IN:
           int flags,             // IN:
           ...)                   // IN:
{
   char *path;
   mode_t mode = 0;
   int fd;

   if (!PosixConvertToCurrent(pathName, &path)) {
      return -1;
   }

   if ((flags & O_CREAT) != 0) {
      va_list a;

      /*
       * The FreeBSD tools compiler
       * (toolchain/lin32/gcc-4.1.2-5/bin/i686-freebsd5.0-gcc)
       * wants us to use va_arg(a, int) instead of va_arg(a, mode_t),
       * so oblige.  -- edward
       */

      va_start(a, flags);
      ASSERT_ON_COMPILE(sizeof (int) >= sizeof(mode_t));
      mode = va_arg(a, int);
      va_end(a);
   }
Beispiel #3
0
void
PhysTrack_Add(PhysTracker *tracker,
              MPN mpn)
{
   unsigned int p1;
   unsigned int p2;
   unsigned int p3;
   unsigned int pos;
   unsigned int bit;
   PhysTrackerL2 *dir2;
   PhysTrackerL3 *dir3;

   ASSERT(tracker);
   PHYSTRACK_MPN2IDX(mpn, p1, p2, p3);
   ASSERT(p1 < PHYSTRACK_L1_ENTRIES);

   dir2 = tracker->dir[p1];
   if (!dir2) { 
      // more efficient with page alloc
      ASSERT_ON_COMPILE(sizeof *dir2 == PAGE_SIZE);
      dir2 = HostIF_AllocPage();
      if (!dir2) { 
         PANIC();
      }
      memset(dir2, 0, sizeof *dir2);
      tracker->dir[p1] = dir2;
   }
   dir3 = PHYSTRACK_ALLOCL3(dir2, p2);
   PHYSTRACK_GETL3POS(p3, pos, bit);
   if (dir3->bits[pos] & bit) {
      PANIC();
   }
   dir3->bits[pos] |= bit;
}
/**
 * @brief New timer request from monitor
 * @param monTimer Monitor timer
 * @param when64 Timer target value
 */
void
MonitorTimer_Request(struct MonTimer *monTimer,
		     uint64 when64)
{
	if (when64) {
		ktime_t kt;

		/*
		 * Simple conversion, assuming RATE64 is 1e+9
		 */
		kt = ns_to_ktime(when64);
		ASSERT_ON_COMPILE(MVP_TIMER_RATE64 == 1000000000);

		/*
		 * Start the timer.  If it was already active, it will remove
		 * the previous expiration time.  Linux handles correctly timer
		 * with deadline in the past, and forces a safety minimal delta
		 * for closer timer deadlines.
		 */
		hrtimer_start(&monTimer->timer, kt, HRTIMER_MODE_ABS);
	} else {
		/*
		 * Cancel a pending request. If there is none, this will do
		 * nothing.  If it's too late, monitor tolerance will forgive
		 * us.
		 */
		hrtimer_cancel(&monTimer->timer);
	}
}
static INLINE void *
VThreadBaseGetNative(void)
{
   /* All thread types must fit into a uintptr_t so we can set them atomically. */
#ifdef _WIN32
   /*
    * On Windows, use a ThreadId instead of the thread handle, to avoid
    * holding a reference that is hard to clean up.
    */
   ASSERT_ON_COMPILE(sizeof (DWORD) <= sizeof (void*));
   return (void *)(uintptr_t)GetCurrentThreadId();
#else
   ASSERT_ON_COMPILE(sizeof (pthread_t) <= sizeof (void*));
   return (void *)(uintptr_t)pthread_self();
#endif
}
Beispiel #6
0
static int
MXUserTimedDown(NativeSemaphore *sema,  // IN:
                uint32 msecWait,        // IN:
                Bool *downOccurred)     // OUT:
{
   uint64 nsecWait;
   VmTimeType before;
   kern_return_t err;

   ASSERT_ON_COMPILE(KERN_SUCCESS == 0);

   /*
    * Work in nanoseconds. Time the semaphore_timedwait operation in case
    * it is interrupted (KERN_ABORT). If it is, determine how much time is
    * necessary to fulfill the specified wait time and retry with a new
    * and appropriate timeout.
    */

   nsecWait = 1000000ULL * (uint64) msecWait;
   before = Hostinfo_SystemTimerNS();

   do {
      VmTimeType after;
      mach_timespec_t ts;

      ts.tv_sec = nsecWait / MXUSER_A_BILLION;
      ts.tv_nsec = nsecWait % MXUSER_A_BILLION;

      err = semaphore_timedwait(*sema, ts);
      after = Hostinfo_SystemTimerNS();

      if (err == KERN_SUCCESS) {
         *downOccurred = TRUE;
      } else {
         *downOccurred = FALSE;

         if (err == KERN_OPERATION_TIMED_OUT) {
            /* Really timed out; no down occurred, no error */
            err = KERN_SUCCESS;
         } else {
            if (err == KERN_ABORTED) {
               VmTimeType duration = after - before;

               if (duration < nsecWait) {
                  nsecWait -= duration;

                  before = after;
               } else {
                  err = KERN_SUCCESS;  // "timed out" anyway... no error
               }
            }
         }
      }
   } while (nsecWait && (err == KERN_ABORTED));

   return err;
}
Beispiel #7
0
static AuthorizationRef
IdAuthCreate(void)
{
   /*
    * Bug 195868: If thread credentials are in use, we need to fork.
    * Otherwise, avoid forking, as it breaks Apple's detection of
    * whether the calling process is a GUI process.
    *
    * This is needed because AuthorizationRefs created by GUI
    * processes can be passed to non-GUI processes to allow them to
    * prompt for authentication with a dialog that automatically
    * steals focus from the current GUI app.  (This is how the Mac UI
    * and VMX work today.)
    *
    * TODO: How should we handle single-threaded apps where uid !=
    * euid or gid != egid?  Some callers may expect us to check
    * against euid, others may expect us to check against uid.
    */

   uid_t thread_uid;
   gid_t thread_gid;
   int ret;

   ret = syscall(SYS_gettid, &thread_uid, &thread_gid);

   if (ret != -1) {
      /*
       * We have per-thread UIDs in use, so Apple's authorization
       * APIs don't work.  Fork so we can use them.
       */

      return IdAuthCreateWithFork();
   } else {
      if (errno != ESRCH) {
         Warning("%s: gettid failed, error %d.\n", __func__, errno);

         return NULL;
      } else {
          // Per-thread identities are not in use in this thread.
         AuthorizationRef auth;
         OSStatus ret;

         ret = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
                                   kAuthorizationFlagDefaults, &auth);

         if (ret == errAuthorizationSuccess) {
            return auth;
         } else {
            ASSERT_ON_COMPILE(sizeof ret == sizeof (int32));
            Warning("%s: AuthorizationCreate failed, error %d.\n",
                    __func__, (int32)ret);

            return NULL;
         }
      }
   }
}
Beispiel #8
0
static bool_t
DynXdrPutLong(XDR *xdrs,                    // IN/OUT
              DYNXDR_CONST DYNXDR_LONG *lp) // IN
{
   int32 out;
   DynXdrData *priv = (DynXdrData *) xdrs->x_private;

#ifdef __APPLE__
   ASSERT_ON_COMPILE(sizeof *lp <= sizeof (int32));
#endif
   out = htonl((int32)*lp);
   return DynBuf_Append(&priv->data, &out, sizeof out);
}
void
MonitorTimer_Request(MonTimer *monTimer, uint64 when64)
{
    if (when64) {
        ktime_t kt;

        kt = ns_to_ktime(when64);
        ASSERT_ON_COMPILE(MVP_TIMER_RATE64 == 1000000000);

        hrtimer_start(&monTimer->timer, kt, HRTIMER_MODE_ABS);
    } else {
        hrtimer_cancel(&monTimer->timer);
    }
}
/**
 * Sends a command to the Sandbox daemon's MMC driver.
 *
 * @param mmc	Pointer to device
 * @param cmd	Pointer to device command
 * @param data	Pointer to device data
 * Result == 0 -> success
 * Result != 0 -> failure
 */
static int sandbox_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
				struct mmc_data *data)
{
	struct doorbell_t *db = sandbox_get_doorbell();
	struct doorbell_command_t *dbc = sandbox_get_doorbell_command();
	const unsigned is_sandbox_mem = (data != NULL &&
					sandbox_in_shared_memory(data->dest));
	const unsigned device = get_device(mmc);

	db->mmc[device].mmc_capacity = mmc->capacity;
	ASSERT_ON_COMPILE(ARRAY_SIZE(db->mmc) == 2);
	dbc->device_id = device == 0 ? SB_MMC0 : SB_MMC1;
	dbc->command_data[0] = cmd->cmdidx;
	dbc->command_data[1] = cmd->resp_type;
	dbc->command_data[2] = cmd->cmdarg;
	dbc->command_data[3] = cmd->flags;
	dbc->command_data[4] = 0;
	dbc->command_data[5] = 0;
	dbc->command_data[6] = 0;
	dbc->command_data[7] = 0;

	if (data != NULL) {
		/*
		 * If the data buffer is not in shared memory, then
		 * it's likely a stack variable in the MMC driver.
		 * The sandbox-daemon does not have access to that
		 * memory, so use a local buffer for the transfer.
		 */
		dbc->command_data[4] = (__u32)(uintptr_t)data->dest;
		dbc->command_data[5] = data->flags;
		dbc->command_data[6] = data->blocks;
		dbc->command_data[7] = data->blocksize;
		if (!is_sandbox_mem)
			dbc->command_data[4] = (__u32)(uintptr_t)dbc->dbc_buf;
	}

	sandbox_ring_doorbell();

	if (data != NULL && !is_sandbox_mem)
		memcpy(data->dest, dbc->dbc_buf,
		       data->blocks * data->blocksize);

	cmd->response[0] = dbc->command_data[8];
	cmd->response[1] = dbc->command_data[9];
	cmd->response[2] = dbc->command_data[10];
	cmd->response[3] = dbc->command_data[11];
	return dbc->result;
}
Beispiel #11
0
char *
print_time_local_short(uint32 time)
{
   char str[128];
   struct tm *ts;
   time_t t = time;

   ASSERT_ON_COMPILE(sizeof t == sizeof(time_t));

   memset(str, 0, sizeof str);
   ts = localtime(&t);
   if (ts) {
      strftime(str, sizeof str, "%d %b %T", ts);
   }
   return safe_strdup(str);
}
Beispiel #12
0
void
blockstore_write_headers(struct blockstore *bs)
{
   btc_block_header *buf;
   struct blockentry *e;
   size_t numWritten;
   uint32 count;
   uint32 numhdr;
   int res;

   e = bs->best_chain;
   count = 0;
   while (e && e->written == 0) {
      e = e->prev;
      count++;
   }
   ASSERT(count < 2048);
   numhdr = count;
   if (count == 0) {
      return;
   }

   buf = safe_malloc(count * sizeof *buf);

   e = bs->best_chain;
   while (e && e->written == 0) {
      count--;
      memcpy(buf + count, &e->header, sizeof e->header);
      e->written = 1;
      e = e->prev;
   }

   ASSERT(count == 0);
   ASSERT(bs->blockSet);
   ASSERT_ON_COMPILE(sizeof *buf == 80);

   res = file_pwrite(bs->blockSet->desc, bs->blockSet->filesize,
                     buf, numhdr * sizeof *buf, &numWritten);
   free(buf);

   if (res != 0 || numWritten != numhdr * sizeof *buf) {
      Warning(LGPFX" failed to write %u block entries.\n", numhdr);
      return;
   }

   bs->blockSet->filesize += numWritten;
}
Beispiel #13
0
char *
print_time_local(uint32 time,
                 const char *fmt)
{
   char str[128];
   struct tm *ts;
   time_t t = time;

   ASSERT_ON_COMPILE(sizeof t == sizeof(time_t));

   memset(str, 0, sizeof str);
   ts = localtime(&t);
   if (ts) {
      strftime(str, sizeof str, fmt, ts);
   }
   return safe_strdup(str);
}
Beispiel #14
0
void
ToolsCore_DumpState(ToolsServiceState *state)
{
   guint i;
   const char *providerStates[] = {
      "idle",
      "active",
      "error"
   };

   ASSERT_ON_COMPILE(ARRAYSIZE(providerStates) == TOOLS_PROVIDER_MAX);

   if (!g_main_loop_is_running(state->ctx.mainLoop)) {
      ToolsCore_LogState(TOOLS_STATE_LOG_ROOT,
                         "VM Tools Service '%s': not running.\n",
                         state->name);
      return;
   }

   ToolsCore_LogState(TOOLS_STATE_LOG_ROOT,
                      "VM Tools Service '%s':\n",
                      state->name);
   ToolsCore_LogState(TOOLS_STATE_LOG_CONTAINER,
                      "Plugin path: %s\n",
                      state->pluginPath);

   for (i = 0; i < state->providers->len; i++) {
      ToolsAppProviderReg *prov = &g_array_index(state->providers,
                                                 ToolsAppProviderReg,
                                                 i);
      ToolsCore_LogState(TOOLS_STATE_LOG_CONTAINER,
                         "App provider: %s (%s)\n",
                         prov->prov->name,
                         providerStates[prov->state]);
      if (prov->prov->dumpState != NULL) {
         prov->prov->dumpState(&state->ctx, prov->prov, NULL);
      }
   }

   ToolsCore_DumpPluginInfo(state);

   g_signal_emit_by_name(state->ctx.serviceObj,
                         TOOLS_CORE_SIG_DUMP_STATE,
                         &state->ctx);
}
Beispiel #15
0
static INLINE_SINGLE_CALLER PhysTrackerL3 *
PhysTrackAllocL3(PhysTrackerL2 *dir2,
                 unsigned int p2)
{
   PhysTrackerL3 *dir3;

   dir3 = dir2->dir[p2];
   if (!dir3) {
      ASSERT_ON_COMPILE(sizeof *dir3 == PAGE_SIZE);
      dir3 = HostIF_AllocPage();
      if (!dir3) {
         PANIC();
      }
      memset(dir3, 0, sizeof *dir3);
      dir2->dir[p2] = dir3;
   }
   return dir3;
}
Beispiel #16
0
Bool
VSockAddr_SocketContextStream(uint32 cid)  // IN
{
   uint32 i;
   VMCIId nonSocketContexts[] = {
      VMCI_HYPERVISOR_CONTEXT_ID,
      VMCI_WELL_KNOWN_CONTEXT_ID,
   };

   ASSERT_ON_COMPILE(sizeof cid == sizeof *nonSocketContexts);

   for (i = 0; i < ARRAYSIZE(nonSocketContexts); i++) {
      if (cid == nonSocketContexts[i]) {
         return FALSE;
      }
   }

   return TRUE;
}
int sandbox_mmc_init(int verbose)
{
	struct doorbell_t *db = sandbox_get_doorbell();
	unsigned i;

	ASSERT_ON_COMPILE(ARRAY_SIZE(db->mmc) ==
			  ARRAY_SIZE(mmc_dev));

	if (!db->mmc[0].mmc_enabled)	/* No MMC devices. */
		return -ENODEV;

	for (i = 0; i < ARRAY_SIZE(db->mmc); ++i) {
		if (db->mmc[i].mmc_enabled) {
			/* Only device 0 is a removable device */
			register_mmc_device(&mmc_dev[i]);
			mmc_dev[1].block_dev.removable = i == 0;
		}
	}
	return 0;
}
Beispiel #18
0
int
HgfsConvertFromNtTimeNsec(struct timespec *unixTime, // OUT: Time in UNIX format
			  uint64 ntTime) // IN: Time in Windows NT format
{
#if !defined(VM_X86_64) && !defined(__arm__)
   uint32 sec;
   uint32 nsec;

   ASSERT(unixTime);
   /* We assume that time_t is 32bit */
   ASSERT_ON_COMPILE(sizeof (unixTime->tv_sec) == 4);

   /* Cap NT time values that are outside of Unix time's range */

   if (ntTime >= UNIX_S32_MAX) {
      unixTime->tv_sec = 0x7FFFFFFF;
      unixTime->tv_nsec = 0;
      return 1;
   }
#else
   ASSERT(unixTime);
#endif

   if (ntTime < UNIX_EPOCH) {
      unixTime->tv_sec = 0;
      unixTime->tv_nsec = 0;
      return -1;
   }

#if !defined(VM_X86_64) && !defined(__arm__)
   Div643232(ntTime - UNIX_EPOCH, 10000000, &sec, &nsec);
   unixTime->tv_sec = sec;
   unixTime->tv_nsec = nsec * 100;
#else
   unixTime->tv_sec = (ntTime - UNIX_EPOCH) / 10000000;
   unixTime->tv_nsec = ((ntTime - UNIX_EPOCH) % 10000000) * 100;
#endif

   return 0;
}
int
VMCIDatagram_Dispatch(VMCIId contextID,
                      VMCIDatagram *dg,
                      Bool fromGuest)
{
   int retval;
   VMCIRoute route;

   ASSERT(dg);
   ASSERT_ON_COMPILE(sizeof(VMCIDatagram) == 24);

   if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
      VMCI_DEBUG_LOG(4, (LGPFX"Payload (size=%"FMT64"u bytes) too big to "
                         "send.\n", dg->payloadSize));
      return VMCI_ERROR_INVALID_ARGS;
   }

   retval = VMCI_Route(&dg->src, &dg->dst, fromGuest, &route);
   if (retval < VMCI_SUCCESS) {
      VMCI_DEBUG_LOG(4, (LGPFX"Failed to route datagram (src=0x%x, dst=0x%x, "
                         "err=%d)\n.", dg->src.context, dg->dst.context,
                         retval));
      return retval;
   }

   if (VMCI_ROUTE_AS_HOST == route) {
      if (VMCI_INVALID_ID == contextID) {
         contextID = VMCI_HOST_CONTEXT_ID;
      }
      return VMCIDatagramDispatchAsHost(contextID, dg);
   }

   if (VMCI_ROUTE_AS_GUEST == route) {
      return VMCIDatagramDispatchAsGuest(dg);
   }

   VMCI_WARNING((LGPFX"Unknown route (%d) for datagram.\n", route));
   return VMCI_ERROR_DST_UNREACHABLE;
}
/**
 * Returns the device number of 'dev'.
 *
 * @param dev	Pointer into array 'mmc_dev'
 * Result == 0 -> &mmc_dev[0]
 * Result == 1 -> &mmc_dev[1]
 */
static unsigned get_device(const struct mmc *dev)
{
	ASSERT_ON_COMPILE(ARRAY_SIZE(mmc_dev) == 2);
	return dev == &mmc_dev[1];
}
gboolean
ToolsDaemonHgfsImpersonated(RpcInData *data) // IN
{
   VixError err;
   size_t hgfsPacketSize = 0;
   size_t hgfsReplySize = 0;
   const char *origArgs = data->args;
   Bool impersonatingVMWareUser = FALSE;
   char *credentialTypeStr = NULL;
   char *obfuscatedNamePassword = NULL;
   void *userToken = NULL;
   int actualUsed;
#define STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING 20
#define OTHER_TEXT_SIZE 4                /* strlen(space zero space quote) */
   static char resultPacket[STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
                              + OTHER_TEXT_SIZE
                              + HGFS_LARGE_PACKET_MAX];
   char *hgfsReplyPacket = resultPacket
                             + STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
                             + OTHER_TEXT_SIZE;

   Debug(">ToolsDaemonHgfsImpersonated\n");

   err = VIX_OK;

   /*
    * We assume VixError is 64 bits.  If it changes, we need
    * to adjust STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING.
    *
    * There isn't much point trying to return gracefully
    * if sizeof(VixError) is larger than we expected: we didn't
    * allocate enough space to actually represent the error!
    * So we're stuck.  Panic at this point.
    */
   ASSERT_ON_COMPILE(sizeof (uint64) == sizeof err);

   /*
    * Get the authentication information.
    */
   credentialTypeStr = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
   obfuscatedNamePassword = ToolsDaemonTcloGetQuotedString(data->args, &data->args);

   /*
    * Make sure we are passed the correct arguments.
    */
   if ((NULL == credentialTypeStr) || (NULL == obfuscatedNamePassword)) {
      err = VIX_E_INVALID_ARG;
      goto abort;
   }

   /*
    * Skip over our token that is right before the HGFS packet.
    * This makes ToolsDaemonTcloGetQuotedString parsing predictable,
    * since it will try to eat trailing spaces after a quoted string,
    * and the HGFS packet might begin with a space.
    */
   if (((data->args - origArgs) >= data->argsSize) || ('#' != *(data->args))) {
      /*
       * Buffer too small or we got an unexpected token.
       */
      err = VIX_E_FAIL;
      goto abort;
   }
   data->args++;
   
   /*
    * At this point args points to the HGFS packet.
    * If we're pointing beyond the end of the buffer, we'll
    * get a negative HGFS packet length and abort.
    */
   hgfsPacketSize = data->argsSize - (data->args - origArgs);
   if (hgfsPacketSize <= 0) {
      err = VIX_E_FAIL;
      goto abort;
   }
   
   if (thisProcessRunsAsRoot) {
      impersonatingVMWareUser = VixToolsImpersonateUserImpl(credentialTypeStr,
                                                            VIX_USER_CREDENTIAL_NONE,
                                                            obfuscatedNamePassword,
                                                            &userToken);
      if (!impersonatingVMWareUser) {
         err = VIX_E_GUEST_USER_PERMISSIONS;
         goto abort;
      }
   }

   /*
    * Impersonation was okay, so let's give our packet to
    * the HGFS server and forward the reply packet back.
    */
   hgfsReplySize = sizeof resultPacket - (hgfsReplyPacket - resultPacket);
   HgfsServerManager_ProcessPacket(&gFoundryHgfsBkdrConn, // hgfs server connection
                                   data->args,            // packet in buf
                                   hgfsPacketSize,        // packet in size
                                   hgfsReplyPacket,       // packet out buf
                                   &hgfsReplySize);       // reply buf/data size

abort:
   if (impersonatingVMWareUser) {
      VixToolsUnimpersonateUser(userToken);
   }
   VixToolsLogoutUser(userToken);

   /*
    * These were allocated by ToolsDaemonTcloGetQuotedString.
    */
   free(credentialTypeStr);
   free(obfuscatedNamePassword);

   data->result = resultPacket;
   data->resultLen = STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
                        + OTHER_TEXT_SIZE
                        + hgfsReplySize;
   
   /*
    * Render the foundry error codes into the buffer.
    */
   actualUsed = Str_Snprintf(resultPacket,
                             STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
                               + OTHER_TEXT_SIZE,
                             "%"FMT64"d 0 ",
                             err);
                             
   if (actualUsed < 0) {
      /*
       * We computed our string length wrong!  This should never happen.
       * But if it does, let's try to recover gracefully.  The "1" in
       * the string below is VIX_E_FAIL.  We don't try to use %d since
       * we couldn't even do that right the first time around.
       * That hash is needed for the parser on the other
       * end to stop before the HGFS packet, since the HGFS packet
       * can contain a space (and the parser can eat trailing spaces).
       */
      ASSERT(0);
      actualUsed = Str_Snprintf(resultPacket,
                                STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING,
                                "1 0 #");
      data->resultLen = actualUsed;
   } else {
      /*
       * We computed the string length correctly.  Great!
       *
       * We allocated enough space to cover a large 64 bit number
       * for VixError.  Chances are we didn't use all that space.
       * Instead, pad it with whitespace so the text parser can skip
       * over it.
       */
      memset(resultPacket + actualUsed,
             ' ',
             STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
                                 + OTHER_TEXT_SIZE
                                 - actualUsed);   
      /*
       * Put a hash right before the HGFS packet.
       * So the buffer will look something like this:
       * "0 0                        #" followed by the HGFS packet.
       */
      resultPacket[STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
                    + OTHER_TEXT_SIZE - 1] = '#';
   }

   Debug("<<<ToolsDaemonHgfsImpersonated\n");
   return TRUE;
} // ToolsDaemonHgfsImpersonated