~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to lib/dnd/dndCommon.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*********************************************************
2
 
 * Copyright (C) 2005 VMware, Inc. All rights reserved.
3
 
 *
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.
7
 
 *
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.
12
 
 *
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.
16
 
 *
17
 
 *********************************************************/
18
 
 
19
 
/*
20
 
 * dndCommon.c --
21
 
 *
22
 
 *     Implementation of bora/lib/public/dnd.h functions that are common to
23
 
 *     Linux and Windows platforms
24
 
 */
25
 
 
26
 
 
27
 
#include <stdlib.h>
28
 
#include <time.h>
29
 
#include <limits.h>
30
 
 
31
 
#include "vmware.h"
32
 
#include "dndInt.h"
33
 
#include "dnd.h"
34
 
#include "file.h"
35
 
#include "str.h"
36
 
#include "random.h"
37
 
#include "util.h"
38
 
#include "cpNameUtil.h"
39
 
#include "hgfsEscape.h"
40
 
#include "hgfsServerPolicy.h"
41
 
#include "hgfsVirtualDir.h"
42
 
#include "unicodeOperations.h"
43
 
#include "hostinfo.h"
44
 
 
45
 
#define LOGLEVEL_MODULE dnd
46
 
#include "loglevel_user.h"
47
 
 
48
 
#define WIN_DIRSEPC     '\\'
49
 
#define WIN_DIRSEPS     "\\"
50
 
 
51
 
static ConstUnicode DnDCreateRootStagingDirectory(void);
52
 
 
53
 
/*
54
 
 *-----------------------------------------------------------------------------
55
 
 *
56
 
 * DnD_CreateStagingDirectory --
57
 
 *
58
 
 *    Generate a unique staging directory name, create the directory, and
59
 
 *    return the name. The caller is responsible for freeing the returned
60
 
 *    string.
61
 
 *
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
70
 
 *    necessary.
71
 
 *
72
 
 * Results:
73
 
 *    A string containing the newly created name, or NULL on failure.
74
 
 *
75
 
 * Side effects:
76
 
 *    A directory is created
77
 
 *
78
 
 *-----------------------------------------------------------------------------
79
 
 */
80
 
 
81
 
Unicode
82
 
DnD_CreateStagingDirectory(void)
83
 
{
84
 
   ConstUnicode root;
85
 
   Unicode *stagingDirList;
86
 
   int numStagingDirs;
87
 
   int i;
88
 
   Unicode ret = NULL;
89
 
   Bool found = FALSE;
90
 
 
91
 
   /*
92
 
    * Make sure the root staging directory is created with the correct
93
 
    * permissions.
94
 
    */
95
 
   root = DnDCreateRootStagingDirectory();
96
 
   if (!root) {
97
 
      return NULL;
98
 
   }
99
 
 
100
 
   /* Look for an existing, empty staging directory */
101
 
   numStagingDirs = File_ListDirectory(root, &stagingDirList);
102
 
   if (numStagingDirs < 0) {
103
 
      goto exit;
104
 
   }
105
 
 
106
 
   for (i = 0; i < numStagingDirs; i++) {
107
 
      if (!found) {
108
 
         Unicode stagingDir;
109
 
 
110
 
         stagingDir = Unicode_Append(root, stagingDirList[i]);
111
 
 
112
 
         if (File_IsEmptyDirectory(stagingDir) &&
113
 
             DnDStagingDirectoryUsable(stagingDir)) {
114
 
               ret = Unicode_Append(stagingDir, DIRSEPS);
115
 
               /*
116
 
                * We can use this directory.  Make sure to continue to loop
117
 
                * so we don't leak the remaining stagindDirList[i]s.
118
 
                */
119
 
               found = TRUE;
120
 
         }
121
 
 
122
 
         Unicode_Free(stagingDir);
123
 
      }
124
 
   }
125
 
 
126
 
   Unicode_FreeList(stagingDirList, numStagingDirs);
127
 
 
128
 
   /* Only create a directory if we didn't find one above. */
129
 
   if (!found) {
130
 
      rqContext *context;
131
 
 
132
 
      context = Random_QuickSeed((unsigned)time(NULL));
133
 
 
134
 
      for (i = 0; i < 10; i++) {
135
 
         Unicode temp;
136
 
 
137
 
         /* Each staging directory is given a random name. */
138
 
         Unicode_Free(ret);
139
 
         temp = Unicode_Format("%08x%c", Random_Quick(context), DIRSEPC);
140
 
         ASSERT_MEM_ALLOC(temp);
141
 
         ret = Unicode_Append(root, temp);
142
 
         Unicode_Free(temp);
143
 
 
144
 
         if (File_CreateDirectory(ret) &&
145
 
             DnDSetPermissionsOnStagingDir(ret)) {
146
 
            found = TRUE;
147
 
            break;
148
 
         }
149
 
      }
150
 
 
151
 
      free(context);
152
 
   }
153
 
 
154
 
exit:
155
 
   if (!found && ret != NULL) {
156
 
      Unicode_Free(ret);
157
 
      ret = NULL;
158
 
   }
159
 
 
160
 
   return ret;
161
 
}
162
 
 
163
 
 
164
 
