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

« back to all changes in this revision

Viewing changes to modules/solaris/vmhgfs/hgfsEscape.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2009-03-20 10:19:00 UTC
  • mfrom: (1.1.4 upstream) (2.4.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090320101900-1o604camiubq2de8
Tags: 2009.03.18-154848-2
Correcting patch system depends (Closes: #520493).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2008 VMware, Inc. All rights reserved.
 
3
 *
 
4
 * The contents of this file are subject to the terms of the Common
 
5
 * Development and Distribution License (the "License") version 1.0
 
6
 * and no later version.  You may not use this file except in
 
7
 * compliance with the License.
 
8
 *
 
9
 * You can obtain a copy of the License at
 
10
 *         http://www.opensource.org/licenses/cddl1.php
 
11
 *
 
12
 * See the License for the specific language governing permissions
 
13
 * and limitations under the License.
 
14
 *
 
15
 *********************************************************/
 
16
 
 
17
/*
 
18
 * hgfsEscape.c --
 
19
 *
 
20
 *    Escape and unescape illegal filenames for different platforms.
 
21
 *
 
22
 */
 
23
 
 
24
#ifdef __KERNEL__
 
25
#  include "driver-config.h"
 
26
#  include <linux/string.h>
 
27
#elif defined(__FreeBSD__)
 
28
#   if defined(_KERNEL)
 
29
#      include <sys/libkern.h>
 
30
#      define strchr(s,c)       index(s,c)
 
31
#   else
 
32
#      include <string.h>
 
33
#   endif
 
34
#   define memmove(s1,s2,n) bcopy(s2,s1,n) 
 
35
#elif defined(__APPLE__) && defined(KERNEL)
 
36
#  include <string.h>
 
37
#elif !defined(sun)
 
38
#  include <stdlib.h>
 
39
#  include <string.h>
 
40
#else
 
41
#  include <string.h>
 
42
#endif
 
43
 
 
44
#include "vmware.h"
 
45
#include "hgfsEscape.h"
 
46
#include "cpName.h"
 
47
 
 
48
#ifdef _WIN32
 
49
 
 
50
#define UNREFERENCED_PARAMETER(P) (P)
 
51
 
 
52
/* These characters are illegal in Windows file names. */
 
53
const char* HGFS_ILLEGAL_CHARS = "/\\*?:\"<>|";
 
54
const char* HGFS_SUBSTITUTE_CHARS = "!@#$^&(){}";
 
55
/* Last character of a file name in Windows can be neither dot nor space. */
 
56
const char* HGFS_ILLEGAL_LAST_CHARS = ". ";
 
57
 
 
58
/* http://msdn.microsoft.com/en-us/library/aa365247.aspx */
 
59
char *HgfsReservedNames[] = {"CON", "PRN", "AUX", "NUL"};
 
60
char *HgfsReservedNamesWithNumber[] = {"COM", "LPT"};
 
61
 
 
62
#define HGFS_RESERVED_NAME_CHARS_LENGTH 3
 
63
#define HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH (HGFS_RESERVED_NAME_CHARS_LENGTH + 1)
 
64
/* Check for special escaping cases - reserved names and illegal last characters. */
 
65
#define IS_SPECIAL_CASE_ESCAPE(b,o,l) HgfsIsSpecialCaseEscape(b,o,l)
 
66
/* Process Windows reserved names. */
 
67
#define PROCESS_RESERVED_NAME(b,s,p,o,c) \
 
68
if (!HgfsProcessReservedName(b,s,p,o,c)) \
 
69
{ \
 
70
 return FALSE; \
 
71
}
 
72
/* Process Windows reserved names. */
 
73
#define PROCESS_LAST_CHARACTER(b,s,p,c) \
 
74
if (!HgfsProcessLastCharacter(b,s,p,c)) \
 
75
{ \
 
76
 return FALSE; \
 
77
}
 
78
 
 
79
#else // _WIN32
 
80
 
 
81
#define UNREFERENCED_PARAMETER(P)
 
82
/* There is no special escape sequences on other than Windows platforms. */
 
83
#define IS_SPECIAL_CASE_ESCAPE(b,o,l) FALSE
 
84
/* There is no reserved names on other then Windows platforms. */
 
85
#define PROCESS_RESERVED_NAME(b,s,p,o,c)
 
86
/* There is no special processing for the last character on non-Windows platforms. */
 
87
#define PROCESS_LAST_CHARACTER(b,s,p,c)
 
88
 
 
89
#if defined(__APPLE__)
 
90
/* These characters are illegal in MAC OS file names. */
 
91
const char* HGFS_ILLEGAL_CHARS = "/:";
 
92
const char* HGFS_SUBSTITUTE_CHARS = "!&";
 
93
#else   // __APPLE__
 
94
/* These characters are illegal in Linux file names. */
 
95
const char* HGFS_ILLEGAL_CHARS = "/";
 
96
const char* HGFS_SUBSTITUTE_CHARS = "!";
 
97
#endif  // __APPLE__
 
98
 
 
99
#endif  // _WIN32
 
100
 
 
101
#define HGFS_ESCAPE_CHAR '%'
 
102
#define HGFS_ESCAPE_SUBSTITUE_CHAR ']'
 
103
 
 
104
typedef enum {
 
105
   HGFS_ESCAPE_ILLEGAL_CHARACTER,
 
106
   HGFS_ESCAPE_RESERVED_NAME,
 
107
   HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER,
 
108
   HGFS_ESCAPE_ESCAPE_SEQUENCE,
 
109
   HGFS_ESCAPE_COMPLETE
 
110
} HgfsEscapeReason;
 
111
 
 
112
 
 
113
typedef Bool (*HgfsEnumCallback)(char const *bufIn,
 
114
                                 uint32 offset,
 
115
                                 HgfsEscapeReason reason,
 
116
                                 void* context);
 
117
 
 
118
/*
 
119
 * The structure is used by HgfsAddEscapeCharacter to keep context information between
 
120
 * invocations
 
121
 * All offsets defined in this structure are in characters, not bytes
 
122
 */
 
123
typedef  struct {
 
124
   uint32   processedOffset;     // Offset of the first unprocessed input character
 
125
   uint32   outputBufferLength;  // Number of characters in the output buffer
 
126
   uint32   outputOffset;        // Number of characters that are already in the output
 
127
   char    *outputBuffer;        // Pointer to the output buffer
 
128
} HgfsEscapeContext;
 
129
 
 
130
static void HgfsEscapeUndoComponent(char *bufIn, uint32 *totalLength);
 
131
static int HgfsEscapeGetComponentSize(char const *bufIn, uint32 sizeIn);
 
132
static int HgfsEscapeDoComponent(char const *bufIn, uint32 sizeIn, uint32 sizeBufOut,
 
133
                                 char *bufOut);
 
134
 
 
135
/*
 
136
 *-----------------------------------------------------------------------------
 
137
 *
 
138
 * HgfsAddEscapeCharacter --
 
139
 *
 
140
 *    Callback function that is called by HgfsEnumerate to insert an escape sequence
 
141
 *    into the input name.
 
142
 *
 
143
 * Results:
 
144
 *    TRUE if successful, FALSE if there is an error like the output buffer is
 
145
 *    too small.
 
146
 *
 
147
 * Side effects:
 
148
 *    Updates the output buffer pointer (stored in the context variable).
 
149
 *
 
150
 *-----------------------------------------------------------------------------
 
151
 */
 
152
 
 
153
static Bool
 
154
HgfsAddEscapeCharacter(char const * bufIn,      // IN: input name
 
155
                       uint32 offset,           // IN: offset that requires escaping
 
156
                       HgfsEscapeReason reason, // IN: reason for esaping
 
157
                       void *context)           // IN/OUT: convertion context
 
158
{
 
159
   HgfsEscapeContext *escapeContext = (HgfsEscapeContext *)context;
 
160
   uint32 charactersToCopy;
 
161
   uint32 outputSpace;
 
162
   char* illegal;
 
163
   Bool result = TRUE;
 
164
 
 
165
   ASSERT(offset >= escapeContext->processedOffset); // Scanning forward
 
166
   charactersToCopy = offset - escapeContext->processedOffset;
 
167
 
 
168
   if (escapeContext->outputOffset + charactersToCopy >
 
169
       escapeContext->outputBufferLength) {
 
170
      return FALSE;
 
171
   }
 
172
 
 
173
   memcpy(escapeContext->outputBuffer + escapeContext->outputOffset,
 
174
          bufIn + escapeContext->processedOffset, charactersToCopy * sizeof *bufIn);
 
175
   escapeContext->outputOffset += charactersToCopy;
 
176
   escapeContext->processedOffset += charactersToCopy;
 
177
 
 
178
   outputSpace = escapeContext->outputBufferLength - escapeContext->outputOffset;
 
179
 
 
180
   switch(reason) {
 
181
   case HGFS_ESCAPE_ILLEGAL_CHARACTER:
 
182
      if (outputSpace < 2) {
 
183
         return FALSE;
 
184
      }
 
185
      illegal = strchr(HGFS_ILLEGAL_CHARS, bufIn[escapeContext->processedOffset]);
 
186
      escapeContext->processedOffset++;  // Skip illegal input character
 
187
      ASSERT(illegal != NULL);
 
188
      escapeContext->outputBuffer[escapeContext->outputOffset] =
 
189
         HGFS_SUBSTITUTE_CHARS[illegal - HGFS_ILLEGAL_CHARS];
 
190
      escapeContext->outputOffset++;
 
191
      escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
 
192
      escapeContext->outputOffset++;
 
193
      break;
 
194
 
 
195
   case HGFS_ESCAPE_RESERVED_NAME:
 
196
      if (outputSpace < 1) {
 
197
         return FALSE;
 
198
      }
 
199
      escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
 
200
      escapeContext->outputOffset++;
 
201
      break;
 
202
 
 
203
   case HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER:
 
204
      if (outputSpace < 1) {
 
205
         return FALSE;
 
206
      }
 
207
      escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
 
208
      escapeContext->outputOffset++;
 
209
      break;
 
210
 
 
211
   case HGFS_ESCAPE_ESCAPE_SEQUENCE:
 
212
      if (outputSpace < 2) {
 
213
         return FALSE;
 
214
      }
 
215
      escapeContext->processedOffset++; // Skip input esape character
 
216
      escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_SUBSTITUE_CHAR;
 
217
      escapeContext->outputOffset++;
 
218
      escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
 
219
      escapeContext->outputOffset++;
 
220
      break;
 
221
 
 
222
   case HGFS_ESCAPE_COMPLETE:
 
223
      if (outputSpace < 1) {
 
224
         return FALSE;
 
225
      }
 
226
      escapeContext->outputBuffer[escapeContext->outputOffset] = '\0';
 
227
      break;
 
228
 
 
229
   default:
 
230
      result = FALSE;
 
231
      ASSERT(FALSE);
 
232
   }
 
233
   return result;
 
234
}
 
235
 
 
236
 
 
237
/*
 
238
 *-----------------------------------------------------------------------------
 
239
 *
 
240
 * HgfsCountEscapeChars --
 
241
 *
 
242
 *    Callback function that is called by HgfsEnumerate to count additional characters
 
243
 *    that need to be inserted in the input name.
 
244
 *
 
245
 * Results:
 
246
 *    TRUE since it never fails.
 
247
 *
 
248
 * Side effects:
 
249
 *    None
 
250
 *
 
251
 *-----------------------------------------------------------------------------
 
252
 */
 
253
 
 
254
static Bool
 
255
HgfsCountEscapeChars(char const *bufIn,       // IN: input name
 
256
                     uint32 offset,           // IN: offset where escape is needed
 
257
                     HgfsEscapeReason reason, // IN: reason for escaping
 
258
                     void *context)           // IN/OUT: context info
 
259
{
 
260
   UNREFERENCED_PARAMETER(bufIn);
 
261
   UNREFERENCED_PARAMETER(offset);
 
262
   if (reason != HGFS_ESCAPE_COMPLETE) {
 
263
      uint32 *counter = (uint32*)context;
 
264
      (*counter)++;
 
265
   }
 
266
   return TRUE;
 
267
}
 
268
 
 
269
 
 
270
#ifdef _WIN32
 
271
/*
 
272
 *-----------------------------------------------------------------------------
 
273
 *
 
274
 * HgfsLetterToUpper --
 
275
 *
 
276
 *    Converts lowercase English letters to uppercase.
 
277
 *    If the symbol is not a lowercase English letter returns the original character.
 
278
 *
 
279
 * Results:
 
280
 *    Converted character.
 
281
 *
 
282
 * Side effects:
 
283
 *    None
 
284
 *
 
285
 *-----------------------------------------------------------------------------
 
286
 */
 
287
 
 
288
static char
 
289
HgfsLetterToUpper(char letter)
 
290
{
 
291
   if (letter >= 'a' && letter <= 'z') {
 
292
      return letter - ('a' - 'A');
 
293
   }
 
294
   return letter;
 
295
}
 
296
 
 
297
 
 
298
/*
 
299
 *-----------------------------------------------------------------------------
 
300
 *
 
301
 * HgfsIsEqualPrefix --
 
302
 *
 
303
 *    Verifies if the string prefix is equal to the given prefix.
 
304
 *    It assumes that the prefix includes only uppercase English letters or numbers
 
305
 *    and it does not have any international characters.
 
306
 *    The string must be either NULL terminated or not shorter then the prefix.
 
307
 *
 
308
 * Results:
 
309
 *    TRUE if the uppcased string starts with the given prefix. False otherwise.
 
310
 *
 
311
 * Side effects:
 
312
 *    None
 
313
 *
 
314
 *-----------------------------------------------------------------------------
 
315
 */
 
316
 
 
317
static Bool
 
318
HgfsIsEqualPrefix(char const *prefix,  // IN: prefix to check
 
319
                  char const *string,  // IN: input string
 
320
                  uint32 prefixLength) // IN: length of the prefix in characters
 
321
{
 
322
   int i;
 
323
   for (i = 0; i < prefixLength; i++) {
 
324
      ASSERT(prefix[i] > 0 && (prefix[i] < 'a' || prefix[i] > 'z' ));
 
325
      if (prefix[i] != HgfsLetterToUpper(string[i])) {
 
326
         return FALSE;
 
327
      }
 
328
   }
 
329
   return TRUE;
 
330
}
 
331
 
 
332
 
 
333
/*
 
334
 *-----------------------------------------------------------------------------
 
335
 *
 
336
 * HgfsIsReservedPrefix --
 
337
 *
 
338
 *    Verifies if the name's prefix is one of the reserved names.
 
339
 *
 
340
 * Results:
 
341
 *    TRUE if the name's prefix is one of the reserved names.
 
342
 *
 
343
 * Side effects:
 
344
 *    None.
 
345
 *
 
346
 *-----------------------------------------------------------------------------
 
347
 */
 
348
 
 
349
static Bool
 
350
HgfsIsReservedPrefix(char const *bufIn)  // IN: input name
 
351
{
 
352
   uint32 i;
 
353
   for (i = 0; i < ARRAYSIZE(HgfsReservedNames); i++) {
 
354
      if (HgfsIsEqualPrefix(HgfsReservedNames[i], bufIn,
 
355
                            HGFS_RESERVED_NAME_CHARS_LENGTH)) {
 
356
         return TRUE;
 
357
      }
 
358
   }
 
359
   return FALSE;
 
360
}
 
361
 
 
362
 
 
363
/*
 
364
 *-----------------------------------------------------------------------------
 
365
 *
 
366
 * HgfsIsReservedPrefixWithNumber --
 
367
 *
 
368
 *    Verifies if the name's prefix is one of the reserved names with number:
 
369
 *    COM1-9 or LPT1-9.
 
370
 *
 
371
 * Results:
 
372
 *    TRUE if the name's prefix is one of the reserved names with number.
 
373
 *
 
374
 * Side effects:
 
375
 *    None.
 
376
 *
 
377
 *-----------------------------------------------------------------------------
 
378
 */
 
379
 
 
380
static Bool
 
381
HgfsIsReservedPrefixWithNumber(char const *bufIn)   // IN: input name
 
382
{
 
383
   uint32 i;
 
384
   for (i = 0; i < ARRAYSIZE(HgfsReservedNamesWithNumber); i++) {
 
385
      if (HgfsIsEqualPrefix(HgfsReservedNamesWithNumber[i], bufIn,
 
386
                            HGFS_RESERVED_NAME_CHARS_LENGTH) &&
 
387
          bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] >= '1' &&
 
388
          bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] <= '9') {
 
389
         return TRUE;
 
390
      }
 
391
   }
 
392
   return FALSE;
 
393
}
 
