1
/*********************************************************
2
* Copyright (C) 2005 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License as published
6
* by the Free Software Foundation version 2.1 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
11
* License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17
*********************************************************/
22
* Implementation of bora/lib/public/dnd.h functions that are common to
23
* Linux and Windows platforms
38
#include "cpNameUtil.h"
39
#include "hgfsEscape.h"
40
#include "hgfsServerPolicy.h"
41
#include "hgfsVirtualDir.h"
42
#include "unicodeOperations.h"
45
#define LOGLEVEL_MODULE dnd
46
#include "loglevel_user.h"
48
#define WIN_DIRSEPC '\\'
49
#define WIN_DIRSEPS "\\"
51
static ConstUnicode DnDCreateRootStagingDirectory(void);
54
*-----------------------------------------------------------------------------
56
* DnD_CreateStagingDirectory --
58
* Generate a unique staging directory name, create the directory, and
59
* return the name. The caller is responsible for freeing the returned
62
* Our staging directory structure is comprised of a "root" staging
63
* directory that itself contains multiple staging directories that are
64
* intended to be used on a per-DnD and per-user basis. That is, each DnD
65
* by a particular user will have its own staging directory within the root.
66
* Sometimes these directories are emptied after the DnD (either because it
67
* was cancelled or the destination application told us to), and we resuse
68
* any empty directories that we can. This function will return a directory
69
* to be reused if possible and fall back on creating a new one if
73
* A string containing the newly created name, or NULL on failure.
76
* A directory is created
78
*-----------------------------------------------------------------------------
82
DnD_CreateStagingDirectory(void)
85
Unicode *stagingDirList;
92
* Make sure the root staging directory is created with the correct
95
root = DnDCreateRootStagingDirectory();
100
/* Look for an existing, empty staging directory */
101
numStagingDirs = File_ListDirectory(root, &stagingDirList);
102
if (numStagingDirs < 0) {
106
for (i = 0; i < numStagingDirs; i++) {
110
stagingDir = Unicode_Append(root, stagingDirList[i]);
112
if (File_IsEmptyDirectory(stagingDir) &&
113
DnDStagingDirectoryUsable(stagingDir)) {
114
ret = Unicode_Append(stagingDir, DIRSEPS);
116
* We can use this directory. Make sure to continue to loop
117
* so we don't leak the remaining stagindDirList[i]s.
122
Unicode_Free(stagingDir);
126
Unicode_FreeList(stagingDirList, numStagingDirs);
128
/* Only create a directory if we didn't find one above. */
132
context = Random_QuickSeed((unsigned)time(NULL));
134
for (i = 0; i < 10; i++) {
137
/* Each staging directory is given a random name. */
139
temp = Unicode_Format("%08x%c", Random_Quick(context), DIRSEPC);
140
ASSERT_MEM_ALLOC(temp);
141
ret = Unicode_Append(root, temp);
144
if (File_CreateDirectory(ret) &&
145
DnDSetPermissionsOnStagingDir(ret)) {
155
if (!found && ret != NULL) {
165
*-----------------------------------------------------------------------------
167
* DnD_DeleteStagingFiles --
169
* Attempts to delete all files in the staging directory. This does not
170
* delete the directory itself.
173
* TRUE if all files were deleted. FALSE if there was an error.
178
*-----------------------------------------------------------------------------
182
DnD_DeleteStagingFiles(ConstUnicode stagingDir, // IN:
183
Bool onReboot) // IN:
189
if (!File_Exists(stagingDir)) {
190
/* The stagingDir is already gone. */
194
if (!File_IsDirectory(stagingDir)) {
199
if (File_UnlinkDelayed(stagingDir)) {
206
Unicode *fileList = NULL;
208
/* get list of files in current directory */
209
numFiles = File_ListDirectory(stagingDir, &fileList);
211
if (numFiles == -1) {
215
/* delete everything in the directory */
216
base = Unicode_Append(stagingDir, DIRSEPS);
218
for (i = 0; i < numFiles; i++) {
221
curPath = Unicode_Append(base, fileList[i]);
223
if (File_IsDirectory(curPath)) {
224
if (!File_DeleteDirectoryTree(curPath)) {
228
if (File_Unlink(curPath) == -1) {
233
Unicode_Free(curPath);
243
*----------------------------------------------------------------------------
245
* DnDCreateRootStagingDirectory --
247
* Checks if the root staging directory exists with the correct permissions,
248
* or creates it if necessary.
251
* The path of the root directory on success, NULL on failure.
256
*----------------------------------------------------------------------------
260
DnDCreateRootStagingDirectory(void)
265
* DnD_GetFileRoot() gives us a pointer to a static string, so there's no
266
* need to free anything.
268
root = DnD_GetFileRoot();
273
if (File_Exists(root)) {
274
if (!DnDRootDirUsable(root) &&
275
!DnDSetPermissionsOnRootDir(root)) {
277
* The directory already exists and its permissions are wrong and
278
* cannot be set, so there's not much we can do.
283
if (!File_CreateDirectory(root) ||
284
!DnDSetPermissionsOnRootDir(root)) {
285
/* We couldn't create the directory or set the permissions. */
295
*----------------------------------------------------------------------------
297
* DnDPrependFileRoot --
299
* Given a buffer of '\0' delimited filenames, this prepends the file root
300
* to each one and uses delimiter for delimiting the output buffer. The
301
* buffer pointed to by *src will be freed and *src will point to a new
302
* buffer containing the results. *srcSize is set to the size of the new
303
* buffer, not including the NUL-terminator.
305
* The logic here and in the called functions appears to be UTF8-safe.
308
* TRUE on success, FALSE on failure.
311
* *src will be freed, and a new buffer will be allocated. This buffer must
312
* be freed by the caller.
314
*----------------------------------------------------------------------------
318
DnDPrependFileRoot(ConstUnicode fileRoot, // IN : file root to append
319
char delimiter, // IN : delimiter for output buffer
320
char **src, // IN/OUT: NUL-delimited list of paths
321
size_t *srcSize) // IN/OUT: size of list
323
char *newData = NULL;
324
size_t newDataLen = 0;
325
Bool firstPass = TRUE;
337
rootLen = strlen(fileRoot);
340
* To prevent CPName_GetComponent() errors, we set begin to the first
341
* Non-NUL character in *src, and end to the last NUL character in *src. We
342
* assume that the components are delimited with single NUL characters; if
343
* that is not true, CPName_GetComponent() will fail.
346
for (begin = *src; *begin == '\0'; begin++)
348
end = CPNameUtil_Strrchr(*src, *srcSize, '\0');
350
/* Get the length of this component, and a pointer to the next */
351
while ((len = CPName_GetComponent(begin, end, &next)) != 0) {
352
size_t origNewDataLen = newDataLen;
356
Log("%s: error getting next component\n", __FUNCTION__);
365
* Append this component to our list: allocate one more for NUL on first
366
* pass and delimiter on all other passes.
369
escapedLen = HgfsEscape_GetSize(begin, len);
370
if (escapedLen < 0) {
371
Log("%s: error calculating buffer size\n", __FUNCTION__);
373
} else if (0 == escapedLen) {
374
newDataLen += rootLen + len + 1;
375
newData = (char *)Util_SafeRealloc(newData, newDataLen);
378
ASSERT(origNewDataLen > 0);
379
newData[origNewDataLen - 1] = delimiter;
381
memcpy(newData + origNewDataLen, fileRoot, rootLen);
382
memcpy(newData + origNewDataLen + rootLen, begin, len);
384
newDataLen += rootLen + 1;
385
newData = (char *)Util_SafeRealloc(newData, newDataLen);
388
ASSERT(origNewDataLen > 0);
389
newData[origNewDataLen - 1] = delimiter;
391
memcpy(newData + origNewDataLen, fileRoot, rootLen);
392
HgfsEscape_Do(begin, len, escapedLen, newData + origNewDataLen + rootLen);
394
newData[newDataLen - 1] = '\0';
402
/* Not including NUL terminator */
403
*srcSize = newDataLen - 1;
409
*----------------------------------------------------------------------------
411
* DnD_LegacyConvertToCPName --
413
* Converts paths received from older tools that do not send data in CPName
414
* format across the backdoor. Older tools send paths in Windows format so
415
* this implementation must always convert from Windows path to CPName path,
416
* regardless of the platform we are running on.
418
* The logic here and in the called functions appears to be UTF8-safe.
421
* On success, returns the number of bytes used in the cross-platform name,
422
* NOT including the final terminating NUL character. On failure, returns
428
*----------------------------------------------------------------------------
432
DnD_LegacyConvertToCPName(const char *nameIn, // IN: Buffer to convert
433
size_t bufOutSize, // IN: Size of output buffer
434
char *bufOut) // OUT: Output buffer
436
const char partialName[] = HGFS_SERVER_POLICY_ROOT_SHARE_NAME;
437
const size_t partialNameLen = HGFS_STR_LEN(HGFS_SERVER_POLICY_ROOT_SHARE_NAME);
438
const char *partialNameSuffix = "";
439
size_t partialNameSuffixLen;
449
* Create the full name. Note that Str_Asprintf should not be
450
* used here as it uses FormatMessages which interprets 'data', a UTF-8
451
* string, as a string in the current locale giving wrong results.
455
* Is this file path a UNC path?
457
if (nameIn[0] == WIN_DIRSEPC && nameIn[1] == WIN_DIRSEPC) {
458
partialNameSuffix = WIN_DIRSEPS HGFS_UNC_DIR_NAME WIN_DIRSEPS;
459
partialNameSuffixLen = HGFS_STR_LEN(WIN_DIRSEPS) +
460
HGFS_STR_LEN(HGFS_UNC_DIR_NAME) +
461
HGFS_STR_LEN(WIN_DIRSEPS);
463
partialNameSuffix = WIN_DIRSEPS HGFS_DRIVE_DIR_NAME WIN_DIRSEPS;
464
partialNameSuffixLen = HGFS_STR_LEN(WIN_DIRSEPS) +
465
HGFS_STR_LEN(HGFS_DRIVE_DIR_NAME) +
466
HGFS_STR_LEN(WIN_DIRSEPS);
469
/* Skip any path separators at the beginning of the input string */
470
while (*nameIn == WIN_DIRSEPC) {
474
nameSize = strlen(nameIn);
475
fullNameSize = partialNameLen + partialNameSuffixLen + nameSize;
476
fullName = (char *)Util_SafeMalloc(fullNameSize + 1);
478
memcpy(fullName, partialName, partialNameLen);
479
memcpy(fullName + partialNameLen, partialNameSuffix, partialNameSuffixLen);
480
memcpy(fullName + partialNameLen + partialNameSuffixLen, nameIn, nameSize);
481
fullName[fullNameSize] = '\0';
483
LOG(4, ("%s: generated name is \"%s\"\n", __FUNCTION__, fullName));
486
* CPName_ConvertTo implementation is performed here without calling any
487
* CPName_ functions. This is safer since those functions might change, but
488
* the legacy behavior we are special casing here will not.
492
char const *winNameIn = fullName;
493
char const *origOut = bufOut;
494
char const *endOut = bufOut + bufOutSize;
495
char const pathSep = WIN_DIRSEPC;
498
/* Skip any path separators at the beginning of the input string */
499
while (*winNameIn == pathSep) {
504
* Copy the string to the output buf, converting all path separators into
505
* '\0' and ignoring the specified characters.
508
for (; *winNameIn != '\0' && bufOut < endOut; winNameIn++) {
510
char *currIgnore = ignores;
513
while (*currIgnore != '\0') {
514
if (*winNameIn == *currIgnore) {
522
*bufOut = (*winNameIn == pathSep) ? '\0' : *winNameIn;
526
*bufOut = (*winNameIn == pathSep) ? '\0' : *winNameIn;
532
* NUL terminate. XXX This should go away.
534
* When we get rid of NUL termination here, this test should
535
* also change to "if (*winNameIn != '\0')".
538
if (bufOut == endOut) {
544
/* Path name size should not require more than 4 bytes. */
545
ASSERT((bufOut - origOut) <= 0xFFFFFFFF);
547
/* If there were any trailing path separators, dont count them [krishnan] */
548
result = (int)(bufOut - origOut);
549
while ((result >= 1) && (origOut[result - 1] == 0)) {
554
* Make exception and call CPName_Print() here, since it's only for
558
LOG(4, ("%s: CPName is \"%s\"\n", __FUNCTION__,
559
CPName_Print(origOut, result)));
570
*-----------------------------------------------------------------------------
572
* DnD_CPNameListToDynBufArray --
574
* Export CPName file list from binary buffer to DynBufArray.
577
* TRUE if success, FALSE otherwise.
580
* Memory may allocated for DynBufArray if success.
582
*-----------------------------------------------------------------------------
586
DnD_CPNameListToDynBufArray(char *fileList, // IN: CPName format
587
size_t listSize, // IN
588
DynBufArray *dynBufArray) // OUT
598
r.unreadLen = listSize;
600
DynBufArray_Init(dynBufArray, 0);
602
while (r.unreadLen > 0) {
604
if (!DnDReadBuffer(&r, &pathLen, sizeof pathLen) ||
605
(pathLen > r.unreadLen) ||
606
!DynBuf_Append(&buf, r.pos, pathLen)) {
610
if (!DnDSlideBuffer(&r, pathLen)) {
614
if (!DynBufArray_Push(dynBufArray, buf)) {
621
DynBuf_Destroy(&buf);
623
count = DynBufArray_Count(dynBufArray);
624
for (i = 0; i < count; i++) {
625
DynBuf *b = DynArray_AddressOf(dynBufArray, i);
628
DynBufArray_SetCount(dynBufArray, 0);
629
DynBufArray_Destroy(dynBufArray);
635
*-----------------------------------------------------------------------------
637
* DnD_GetLastDirName --
639
* Try to get last directory name from a full path name.
642
* The allocated Unicode string, or NULL on failure.
647
*-----------------------------------------------------------------------------
651
DnD_GetLastDirName(ConstUnicode str) // IN
653
size_t end = strlen(str);
657
if (end != 0 && DIRSEPC == str[end - 1]) {
667
while (start && DIRSEPC != str[start - 1]) {
671
/* There should be at lease 1 DIRSEPC before end. */
677
return Unicode_AllocWithLength(str + start, res, STRING_ENCODING_UTF8);
681
/* Transport layer big buffer support functions. */
684
*-----------------------------------------------------------------------------
686
* DnD_TransportBufInit --
688
* Initialize transport layer buffer with DnD message.
694
* Buffer memory is allocated.
696
*-----------------------------------------------------------------------------
700
DnD_TransportBufInit(DnDTransportBuffer *buf, // OUT
702
size_t msgSize, // IN
706
ASSERT(msgSize <= DNDMSG_MAX_ARGSZ);
709
buf->buffer = Util_SafeMalloc(msgSize);
710
memcpy(buf->buffer, msg, msgSize);
711
buf->seqNum = seqNum;
712
buf->totalSize = msgSize;
718
*-----------------------------------------------------------------------------
720
* DnD_TransportBufReset --
722
* Reset transport layer buffer.
730
*-----------------------------------------------------------------------------
734
DnD_TransportBufReset(DnDTransportBuffer *buf) // IN/OUT
744
buf->lastUpdateTime = 0;
749
*-----------------------------------------------------------------------------
751
* DnD_TransportBufGetPacket --
753
* Get a transport layer packet from transport layer buffer.
756
* Transport layer packet size, or 0 if failed.
759
* Memory may be allocated for packet.
761
*-----------------------------------------------------------------------------
765
DnD_TransportBufGetPacket(DnDTransportBuffer *buf, // IN/OUT
766
DnDTransportPacketHeader **packet) // OUT
772
if (buf->totalSize < buf->offset) {
776
if ((buf->totalSize - buf->offset) > DND_MAX_TRANSPORT_PACKET_PAYLOAD_SIZE) {
777
payloadSize = DND_MAX_TRANSPORT_PACKET_PAYLOAD_SIZE;
779
payloadSize = buf->totalSize - buf->offset;
782
*packet = (DnDTransportPacketHeader *)Util_SafeMalloc(
783
payloadSize + DND_TRANSPORT_PACKET_HEADER_SIZE);
784
(*packet)->type = DND_TRANSPORT_PACKET_TYPE_PAYLOAD;
785
(*packet)->seqNum = buf->seqNum;
786
(*packet)->totalSize = buf->totalSize;
787
(*packet)->payloadSize = payloadSize;
788
(*packet)->offset = buf->offset;
790
memcpy((*packet)->payload,
791
buf->buffer + buf->offset,
793
buf->offset += payloadSize;
795
/* This time is used for timeout purpose. */
796
Hostinfo_GetTimeOfDay(&buf->lastUpdateTime);
798
return payloadSize + DND_TRANSPORT_PACKET_HEADER_SIZE;
803
*-----------------------------------------------------------------------------
805
* DnD_TransportBufAppendPacket --
807
* Put a received packet into transport layer buffer.
810
* TRUE if success, FALSE otherwise.
813
* Memory may be allocated for transport layer buffer.
815
*-----------------------------------------------------------------------------
819
DnD_TransportBufAppendPacket(DnDTransportBuffer *buf, // IN/OUT
820
DnDTransportPacketHeader *packet, // IN
821
size_t packetSize) // IN
824
ASSERT(packetSize == (packet->payloadSize + DND_TRANSPORT_PACKET_HEADER_SIZE) &&
825
packetSize <= DND_MAX_TRANSPORT_PACKET_SIZE &&
826
(packet->payloadSize + packet->offset) <= packet->totalSize &&
827
packet->totalSize <= DNDMSG_MAX_ARGSZ);
829
if (packetSize != (packet->payloadSize + DND_TRANSPORT_PACKET_HEADER_SIZE) ||
830
packetSize > DND_MAX_TRANSPORT_PACKET_SIZE ||
831
(packet->payloadSize + packet->offset) > packet->totalSize ||
832
packet->totalSize > DNDMSG_MAX_ARGSZ) {
837
* If seqNum does not match, it means either this is the first packet, or there
838
* is a timeout in another side. Reset the buffer in all cases.
840
if (buf->seqNum != packet->seqNum) {
841
DnD_TransportBufReset(buf);
845
ASSERT(!packet->offset);
846
if (packet->offset) {
849
buf->buffer = Util_SafeMalloc(packet->totalSize);
850
buf->totalSize = packet->totalSize;
851
buf->seqNum = packet->seqNum;
855
if (buf->offset != packet->offset) {
859
memcpy(buf->buffer + buf->offset,
861
packet->payloadSize);
862
buf->offset += packet->payloadSize;
866
DnD_TransportBufReset(buf);
872
*-----------------------------------------------------------------------------
874
* DnD_TransportMsgToPacket --
876
* Get a packet from small size message.
879
* Transport layer packet size, or 0 if failed.
882
* Memory may be allocated for packet.
884
*-----------------------------------------------------------------------------
888
DnD_TransportMsgToPacket(uint8 *msg, // IN
889
size_t msgSize, // IN
891
DnDTransportPacketHeader **packet) // OUT
895
ASSERT(msgSize > 0 && msgSize <= DND_MAX_TRANSPORT_PACKET_PAYLOAD_SIZE);
900
msgSize > DND_MAX_TRANSPORT_PACKET_PAYLOAD_SIZE ||
905
packetSize = msgSize + DND_TRANSPORT_PACKET_HEADER_SIZE;
907
*packet = (DnDTransportPacketHeader *)Util_SafeMalloc(packetSize);
909
(*packet)->type = DND_TRANSPORT_PACKET_TYPE_SINGLE;
910
(*packet)->seqNum = seqNum;
911
(*packet)->totalSize = msgSize;
912
(*packet)->payloadSize = msgSize;
913
(*packet)->offset = 0;
915
memcpy((*packet)->payload, msg, msgSize);
922
*-----------------------------------------------------------------------------
924
* DnD_TransportReqPacket --
926
* Generate a request packet with empty payload. After got a payload, receive
927
* side should send a DND_TRANSPORT_PACKET_TYPE_REQUEST packet to ask for
928
* next payload packet.
931
* Transport layer packet size.
934
* Memory is allocated for packet.
936
*-----------------------------------------------------------------------------
940
DnD_TransportReqPacket(DnDTransportBuffer *buf, // IN
941
DnDTransportPacketHeader **packet) // OUT
943
*packet = (DnDTransportPacketHeader *)Util_SafeMalloc(
944
DND_TRANSPORT_PACKET_HEADER_SIZE);
946
(*packet)->type = DND_TRANSPORT_PACKET_TYPE_REQUEST;
947
(*packet)->seqNum = buf->seqNum;
948
(*packet)->totalSize = buf->totalSize;
949
(*packet)->payloadSize = 0;
950
(*packet)->offset = buf->offset;
951
return DND_TRANSPORT_PACKET_HEADER_SIZE;
956
*----------------------------------------------------------------------------
960
* Copies len bytes of data from b to out. Subsequent calls to this
961
* function will copy data from the last unread point.
964
* TRUE when data is successfully copies to out, FALSE otherwise.
969
*----------------------------------------------------------------------------
973
DnDReadBuffer(BufRead *b, // IN/OUT: buffer to read from
974
void *out, // OUT: the output buffer
975
size_t len) // IN: the amount to read
980
if (len > b->unreadLen) {
984
memcpy(out, b->pos, len);
985
if (!DnDSlideBuffer(b, len)) {
994
*----------------------------------------------------------------------------
998
* Ignore len bytes of data in b. Subsequent calls to DnDReadBuffer will
999
* copy data from the last point.
1002
* TRUE when pos is successfully changed, FALSE otherwise.
1007
*----------------------------------------------------------------------------
1011
DnDSlideBuffer(BufRead *b, // IN/OUT: buffer to read from
1012
size_t len) // IN: the amount to read
1016
if (len > b->unreadLen) {
1021
b->unreadLen -= len;