/*
165
 
 *-----------------------------------------------------------------------------
166
 
 *
167
 
 * DnD_DeleteStagingFiles --
168
 
 *
169
 
 *    Attempts to delete all files in the staging directory. This does not
170
 
 *    delete the directory itself.
171
 
 *
172
 
 * Results:
173
 
 *    TRUE if all files were deleted. FALSE if there was an error.
174
 
 *
175
 
 * Side effects:
176
 
 *    None
177
 
 *
178
 
 *-----------------------------------------------------------------------------
179
 
 */
180
 
 
181
 
Bool
182
 
DnD_DeleteStagingFiles(ConstUnicode stagingDir,  // IN:
183
 
                       Bool onReboot)            // IN:
184
 
{
185
 
   Bool ret = TRUE;
186
 
 
187
 
   ASSERT(stagingDir);
188
 
 
189
 
   if (!File_Exists(stagingDir)) {
190
 
      /* The stagingDir is already gone. */
191
 
      return TRUE;
192
 
   }
193
 
 
194
 
   if (!File_IsDirectory(stagingDir)) {
195
 
      return FALSE;
196
 
   }
197
 
 
198
 
   if (onReboot) {
199
 
      if (File_UnlinkDelayed(stagingDir)) {
200
 
         ret = FALSE;
201
 
      }
202
 
   } else {
203
 
      int i;
204
 
      int numFiles;
205
 
      Unicode base;
206
 
      Unicode *fileList = NULL;
207
 
 
208
 
      /* get list of files in current directory */
209
 
      numFiles = File_ListDirectory(stagingDir, &fileList);
210
 
 
211
 
      if (numFiles == -1) {
212
 
         return FALSE;
213
 
      }
214
 
 
215
 
      /* delete everything in the directory */
216
 
      base = Unicode_Append(stagingDir, DIRSEPS);
217
 
 
218
 
      for (i = 0; i < numFiles; i++) {
219
 
         Unicode curPath;
220
 
 
221
 
         curPath = Unicode_Append(base, fileList[i]);
222
 
 
223
 
         if (File_IsDirectory(curPath)) {
224
 
            if (!File_DeleteDirectoryTree(curPath)) {
225
 
               ret = FALSE;
226
 
            }
227
 
         } else {
228
 
            if (File_Unlink(curPath) == -1) {
229
 
               ret = FALSE;
230
 
            }
231
 
         }
232
 
 
233
 
         Unicode_Free(curPath);
234
 
      }
235
 
 
236
 
      Unicode_Free(base);
237
 
   }
238
 
 
239
 
   return ret;
240
 
}
241
 
 
242
 
/*
243
 
 *----------------------------------------------------------------------------
244
 
 *
245
 
 * DnDCreateRootStagingDirectory --
246
 
 *
247
 
 *    Checks if the root staging directory exists with the correct permissions,
248
 
 *    or creates it if necessary.
249
 
 *
250
 
 * Results:
251
 
 *    The path of the root directory on success, NULL on failure.
252
 
 *
253
 
 * Side effects:
254
 
 *    None.
255
 
 *
256
 
 *----------------------------------------------------------------------------
257
 
 */