394
 
 
395
 
 
396
/*
 
397
 *-----------------------------------------------------------------------------
 
398
 *
 
399
 * HgfsIsSpecialCaseEscape --
 
400
 *
 
401
 *    Verifies if the escape character is a part of special case escape sequence
 
402
 *    that exists only in Windows - escaped reserved name or escaped illegal last
 
403
 *    character.
 
404
 *
 
405
 * Results:
 
406
 *    TRUE if the name's prefix is one of the reserved names with number.
 
407
 *
 
408
 * Side effects:
 
409
 *    None.
 
410
 *
 
411
 *-----------------------------------------------------------------------------
 
412
 */
 
413
 
 
414
static Bool
 
415
HgfsIsSpecialCaseEscape(char const *bufIn,   // IN: input name
 
416
                        uint32 offset,       // IN: offset of the escape character
 
417
                        uint32 length)       // IN: length of the name in characters
 
418
{
 
419
   if (offset + 1 == length &&
 
420
      strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[offset - 1]) != NULL) {
 
421
      return TRUE;
 
422
   }
 
423
   if (offset == HGFS_RESERVED_NAME_CHARS_LENGTH &&
 
424
      (length == HGFS_RESERVED_NAME_CHARS_LENGTH + 1 || bufIn[offset+1] == '.')) {
 
425
      return HgfsIsReservedPrefix(bufIn);
 
426
   }
 
427
   if (offset == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH &&
 
428
      (length == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH + 1 ||
 
429
      bufIn[offset+1] == '.')) {
 
430
      return HgfsIsReservedPrefixWithNumber(bufIn);
 
431
   }
 
432
   return FALSE;
 
433
}
 
434
 
 
435
 
 
436
/*
 
437
 *-----------------------------------------------------------------------------
 
438
 *
 
439
 * HgfsProcessReservedName --
 
440
 *
 
441
 *    Verifies if the name is one of reserved Windows file names.
 
442
 *    If it is a reserved name invokes callback that performs required
 
443
 *    processing.
 
444
 *
 
445
 * Results:
 
446
 *    TRUE if no processing is required of if processing succeeded,
 
447
 *    FALSE if processing failed.
 
448
 *
 
449
 * Side effects:
 
450
 *    None.
 
451
 *
 
452
 *-----------------------------------------------------------------------------
 
453
 */
 
454
 
 
455
static Bool
 
456
HgfsProcessReservedName(char const *bufIn,              // IN:  Unescaped input buffer
 
457
                        uint32 sizeIn,                  // IN:  Length of the input
 
458
                        HgfsEnumCallback processEscape, // IN:  Callack that is invoked
 
459
                                                        //      if input is reserved name
 
460
                        uint32 *offset,                 // OUT: New offset in the input
 
461
                        void *context)                  // IN/OUT: Context for callback
 