258
 
 
259
 
static ConstUnicode
260
 
DnDCreateRootStagingDirectory(void)
261
 
{
262
 
   ConstUnicode root;
263
 
 
264
 
   /*
265
 
    * DnD_GetFileRoot() gives us a pointer to a static string, so there's no
266
 
    * need to free anything.
267
 
    */
268
 
   root = DnD_GetFileRoot();
269
 
   if (!root) {
270
 
      return NULL;
271
 
   }
272
 
 
273
 
   if (File_Exists(root)) {
274
 
      if (!DnDRootDirUsable(root) &&
275
 
          !DnDSetPermissionsOnRootDir(root)) {
276
 
         /*
277
 
          * The directory already exists and its permissions are wrong and
278
 
          * cannot be set, so there's not much we can do.
279
 
          */
280
 
         return NULL;
281
 
      }
282
 
   } else {
283
 
      if (!File_CreateDirectory(root) ||
284
 
          !DnDSetPermissionsOnRootDir(root)) {
285
 
         /* We couldn't create the directory or set the permissions. */
286
 
         return NULL;
287
 
      }
288
 
   }
289
 
 
290
 
   return root;
291
 
}
292
 
 
293
 
 
294
 
/*
295
 
 *----------------------------------------------------------------------------
296
 
 *
297
 
 * DnDPrependFileRoot --
298
 
 *
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.
304
 
 *
305
 
 *    The logic here and in the called functions appears to be UTF8-safe.
306
 
 *
307
 
 * Results:
308
 
 *    TRUE on success, FALSE on failure.
309
 
 *
310
 
 * Side effects:
311
 
 *    *src will be freed, and a new buffer will be allocated. This buffer must
312
 
 *    be freed by the caller.
313
 
 *
314
 
 *----------------------------------------------------------------------------
315
 
 */
316
 
 
317
 
Bool
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
322
 
{
323
 
   char *newData = NULL;
324
 
   size_t newDataLen = 0;
325
 
   Bool firstPass = TRUE;
326
 
   const char *begin;
327
 
   const char *end;
328
 
   const char *next;
329
 
   size_t rootLen;
330
 
   int len;
331
 
 
332
 
   ASSERT(fileRoot);
333
 
   ASSERT(src);
334
 
   ASSERT(*src);
335
 
   ASSERT(srcSize);
336
 
 
337
 
   rootLen = strlen(fileRoot);
338
 
 
339
 
   /*
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.
344
 
    */
345
 
 
346
 
   for (begin = *src; *begin == '\0'; begin++)
347
 
      ;
348
 
   end = CPNameUtil_Strrchr(*src, *srcSize, '\0');
349
 
 
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;
353
 
      int escapedLen;
354
 
 
355
 
      if (len < 0) {
356
 
         Log("%s: error getting next component\n", __FUNCTION__);
357
 
         if (!firstPass) {
358
 
            free(newData);
359
 
         }
360
 
 
361
 
         return FALSE;
362
 
      }
363
 
 
364
 
      /*
365
 
       * Append this component to our list: allocate one more for NUL on first
366
 
       * pass and delimiter on all other passes.
367
 
       */
368
 
 
369
 
      escapedLen = HgfsEscape_GetSize(begin, len);
370
 
      if (escapedLen < 0) {
371
 
         Log("%s: error calculating buffer size\n", __FUNCTION__);
372
 
         return FALSE;
373
 
      } else if (0 == escapedLen) {
374
 
         newDataLen += rootLen + len + 1;
375
 
         newData = (char *)Util_SafeRealloc(newData, newDataLen);
376
 
 
377
 
         if (!firstPass) {
378
 
            ASSERT(origNewDataLen > 0);
379
 
            newData[origNewDataLen - 1] = delimiter;
380
 
         }
381
 
         memcpy(newData + origNewDataLen, fileRoot, rootLen);
382
 
         memcpy(newData + origNewDataLen + rootLen, begin, len);
383
 
      } else {
384
 
         newDataLen += rootLen + 1;
385
 
         newData = (char *)Util_SafeRealloc(newData, newDataLen);
386
 
 
387
 
         if (!firstPass) {
388
 
            ASSERT(origNewDataLen > 0);
389
 
            newData[origNewDataLen - 1] = delimiter;
390
 
         }
391
 
         memcpy(newData + origNewDataLen, fileRoot, rootLen);
392
 
         HgfsEscape_Do(begin, len, escapedLen, newData + origNewDataLen + rootLen);
393
 
      }
394
 
      newData[newDataLen - 1] = '\0';
395
 
 
396
 
      firstPass = FALSE;
397
 
      begin = next;
398
 
   }