462
{
 
463
   /*  Look reserved names: CON, PRN, AUX, NUL. */
 
464
   if (sizeIn >= HGFS_RESERVED_NAME_CHARS_LENGTH && HgfsIsReservedPrefix(bufIn)) {
 
465
      if (HGFS_RESERVED_NAME_CHARS_LENGTH == sizeIn ||
 
466
         bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] == '.') {
 
467
         if (!processEscape(bufIn, HGFS_RESERVED_NAME_CHARS_LENGTH,
 
468
                            HGFS_ESCAPE_RESERVED_NAME, context)) {
 
469
            return FALSE;
 
470
         }
 
471
         *offset = HGFS_RESERVED_NAME_CHARS_LENGTH;
 
472
      }
 
473
   }
 
474
 
 
475
   /*  Look reserved names with numbers: COM1-9 and LPT1-9. */
 
476
   if (sizeIn >= HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH &&
 
477
       HgfsIsReservedPrefixWithNumber(bufIn)) {
 
478
      if (HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH == sizeIn ||
 
479
         bufIn[HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH] == '.') {
 
480
         if (!processEscape(bufIn, HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH,
 
481
                            HGFS_ESCAPE_RESERVED_NAME, context)) {
 
482
            return FALSE;
 
483
         }
 
484
         *offset = HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH;
 
485
      }
 
486
   }
 
487
   return TRUE;
 
488
}
 
489
 
 
490
 
 
491
/*
 
492
 *-----------------------------------------------------------------------------
 
493
 *
 
494
 * HgfsProcessLastCharacter --
 
495
 *
 
496
 *    Verifies if the trailing character in the name is a valid last character.
 
497
 *    In Windows it is illegal to have a file name that ends with dot ('.') or
 
498
 *    space (' '). The only exception is "." and ".." directory names.
 
499
 *    If the last character is invalid the function invokes a callback to process it.
 
500
 *
 
501
 * Results:
 
502
 *    TRUE if no processing is required of if processing succeeded,
 
503
 *    FALSE if processing failed.
 
504
 *
 
505
 * Side effects:
 
506
 *    None.
 
507
 *
 
508
 *-----------------------------------------------------------------------------
 
509
 */
 
510
 
 
511
static Bool
 
512
HgfsProcessLastCharacter(char const *bufIn,              // IN:  Unescaped input buffer
 
513
                         uint32 sizeIn,                  // IN:  Length of the input
 
514
                         HgfsEnumCallback processEscape, // IN:  Callack that is invoked
 
515
                                                         //      when escaping is needed
 
516
                         void *context)                  // IN/OUT: Callback context
 
517
{
 
518
 
 
519
   /* If the filename is '.' or '..' we shouldn't escape it. */
 
520
   if ((sizeIn == 1 && bufIn[0] == '.') ||
 
521
       (sizeIn == 2 && bufIn[0] == '.' && bufIn[1] == '.')) {
 
522
      return TRUE;
 
523
   }
 
524
 
 
525
   /* Invoke the callback if the last character is illegal. */
 
526
   if (strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[sizeIn - 1]) != NULL) {
 
527
      if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER, context)) {
 
528
         return FALSE;
 
529
      }
 
530
   }
 
531
   return TRUE;
 
532
}
 
533
 
 
534
#endif //  WIN32
 
535
 
 
536
 
 
537
/*
 
538
 *-----------------------------------------------------------------------------
 
539
 *
 
540
 * HgfsIsEscapeSequence --
 
541
 *
 
542
 *    Verifies if input buffer has an escape sequence at the position
 
543
 *    defined by offset.
 
544
 *
 
545
 * Results:
 
546
 *    TRUE if there is an escape sequence at the position defined by offset.
 
547
 *
 
548
 * Side effects:
 
549
 *    None.
 
550
 *
 
551
 *-----------------------------------------------------------------------------
 
552
 */
 
553
 
 
554
static Bool
 
555
HgfsIsEscapeSequence(char const *bufIn,   // IN: input name
 
556
                     uint32 offset,       // IN: offset of the escape character
 
557
                     uint32 length)       // IN: length of the name in characters
 
558
{
 
559
   if (bufIn[offset] == HGFS_ESCAPE_CHAR && offset > 0) {
 
560
      char *substitute;
 
561
      if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR) {
 
562
         return TRUE;
 
563
      }
 
564
      substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]);
 
565
      if (substitute != NULL) {
 
566
         return TRUE;
 
567
      }
 
568
      return IS_SPECIAL_CASE_ESCAPE(bufIn,offset,length);
 
569
   }
 
570
   return FALSE;
 
571
}
 
572
 
 
573
 
 
574
/*
 
575
 *-----------------------------------------------------------------------------
 
576
 *
 
577
 * HgfsEscapeEnumerate --
 
578
 *
 
579
 *    The function scans the input buffer and calls processEscape callback for every
 
580
 *    place in the input buffer which require escaping.
 
581
 *
 
582
 *    Callback does the required processing. There are two different callbacks -
 
583
 *    one counts extra symbols that are needed for escaping and another produces
 
584
 *    escaped output name based on input name.
 
585
 *
 
586
 *    1. The first function calculates number of extra characters. It just increments
 
587
 *    a counter which is passed to it in context variable every time it is called
 
588
 *    for the reason different from "complete processing" assuming that
 
589
 *    exactly one extra  character is required to escape any invalid input.
 
590
 *
 
591
 *    2. The second function produces output name by copying everything from input
 
592
 *    name into the output name up to the place which require escaping and
 
593
 *    then inserts appropriate escape sequence into the output. It keeps track of its
 
594
 *    progress and keeps pointer to the output buffer in the context variable.
 
595
 *    HgfsEscapeEnumerate calls calback function one more time at the end of the
 
596
 *    input buffer to let callback finish processing of the input (for example copy
 
597
 *    the rest of the name after the last escape sequence from input buffer to
 
598
 *    output buffer).
 
599
 *
 
600
 * Results:
 
601
 *    TRUE if the input has been processed successfully by the callback, false otherwise.
 
602
 *
 
603
 * Side effects:
 
604
 *    None.
 
605
 *
 
606
 *-----------------------------------------------------------------------------
 
607
 */
 