399
 
 
400
 
   free(*src);
401
 
   *src = newData;
402
 
   /* Not including NUL terminator */
403
 
   *srcSize = newDataLen - 1;
404
 
   return TRUE;
405
 
}
406
 
 
407
 
 
408
 
/*
409
 
 *----------------------------------------------------------------------------
410
 
 *
411
 
 * DnD_LegacyConvertToCPName --
412
 
 *
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.
417
 
 *
418
 
 *    The logic here and in the called functions appears to be UTF8-safe.
419
 
 *
420
 
 * Results:
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
423
 
 *    a negative error.
424
 
 *
425
 
 * Side effects:
426
 
 *    None.
427
 
 *
428
 
 *----------------------------------------------------------------------------
429
 
 */
430
 
 
431
 
int
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
435
 
{
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;
440
 
   char *fullName;
441
 
   size_t fullNameSize;
442
 
   size_t nameSize;
443
 
   int result;
444
 
 
445
 
   ASSERT(nameIn);
446
 
   ASSERT(bufOut);
447
 
 
448
 
   /*
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.
452
 
    */
453
 
 
454
 
   /*
455
 
    * Is this file path a UNC path?
456
 
    */
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);
462
 
   } else {
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);
467
 
   }
468
 
 
469
 
   /* Skip any path separators at the beginning of the input string */
470
 
   while (*nameIn == WIN_DIRSEPC) {
471
 
      nameIn++;
472
 
   }
473
 
 
474
 
   nameSize = strlen(nameIn);
475
 
   fullNameSize = partialNameLen + partialNameSuffixLen + nameSize;
476
 
   fullName = (char *)Util_SafeMalloc(fullNameSize + 1);
477
 
 
478
 
   memcpy(fullName, partialName, partialNameLen);
479
 
   memcpy(fullName + partialNameLen, partialNameSuffix, partialNameSuffixLen);
480
 
   memcpy(fullName + partialNameLen + partialNameSuffixLen, nameIn, nameSize);
481
 
   fullName[fullNameSize] = '\0';
482
 
 
483
 
   LOG(4, ("%s: generated name is \"%s\"\n", __FUNCTION__, fullName));
484
 
 
485
 
   /*
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.
489
 
    */
490
 
 
491
 
   {
492
 
      char const *winNameIn = fullName;
493
 
      char const *origOut = bufOut;
494
 
      char const *endOut = bufOut + bufOutSize;
495
 
      char const pathSep = WIN_DIRSEPC;
496
 
      char *ignores = ":";
497
 
 
498
 
      /* Skip any path separators at the beginning of the input string */
499
 
      while (*winNameIn == pathSep) {
500
 
         winNameIn++;
501
 
      }
502
 
 
503
 
      /*
504
 
       * Copy the string to the output buf, converting all path separators into
505
 
       * '\0' and ignoring the specified characters.
506
 
       */
507
 
 
508
 
      for (; *winNameIn != '\0' && bufOut < endOut; winNameIn++) {
509
 
         if (ignores) {
510
 
            char *currIgnore = ignores;
511
 
            Bool ignore = FALSE;
512
 
 
513
 
            while (*currIgnore != '\0') {
514
 
               if (*winNameIn == *currIgnore) {
515
 
                  ignore = TRUE;
516
 
                  break;
517
 
               }
518
 
               currIgnore++;
519
 
            }
520
 
 
521
 
            if (!ignore) {
522
 
               *bufOut = (*winNameIn == pathSep) ? '\0' : *winNameIn;
523
 
               bufOut++;
524
 
            }
525
 
         } else {
526
 
            *bufOut = (*winNameIn == pathSep) ? '\0' : *winNameIn;
527
 
            bufOut++;
528
 
         }
529
 
      }
530
 
 
531
 
      /*
532
 
       * NUL terminate. XXX This should go away.
533
 
       *
534
 
       * When we get rid of NUL termination here, this test should
535
 
       * also change to "if (*winNameIn != '\0')".
536
 
       */
537
 
 
538
 
      if (bufOut == endOut) {
539
 
         result = -1;
540
 
         goto out;
541
 
      }
542
 
      *bufOut = '\0';
543
 
 
544
 
      /* Path name size should not require more than 4 bytes. */
545
 
      ASSERT((bufOut - origOut) <= 0xFFFFFFFF);
546
 
 
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)) {
550
 
         result--;
551
 
      }
552
 
 
553
 
      /*
554
 
       * Make exception and call CPName_Print() here, since it's only for
555
 
       * logging
556
 
       */
557
 
 
558
 
      LOG(4, ("%s: CPName is \"%s\"\n", __FUNCTION__, 
559
 
              CPName_Print(origOut, result)));
560
 
   }
561
 
 
562
 
out:
563
 
   free(fullName);
564
 
 
565
 
   return result;
566
 
}
567
 
 
568
 
 
569
 
/*
570
 
 *-----------------------------------------------------------------------------
571
 
 *
572
 
 * DnD_CPNameListToDynBufArray --
573
 
 *
574
 
 *    Export CPName file list from binary buffer to DynBufArray.
575
 
 *
576
 
 * Results:
577
 
 *    TRUE if success, FALSE otherwise.
578
 
 *
579
 
 * Side effects:
580
 
 *    Memory may allocated for DynBufArray if success.
581
 
 *
582
 
 *-----------------------------------------------------------------------------
583
 
 */
584
 
 
585
 
Bool
586
 
DnD_CPNameListToDynBufArray(char *fileList,           // IN: CPName format
587
 
                            size_t listSize,          // IN
588
 
                            DynBufArray *dynBufArray) // OUT
589
 
{
590
 
   DynBuf buf;
591
 
   BufRead r;
592
 
   int32 pathLen;
593
 
   size_t count;
594
 
   size_t i;
595
 
 
596
 
   ASSERT(fileList);
597
 
   r.pos = fileList;
598
 
   r.unreadLen = listSize;
599
 
 
600
 
   DynBufArray_Init(dynBufArray, 0);
601
 
 
602
 
   while (r.unreadLen > 0) {
603
 
      DynBuf_Init(&buf);
604
 
      if (!DnDReadBuffer(&r, &pathLen, sizeof pathLen) ||
605
 
          (pathLen > r.unreadLen) ||
606
 
          !DynBuf_Append(&buf, r.pos, pathLen)) {
607
 
         goto error;
608
 
      }
609
 
 
610
 
      if (!DnDSlideBuffer(&r, pathLen)) {
611
 
         goto error;
612
 
      }
613
 
 
614
 
      if (!DynBufArray_Push(dynBufArray, buf)) {
615
 
         goto error;
616
 
      }
617
 
   }
618
 
   return TRUE;
619
 
 
620
 
error:
621
 
   DynBuf_Destroy(&buf);
622
 
 
623
 
   count = DynBufArray_Count(dynBufArray);
624
 
   for (i = 0; i < count; i++) {
625
 
      DynBuf *b = DynArray_AddressOf(dynBufArray, i);
626
 
      DynBuf_Destroy(b);
627
 
   }
628
 
   DynBufArray_SetCount(dynBufArray, 0);
629
 
   DynBufArray_Destroy(dynBufArray);
630
 
   return FALSE;
631
 
}
632
 
 
633
 
 
634
 
/*
635
 
 *-----------------------------------------------------------------------------
636
 
 *
637
 
 * DnD_GetLastDirName --
638
 
 *
639
 
 *    Try to get last directory name from a full path name.
640
 
 *
641
 
 * Results:
642
 
 *    The allocated Unicode string, or NULL on failure.
643
 
 *
644
 
 * Side effects:
645
 
 *    None.
646
 
 *
647
 
 *-----------------------------------------------------------------------------
648
 
 */