608
 
 
609
static Bool
 
610
HgfsEscapeEnumerate(char const *bufIn,              // IN:  Buffer with unescaped input
 
611
                    uint32 sizeIn,                  // IN:  Number of input *characters*
 
612
                    HgfsEnumCallback processEscape, // IN: Callack that is invoked every
 
613
                                                    //     time escaping is required
 
614
                    void *context)                  // IN/OUT: Context for processEscape
 
615
{
 
616
   /*  First look for invalid characters in the input name. */
 
617
   uint32 i, offset = 0;
 
618
   if (sizeIn == 0) {
 
619
      return TRUE;
 
620
   }
 
621
 
 
622
   ASSERT(processEscape);
 
623
 
 
624
   PROCESS_RESERVED_NAME(bufIn, sizeIn, processEscape, &offset, context);
 
625
 
 
626
   for (i = offset; i < sizeIn; i++) {
 
627
      if (strchr(HGFS_ILLEGAL_CHARS, bufIn[i]) != NULL) {
 
628
         if (!processEscape(bufIn, i, HGFS_ESCAPE_ILLEGAL_CHARACTER, context)) {
 
629
            return FALSE;
 
630
         }
 
631
      } else if (HgfsIsEscapeSequence(bufIn, i, sizeIn)) {
 
632
         if (!processEscape(bufIn, i, HGFS_ESCAPE_ESCAPE_SEQUENCE, context)) {
 
633
            return FALSE;
 
634
         }
 
635
      }
 
636
   }
 
637
 
 
638
   PROCESS_LAST_CHARACTER(bufIn, sizeIn, processEscape, context);
 
639
 
 
640
   if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_COMPLETE, context)) {
 
641
      return FALSE;
 
642
   }
 
643
 
 
644
   return TRUE;
 
645
}
 
646
 
 
647
 
 
648
/*
 
649
 *-----------------------------------------------------------------------------
 
650
 *
 
651
 * HgfsEscape_Do --
 
652
 *
 
653
 *    Escape any characters that are not legal in a windows filename.
 
654
 *    Escape reserved file names that can't be used in Windows.
 
655
 *    We also of course have to escape the escape character, which is "%",
 
656
 *    when it is part of a character sequence that would require unescaping
 
657
 *
 
658
 *    sizeBufOut must account for the NUL terminator.
 
659
 *
 
660
 * Results:
 
661
 *    On success, the size (excluding the NUL terminator) of the
 
662
 *    escaped, NUL terminated buffer.
 
663
 *    On failure (bufOut not big enough to hold result), negative value.
 
664
 *
 
665
 * Side effects:
 
666
 *    None
 
667
 *
 
668
 *-----------------------------------------------------------------------------
 
669
 */
 
670
 
 
671
int
 
672
HgfsEscape_Do(char const *bufIn, // IN:  Buffer with unescaped input
 
673
                   uint32 sizeIn,     // IN:  Size of input buffer
 
674
                   uint32 sizeBufOut, // IN:  Size of output buffer
 
675
                   char *bufOut)      // OUT: Buffer for escaped output
 
676
{
 
677
   const char *currentComponent = bufIn;
 
678
   uint32 sizeLeft = sizeBufOut;
 
679
   char *outPointer = bufOut;
 
680
   const char *end = bufIn + sizeIn;
 
681
   const char *next;
 
682
   ASSERT(sizeIn > 0);
 
683
   if (bufIn[sizeIn - 1] == '\0') {
 
684
      /*
 
685
       * In some cases a NUL terminated string is passed to HgfsEscape_Do
 
686
       * so it make sense to support such input even if CPName_GetComponent
 
687
       * does not. Detect this case and make the input compliant with
 
688
       * CPName_GetComponent by removing terminating NUL.
 
689
       */
 
690
      end--;
 
691
      sizeIn--;
 
692
   }
 
693
   /*
 
694
    * Absolute symbolic link name starts with the '\0'. HgfsEscapeDo needs to work
 
695
    * with such names. Leading NULL symbols should be skipped here since
 
696
    * CPName_GetComponent does not support such names.
 
697
    */
 
698
   while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) {
 
699
      currentComponent++;
 
700
      sizeLeft--;
 
701
      *outPointer++ = '\0';
 
702
   }
 