649
 
 
650
 
Unicode
651
 
DnD_GetLastDirName(ConstUnicode str) // IN
652
 
{
653
 
   size_t end = strlen(str);
654
 
   size_t start;
655
 
   size_t res = 0;
656
 
 
657
 
   if (end != 0 && DIRSEPC == str[end - 1]) {
658
 
      end--;
659
 
   }
660
 
 
661
 
   if (end == 0) {
662
 
      return 0;
663
 
   }
664
 
 
665
 
   start = end;
666
 
 
667
 
   while (start && DIRSEPC != str[start - 1]) {
668
 
      start--;
669
 
   }
670
 
 
671
 
   /* There should be at lease 1 DIRSEPC before end. */
672
 
   if (start == 0) {
673
 
      return 0;
674
 
   }
675
 
 
676
 
   res = end - start;
677
 
   return Unicode_AllocWithLength(str + start, res, STRING_ENCODING_UTF8);
678
 
}
679
 
 
680
 
 
681
 
/* Transport layer big buffer support functions. */
682
 
 
683
 
/*
684
 
 *-----------------------------------------------------------------------------
685
 
 *
686
 
 * DnD_TransportBufInit --
687
 
 *
688
 
 *    Initialize transport layer buffer with DnD message.
689
 
 *
690
 
 * Results:
691
 
 *    None.
692
 
 *
693
 
 * Side effects:
694
 
 *    Buffer memory is allocated.
695
 
 *
696
 
 *-----------------------------------------------------------------------------
697
 
 */
698
 
 
699
 
void
700
 
DnD_TransportBufInit(DnDTransportBuffer *buf, // OUT
701
 
                     uint8 *msg,              // IN
702
 
                     size_t msgSize,          // IN
703
 
                     uint32 seqNum)           // IN
704
 
{
705
 
   ASSERT(buf);
706
 
   ASSERT(msgSize <= DNDMSG_MAX_ARGSZ);
707
 
 
708
 
   free(buf->buffer);
709
 
   buf->buffer = Util_SafeMalloc(msgSize);
710
 
   memcpy(buf->buffer, msg, msgSize);
711
 
   buf->seqNum = seqNum;
712
 
   buf->totalSize = msgSize;
713
 
   buf->offset = 0;
714
 
}
715
 
 
716
 
 
717
 
/*
718
 
 *-----------------------------------------------------------------------------
719
 
 *
720
 
 * DnD_TransportBufReset --
721
 
 *
722
 
 *    Reset transport layer buffer.
723
 
 *
724
 
 * Results:
725
 
 *    None.
726
 
 *
727
 
 * Side effects:
728
 
 *    None.
729
 
 *
730
 
 *-----------------------------------------------------------------------------
731
 
 */
732
 
 
733
 
void
734
 
DnD_TransportBufReset(DnDTransportBuffer *buf) // IN/OUT
735
 
{
736
 
   ASSERT(buf);
737
 
 
738
 
   free(buf->buffer);
739
 
   buf->buffer = NULL;
740
 
 
741
 
   buf->seqNum = 0;
742
 
   buf->totalSize = 0;
743
 
   buf->offset = 0;
744
 
   buf->lastUpdateTime = 0;
745
 
}
746
 
 
747
 
 
748
 
/*
749
 
 *-----------------------------------------------------------------------------
750
 
 *
751
 
 * DnD_TransportBufGetPacket --
752
 
 *
753
 
 *    Get a transport layer packet from transport layer buffer.
754
 
 *
755
 
 * Results:
756
 
 *    Transport layer packet size, or 0 if failed.
757
 
 *
758
 
 * Side effects:
759
 
 *    Memory may be allocated for packet.
760
 
 *
761
 
 *-----------------------------------------------------------------------------
762
 
 */
763
 
 
764
 
size_t
765
 
DnD_TransportBufGetPacket(DnDTransportBuffer *buf,           // IN/OUT
766
 
                          DnDTransportPacketHeader **packet) // OUT
767
 