703
   while (currentComponent - bufIn < sizeIn) {
 
704
      int escapedLength;
 
705
      uint32 componentSize = CPName_GetComponent(currentComponent, end, &next);
 
706
 
 
707
      escapedLength = HgfsEscapeDoComponent(currentComponent, componentSize,
 
708
                                            sizeLeft, outPointer);
 
709
      if (escapedLength < 0) {
 
710
         return escapedLength;
 
711
      }
 
712
      currentComponent = next;
 
713
      sizeLeft -= escapedLength + 1;
 
714
      outPointer += escapedLength + 1;
 
715
   }
 
716
   return (int) (outPointer - bufOut) - 1; // Do not count the last NUL terminator
 
717
}
 
718
 
 
719
/*
 
720
 *-----------------------------------------------------------------------------
 
721
 *
 
722
 * HgfsEscape_GetSize --
 
723
 *
 
724
 *    Calculates required size in bytes for the buffer that is needed to hold escaped
 
725
 *    cross platform path name. Returns 0 if no escaping is required.
 
726
 *
 
727
 * Results:
 
728
 *    On success, the size (excluding the NUL terminator) of the
 
729
 *    escaped, NUL terminated buffer.
 
730
 *    Returns 0 if the name is a valid Windows file name.
 
731
 *
 
732
 * Side effects:
 
733
 *    None
 
734
 *
 
735
 *-----------------------------------------------------------------------------
 
736
 */
 
737
 
 
738
int
 
739
HgfsEscape_GetSize(char const *bufIn,    // IN:  Buffer with unescaped input
 
740
                   uint32 sizeIn)        // IN:  Size of the input buffer
 
741
{
 
742
   uint32 result = 0;
 
743
   const char *currentComponent = bufIn;
 
744
   const char *end = bufIn + sizeIn;
 
745
   const char *next;
 
746
 
 
747
   if (sizeIn == 0) { // No need toescape empty name.
 
748
      return 0;
 
749
   }
 
750
   if (bufIn[sizeIn - 1] == '\0') {
 
751
      /*
 
752
       * In some cases a NUL terminated string is passed to HgfsEscape_GeSize
 
753
       * so it make sense to support such input even if CPName_GetComponent
 
754
       * does not. Detect this case and make the input compliant with
 
755
       * CPName_GetComponent by removing terminating NUL.
 
756
       */
 
757
      end--;
 
758
      sizeIn--;
 
759
   }
 
760
   /* Skip leading NULs to keep CPName_GetComponent happy. */
 
761
   while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) {
 
762
      currentComponent++;
 
763
   }
 
764
   while (currentComponent - bufIn < sizeIn) {
 
765
      uint32 componentSize = CPName_GetComponent(currentComponent, end, &next);
 
766
      result += HgfsEscapeGetComponentSize(currentComponent, componentSize);
 
767
      currentComponent = next;
 
768
   }
 
769
   return (result == 0) ? 0 : result + sizeIn;
 
770
}
 
771
 
 
772
 
 
773
/*
 
774
 *-----------------------------------------------------------------------------
 
775
 *
 
776
 * HgfsEscape_Undo --
 
777
 *
 
778
 *    Unescape a buffer that was escaped using HgfsEscapeBuffer.
 
779
 *
 
780
 *    The unescaping is done in place in the input buffer, and
 
781
 *    can not fail.
 
782
 *
 
783
 * Results:
 
784
 *    The size (excluding the NUL terminator) of the unescaped, NUL
 
785
 *    terminated buffer.
 
786
 *
 
787
 * Side effects:
 
788
 *    None
 
789
 *
 
790
 *-----------------------------------------------------------------------------
 
791
 */
 
792
 
 
793
int
 
794
HgfsEscape_Undo(char *bufIn,       // IN: Characters to be unescaped
 
795
                uint32 sizeIn)     // IN: Number of characters in bufIn
 
796
{
 
797
   uint32 componentSize = strlen(bufIn) + 1;
 
798
   uint32 unprocessedSize = sizeIn + 1;
 
799
   uint32 result = 0;
 
800
   char *currentComponent = bufIn;
 
801
   while (currentComponent != NULL) {
 
802
      HgfsEscapeUndoComponent(currentComponent, &unprocessedSize);
 
803
      componentSize = strlen(currentComponent) + 1; // Unescaped size
 
804
      result += componentSize;
 
805
      if (unprocessedSize > 1) {
 
806
         currentComponent = currentComponent + componentSize;
 
807
         componentSize = strlen(currentComponent) + 1; // Size of the next component
 
808
      } else {
 
809
         currentComponent = NULL;
 
810
      }
 
811
   }
 
812
   return result - 1;
 
813
}
 
814
 
 
815
 
 
816
/*
 
817
 *-----------------------------------------------------------------------------
 
818
 *
 
819
 * HgfsEscapeUndoComponent --
 
820
 *
 
821
 *    Unescape a buffer that was escaped using HgfsEscapeBuffer.
 
822
 *
 
823
 *    The unescaping is done in place in the input buffer, and
 
824
 *    can not fail.
 
825
 *
 
826
 * Results:
 
827
 *    None
 
828
 *
 
829
 * Side effects:
 
830
 *    None
 
831
 *
 
832
 *-----------------------------------------------------------------------------
 
833
 */
 