{
768
 
   size_t payloadSize;
769
 
 
770
 
   ASSERT(buf);
771
 
 
772
 
   if (buf->totalSize < buf->offset) {
773
 
      return 0;
774
 
   }
775
 
 
776
 
   if ((buf->totalSize - buf->offset) > DND_MAX_TRANSPORT_PACKET_PAYLOAD_SIZE) {
777
 
      payloadSize = DND_MAX_TRANSPORT_PACKET_PAYLOAD_SIZE;
778
 
   } else {
779
 
      payloadSize = buf->totalSize - buf->offset;
780
 
   }
781
 
 
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;
789
 
 
790
 
   memcpy((*packet)->payload,
791
 
          buf->buffer + buf->offset,
792
 
          payloadSize);
793
 
   buf->offset += payloadSize;
794
 
 
795
 
   /* This time is used for timeout purpose. */
796
 
   Hostinfo_GetTimeOfDay(&buf->lastUpdateTime);
797
 
 
798
 
   return payloadSize + DND_TRANSPORT_PACKET_HEADER_SIZE;
799
 
}
800
 
 
801
 
 
802
 
/*
803
 
 *-----------------------------------------------------------------------------
804
 
 *
805
 
 * DnD_TransportBufAppendPacket --
806
 
 *
807
 
 *    Put a received packet into transport layer buffer.
808
 
 *
809
 
 * Results:
810
 
 *    TRUE if success, FALSE otherwise.
811
 
 *
812
 
 * Side effects:
813
 
 *    Memory may be allocated for transport layer buffer.
814
 
 *
815
 
 *-----------------------------------------------------------------------------
816
 
 */
817
 
 
818
 
Bool
819
 
DnD_TransportBufAppendPacket(DnDTransportBuffer *buf,          // IN/OUT
820
 
                             DnDTransportPacketHeader *packet, // IN
821
 
                             size_t packetSize)                // IN
822
 
{
823
 
   ASSERT(buf);
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);
828
 
 
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) {
833
 
      goto error;
834
 
   }
835
 
 
836
 
   /*
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.
839
 
    */
840
 
   if (buf->seqNum != packet->seqNum) {
841
 
      DnD_TransportBufReset(buf);
842
 
   }
843
 
 
844
 
   if (!buf->buffer) {
845
 
      ASSERT(!packet->offset);
846
 
      if (packet->offset) {
847
 
         goto error;
848
 
      }
849
 
      buf->buffer = Util_SafeMalloc(packet->totalSize);
850
 
      buf->totalSize = packet->totalSize;
851
 
      buf->seqNum = packet->seqNum;
852
 
      buf->offset = 0;
853
 
   }
854
 
 
855
 
   if (buf->offset != packet->offset) {
856
 
      goto error;
857
 
   }
858
 
 
859
 
   memcpy(buf->buffer + buf->offset,
860
 
          packet->payload,
861
 
          packet->payloadSize);
862
 
   buf->offset += packet->payloadSize;
863
 
   return TRUE;
864
 
 
865
 
error:
866
 
   DnD_TransportBufReset(buf);
867
 
   return FALSE;
868
 
}
869
 
 
870
 
 
871
 
/*
872
 
 *-----------------------------------------------------------------------------
873
 
 *
874
 
 * DnD_TransportMsgToPacket --
875
 
 *
876
 
 *    Get a packet from small size message.
877
 
 *
878
 
 * Results:
879
 
 *    Transport layer packet size, or 0 if failed.
880
 
 *
881
 
 * Side effects:
882
 
 *    Memory may be allocated for packet.
883
 
 *
884
 
 *-----------------------------------------------------------------------------
885
 
 */
886
 
 
887
 
size_t
888
 
DnD_TransportMsgToPacket(uint8 *msg,                        // IN
889
 
                         size_t msgSize,                    // IN
890
 
                         uint32 seqNum,                     // IN
891
 
                         DnDTransportPacketHeader **packet) // OUT
892
 