834
 
 
835
void
 
836
HgfsEscapeUndoComponent(char   *bufIn,             // IN: Characters to be unescaped
 
837
                        uint32 *unprocessedLength) // IN: Unprocessed characters
 
838
                                                   //     in the whole name
 
839
{
 
840
   size_t offset;
 
841
   size_t sizeIn = strlen(bufIn);
 
842
   char* curOutBuffer = bufIn;
 
843
   char* escapePointer;
 
844
   ASSERT(bufIn);
 
845
 
 
846
   escapePointer = strchr(curOutBuffer, HGFS_ESCAPE_CHAR);
 
847
   while (escapePointer != NULL) {
 
848
      offset = escapePointer - bufIn;
 
849
      if (HgfsIsEscapeSequence(bufIn, offset, sizeIn)) {
 
850
         char* substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]);
 
851
         if (substitute != NULL) {
 
852
            bufIn[offset - 1] = HGFS_ILLEGAL_CHARS[substitute - HGFS_SUBSTITUTE_CHARS];
 
853
         } else if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR) {
 
854
            bufIn[offset - 1] = HGFS_ESCAPE_CHAR;
 
855
         }
 
856
         memmove(escapePointer, escapePointer + 1, (*unprocessedLength) - offset - 1);
 
857
         (*unprocessedLength)--;
 
858
         sizeIn--;
 
859
         if (sizeIn > 0) {
 
860
            escapePointer = strchr(escapePointer, HGFS_ESCAPE_CHAR);
 
861
         } else {
 
862
            escapePointer = NULL;
 
863
         }
 
864
      } else {
 
865
         escapePointer = strchr(escapePointer + 1, HGFS_ESCAPE_CHAR);
 
866
      }
 
867
   }
 
868
   ASSERT((*unprocessedLength) > sizeIn);
 
869
   (*unprocessedLength) -= sizeIn + 1;
 
870
}
 
871
 
 
872
 
 
873
/*
 
874
 *-----------------------------------------------------------------------------
 
875
 *
 
876
 * HgfsEscapeDoComponent --
 
877
 *
 
878
 *    Escape any characters that are not legal in a windows filename.
 
879
 *    Escape reserved file names that can't be used in Windows.
 
880
 *    We also of course have to escape the escape character, which is "%",
 
881
 *    when it is part of a character sequence that would require unescaping
 
882
 *
 
883
 *    sizeBufOut must account for the NUL terminator.
 
884
 *
 
885
 * Results:
 
886
 *    On success, the size (excluding the NUL terminator) of the
 
887
 *    escaped, NUL terminated buffer.
 
888
 *    On failure (bufOut not big enough to hold result), negative value.
 
889
 *
 
890
 * Side effects:
 
891
 *    None
 
892
 *
 
893
 *-----------------------------------------------------------------------------
 
894
 */
 
895
 
 
896
int
 
897
HgfsEscapeDoComponent(char const *bufIn, // IN:  Buffer with unescaped input
 
898
                           uint32 sizeIn,     // IN:  Size of input buffer
 
899
                           uint32 sizeBufOut, // IN:  Size of output buffer
 
900
                           char *bufOut)      // OUT: Buffer for escaped output
 
901
{
 
902
   HgfsEscapeContext conversionContext;
 
903
   conversionContext.processedOffset = 0;
 
904
   conversionContext.outputBufferLength = sizeBufOut / sizeof *bufOut;
 
905
   conversionContext.outputOffset = 0;
 
906
   conversionContext.outputBuffer = bufOut;
 
907
 
 
908
   if (!HgfsEscapeEnumerate(bufIn, sizeIn, HgfsAddEscapeCharacter, &conversionContext)) {
 
909
      return -1;
 
910
   }
 
911
   return conversionContext.outputOffset * sizeof *bufOut;
 
912
}
 
913
 
 
914
 
 
915
/*
 
916
 *-----------------------------------------------------------------------------
 
917
 *
 
918
 * HgfsEscapeGetComponentSize --
 
919
 *
 
920
 *    Calculates number of addtitional characters that are needed to escape
 
921
 *    name for one NUL terminated component of the path.
 
922
 *
 
923
 * Results:
 
924
 *    Number of additional escape characters needed to escape the name.
 
925
 *    Returns 0 if no escaping is required.
 
926
 *
 
927
 * Side effects:
 
928
 *    None
 
929
 *
 
930
 *-----------------------------------------------------------------------------
 
931
 */
 
932
 
 
933
int
 
934
HgfsEscapeGetComponentSize(char const *bufIn, // IN:  Buffer with unescaped input
 
935
                           uint32 sizeIn)     // IN:  Size of the in input buffer
 
936
{
 
937
   int result = 0;
 
938
   HgfsEscapeEnumerate(bufIn, sizeIn, HgfsCountEscapeChars, &result);
 
939
   return result;
 
940
}