{
893
 
   size_t packetSize;
894
 
 
895
 
   ASSERT(msgSize > 0 && msgSize <= DND_MAX_TRANSPORT_PACKET_PAYLOAD_SIZE);
896
 
   ASSERT(msg);
897
 
   ASSERT(packet);
898
 
 
899
 
   if (msgSize <=0 ||
900
 
       msgSize > DND_MAX_TRANSPORT_PACKET_PAYLOAD_SIZE ||
901
 
       !msg || !packet) {
902
 
      return 0;
903
 
   }
904
 
 
905
 
   packetSize = msgSize + DND_TRANSPORT_PACKET_HEADER_SIZE;
906
 
 
907
 
   *packet = (DnDTransportPacketHeader *)Util_SafeMalloc(packetSize);
908
 
 
909
 
   (*packet)->type = DND_TRANSPORT_PACKET_TYPE_SINGLE;
910
 
   (*packet)->seqNum = seqNum;
911
 
   (*packet)->totalSize = msgSize;
912
 
   (*packet)->payloadSize = msgSize;
913
 
   (*packet)->offset = 0;
914
 
 
915
 
   memcpy((*packet)->payload, msg, msgSize);
916
 
 
917
 
   return packetSize;
918
 
}
919
 
 
920
 
 
921
 
/*
922
 
 *-----------------------------------------------------------------------------
923
 
 *
924
 
 * DnD_TransportReqPacket --
925
 
 *
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.
929
 
 *
930
 
 * Results:
931
 
 *    Transport layer packet size.
932
 
 *
933
 
 * Side effects:
934
 
 *    Memory is allocated for packet.
935
 
 *
936
 
 *-----------------------------------------------------------------------------
937
 
 */
938
 
 
939
 
size_t
940
 
DnD_TransportReqPacket(DnDTransportBuffer *buf,           // IN
941
 
                       DnDTransportPacketHeader **packet) // OUT
942
 
{
943
 
   *packet = (DnDTransportPacketHeader *)Util_SafeMalloc(
944
 
      DND_TRANSPORT_PACKET_HEADER_SIZE);
945
 
 
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;
952
 
}
953
 
 
954
 
 
955
 
/*
956
 
 *----------------------------------------------------------------------------
957
 
 *
958
 
 * DnDReadBuffer --
959
 
 *
960
 
 *      Copies len bytes of data from b to out. Subsequent calls to this
961
 
 *      function will copy data from the last unread point.
962
 
 *
963
 
 * Results:
964
 
 *      TRUE when data is successfully copies to out, FALSE otherwise.
965
 
 *
966
 
 * Side effects:
967
 
 *      None.
968
 
 *
969
 
 *----------------------------------------------------------------------------
970
 
 */
971
 
 
972
 
Bool
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
976
 
{
977
 
   ASSERT(b);
978
 
   ASSERT(out);
979
 
 
980
 
   if (len > b->unreadLen) {
981
 
      return FALSE;
982
 
   }
983
 
 
984
 
   memcpy(out, b->pos, len);
985
 
   if (!DnDSlideBuffer(b, len)) {
986
 
      return FALSE;
987
 
   }
988
 
 
989
 
   return TRUE;
990
 
}
991
 
 
992
 
 
993
 
/*
994
 
 *----------------------------------------------------------------------------
995
 
 *
996
 
 * DnDSlideBuffer --
997
 
 *
998
 
 *      Ignore len bytes of data in b. Subsequent calls to DnDReadBuffer will
999
 
 *      copy data from the last point.
1000
 
 *
1001
 
 * Results:
1002
 
 *      TRUE when pos is successfully changed, FALSE otherwise.
1003
 
 *
1004
 
 * Side effects:
1005
 
 *      None.
1006
 
 *
1007
 
 *----------------------------------------------------------------------------
1008
 
 */
1009
 
 
1010
 
Bool
1011
 
DnDSlideBuffer(BufRead *b, // IN/OUT: buffer to read from
1012
 
               size_t len) // IN: the amount to read
1013
 
{
1014
 
   ASSERT(b);
1015
 
 
1016
 
   if (len > b->unreadLen) {
1017
 
      return FALSE;
1018
 
   }
1019
 
 
1020
 
   b->pos += len;
1021
 
   b->unreadLen -= len;
1022
 
 
1023
 
   return TRUE;
1024
 
}
1025