VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedFolders/vbsf.cpp@ 18756

Last change on this file since 18756 was 18593, checked in by vboxsync, 16 years ago

HostServices/SharedFolders: on non-windows (=posix) host use 0666 as base mode

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.2 KB
Line 
1/** @file
2 *
3 * Shared Folders:
4 * VBox Shared Folders.
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#include "mappings.h"
24#include "vbsf.h"
25#include "shflhandle.h"
26
27#include <iprt/alloc.h>
28#include <iprt/assert.h>
29#include <iprt/fs.h>
30#include <iprt/dir.h>
31#include <iprt/file.h>
32#include <iprt/path.h>
33#include <iprt/string.h>
34#include <iprt/uni.h>
35#ifdef RT_OS_DARWIN
36#include <Carbon/Carbon.h>
37#endif
38
39#undef LogFlow
40#define LogFlow Log
41
42void vbsfStripLastComponent (char *pszFullPath, uint32_t cbFullPathRoot)
43{
44 RTUNICP cp;
45
46 /* Do not strip root. */
47 char *s = pszFullPath + cbFullPathRoot;
48 char *delimSecondLast = NULL;
49 char *delimLast = NULL;
50
51 LogFlowFunc(("%s -> %s\n", pszFullPath, s));
52
53 for (;;)
54 {
55 cp = RTStrGetCp(s);
56
57 if (cp == RTUNICP_INVALID || cp == 0)
58 {
59 break;
60 }
61
62 if (cp == RTPATH_DELIMITER)
63 {
64 if (delimLast != NULL)
65 {
66 delimSecondLast = delimLast;
67 }
68
69 delimLast = s;
70 }
71
72 s = RTStrNextCp (s);
73 }
74
75 if (cp == 0)
76 {
77 if (delimLast + 1 == s)
78 {
79 if (delimSecondLast)
80 {
81 *delimSecondLast = 0;
82 }
83 else if (delimLast)
84 {
85 *delimLast = 0;
86 }
87 }
88 else
89 {
90 if (delimLast)
91 {
92 *delimLast = 0;
93 }
94 }
95 }
96
97 LogFlowFunc(("%s, %s, %s\n", pszFullPath, delimLast, delimSecondLast));
98}
99
100static int vbsfCorrectCasing(char *pszFullPath, char *pszStartComponent)
101{
102 PRTDIRENTRYEX pDirEntry = NULL;
103 uint32_t cbDirEntry, cbComponent;
104 int rc = VERR_FILE_NOT_FOUND;
105 PRTDIR hSearch = 0;
106 char szWildCard[4];
107
108 Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent));
109
110 cbComponent = (uint32_t) strlen(pszStartComponent);
111
112 cbDirEntry = 4096;
113 pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
114 if (pDirEntry == 0)
115 {
116 AssertFailed();
117 return VERR_NO_MEMORY;
118 }
119
120 /** @todo this is quite inefficient, especially for directories with many files */
121 Assert(pszFullPath < pszStartComponent-1);
122 Assert(*(pszStartComponent-1) == RTPATH_DELIMITER);
123 *(pszStartComponent-1) = 0;
124 strcpy(pDirEntry->szName, pszFullPath);
125 szWildCard[0] = RTPATH_DELIMITER;
126 szWildCard[1] = '*';
127 szWildCard[2] = 0;
128 strcat(pDirEntry->szName, szWildCard);
129
130 rc = RTDirOpenFiltered (&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT);
131 *(pszStartComponent-1) = RTPATH_DELIMITER;
132 if (RT_FAILURE(rc))
133 goto end;
134
135 for(;;)
136 {
137 size_t cbDirEntrySize = cbDirEntry;
138
139 rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING);
140 if (rc == VERR_NO_MORE_FILES)
141 break;
142
143 if (VINF_SUCCESS != rc && rc != VWRN_NO_DIRENT_INFO)
144 {
145 AssertFailed();
146 if (rc != VERR_NO_TRANSLATION)
147 break;
148 else
149 continue;
150 }
151
152 Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0]));
153 if ( pDirEntry->cbName == cbComponent
154 && !RTStrICmp(pszStartComponent, &pDirEntry->szName[0]))
155 {
156 Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent));
157 strcpy(pszStartComponent, &pDirEntry->szName[0]);
158 rc = VINF_SUCCESS;
159 break;
160 }
161 }
162
163end:
164 if (RT_FAILURE(rc))
165 Log(("vbsfCorrectCasing %s failed with %d\n", pszStartComponent, rc));
166
167 if (pDirEntry)
168 RTMemFree(pDirEntry);
169
170 if (hSearch)
171 RTDirClose(hSearch);
172 return rc;
173}
174
175static int vbsfBuildFullPath (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath,
176 uint32_t cbPath, char **ppszFullPath, uint32_t *pcbFullPathRoot, bool fWildCard = false)
177{
178 int rc = VINF_SUCCESS;
179
180 char *pszFullPath = NULL;
181
182 /* Query UCS2 root prefix for the path, cbRoot is the length in bytes including trailing (RTUTF16)0. */
183 uint32_t cbRoot = 0;
184 PCRTUTF16 pwszRoot = vbsfMappingsQueryHostRoot (root, &cbRoot);
185
186 if (!pwszRoot || cbRoot == 0)
187 {
188 Log(("vbsfBuildFullPath: invalid root!\n"));
189 return VERR_INVALID_PARAMETER;
190 }
191
192 if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
193 {
194 int rc;
195 char *utf8Root;
196
197 rc = RTUtf16ToUtf8 (pwszRoot, &utf8Root);
198 if (RT_SUCCESS (rc))
199 {
200 size_t cbUtf8Root, cbUtf8FullPath;
201 char *utf8FullPath;
202
203 cbUtf8Root = strlen (utf8Root);
204 cbUtf8FullPath = cbUtf8Root + 1 + pPath->u16Length + 1;
205 utf8FullPath = (char *) RTMemAllocZ (cbUtf8FullPath);
206
207 if (!utf8FullPath)
208 {
209 rc = VERR_NO_MEMORY;
210 *ppszFullPath = NULL;
211 Log(("RTMemAllocZ %x failed!!\n", cbUtf8FullPath));
212 }
213 else
214 {
215 memcpy (utf8FullPath, utf8Root, cbUtf8Root);
216 memcpy (utf8FullPath + cbUtf8Root + 1,
217 &pPath->String.utf8[0],
218 pPath->u16Length);
219
220 utf8FullPath[cbUtf8Root] = '/';
221 utf8FullPath[cbUtf8FullPath - 1] = 0;
222 pszFullPath = utf8FullPath;
223
224 if (pcbFullPathRoot)
225 *pcbFullPathRoot = (uint32_t)cbUtf8Root; /* Must index the path delimiter. */
226 }
227
228 RTStrFree (utf8Root);
229 }
230 else
231 {
232 Log (("vbsfBuildFullPath: RTUtf16ToUtf8 failed with %Rrc\n", rc));
233 }
234 }
235 else
236 {
237#ifdef RT_OS_DARWIN
238/** @todo This belongs in rtPathToNative or in the windows shared folder file system driver...
239 * The question is simply whether the NFD normalization is actually applied on a (virtaul) file
240 * system level in darwin, or just by the user mode application libs. */
241 SHFLSTRING *pPathParameter = pPath;
242 size_t cbPathLength;
243 CFMutableStringRef inStr = ::CFStringCreateMutable(NULL, 0);
244 uint16_t ucs2Length;
245 CFRange rangeCharacters;
246
247 // Is 8 times length enough for decomposed in worst case...?
248 cbPathLength = sizeof(SHFLSTRING) + pPathParameter->u16Length * 8 + 2;
249 pPath = (SHFLSTRING *)RTMemAllocZ (cbPathLength);
250 if (!pPath)
251 {
252 rc = VERR_NO_MEMORY;
253 Log(("RTMemAllocZ %x failed!!\n", cbPathLength));
254 return rc;
255 }
256
257 ::CFStringAppendCharacters(inStr, (UniChar*)pPathParameter->String.ucs2, pPathParameter->u16Length / sizeof(pPathParameter->String.ucs2[0]));
258 ::CFStringNormalize(inStr, kCFStringNormalizationFormD);
259 ucs2Length = ::CFStringGetLength(inStr);
260
261 rangeCharacters.location = 0;
262 rangeCharacters.length = ucs2Length;
263 ::CFStringGetCharacters(inStr, rangeCharacters, pPath->String.ucs2);
264 pPath->String.ucs2[ucs2Length] = 0x0000; // NULL terminated
265 pPath->u16Length = ucs2Length * sizeof(pPath->String.ucs2[0]);
266 pPath->u16Size = pPath->u16Length + sizeof(pPath->String.ucs2[0]);
267
268 CFRelease(inStr);
269#endif
270 /* Client sends us UCS2, so convert it to UTF8. */
271 Log(("Root %ls path %.*ls\n", pwszRoot, pPath->u16Length/sizeof(pPath->String.ucs2[0]), pPath->String.ucs2));
272
273 /* Allocate buffer that will be able to contain
274 * the root prefix and the pPath converted to UTF8.
275 * Expect a 2 bytes UCS2 to be converted to 8 bytes UTF8
276 * in worst case.
277 */
278 uint32_t cbFullPath = (cbRoot/sizeof (RTUTF16) + ShflStringLength (pPath)) * 4;
279
280 pszFullPath = (char *)RTMemAllocZ (cbFullPath);
281
282 if (!pszFullPath)
283 {
284 rc = VERR_NO_MEMORY;
285 }
286 else
287 {
288 uint32_t cb = cbFullPath;
289
290 rc = RTUtf16ToUtf8Ex (pwszRoot, RTSTR_MAX, &pszFullPath, cb, NULL);
291 if (RT_FAILURE(rc))
292 {
293 AssertFailed();
294#ifdef RT_OS_DARWIN
295 RTMemFree(pPath);
296 pPath = pPathParameter;
297#endif
298 return rc;
299 }
300
301 char *dst = pszFullPath;
302
303 cbRoot = (uint32_t)strlen(dst);
304 if (dst[cbRoot - 1] != RTPATH_DELIMITER)
305 {
306 dst[cbRoot] = RTPATH_DELIMITER;
307 cbRoot++;
308 }
309
310 if (pcbFullPathRoot)
311 *pcbFullPathRoot = cbRoot - 1; /* Must index the path delimiter. */
312
313 dst += cbRoot;
314 cb -= cbRoot;
315
316 if (pPath->u16Length)
317 {
318 /* Convert and copy components. */
319 PRTUTF16 src = &pPath->String.ucs2[0];
320
321 /* Correct path delimiters */
322 if (pClient->PathDelimiter != RTPATH_DELIMITER)
323 {
324 LogFlow(("Correct path delimiter in %ls\n", src));
325 while (*src)
326 {
327 if (*src == pClient->PathDelimiter)
328 *src = RTPATH_DELIMITER;
329 src++;
330 }
331 src = &pPath->String.ucs2[0];
332 LogFlow(("Corrected string %ls\n", src));
333 }
334 if (*src == RTPATH_DELIMITER)
335 src++; /* we already appended a delimiter to the first part */
336
337 rc = RTUtf16ToUtf8Ex (src, RTSTR_MAX, &dst, cb, NULL);
338 if (RT_FAILURE(rc))
339 {
340 AssertFailed();
341#ifdef RT_OS_DARWIN
342 RTMemFree(pPath);
343 pPath = pPathParameter;
344#endif
345 return rc;
346 }
347
348 uint32_t l = (uint32_t)strlen (dst);
349
350 cb -= l;
351 dst += l;
352
353 Assert(cb > 0);
354 }
355
356 /* Nul terminate the string */
357 *dst = 0;
358 }
359#ifdef RT_OS_DARWIN
360 RTMemFree(pPath);
361 pPath = pPathParameter;
362#endif
363 }
364
365 if (RT_SUCCESS (rc))
366 {
367 /* When the host file system is case sensitive and the guest expects a case insensitive fs, then problems can occur */
368 if ( vbsfIsHostMappingCaseSensitive (root)
369 && !vbsfIsGuestMappingCaseSensitive(root))
370 {
371 RTFSOBJINFO info;
372 char *pszWildCardComponent = NULL;
373
374 if (fWildCard)
375 {
376 /* strip off the last path component, that contains the wildcard(s) */
377 uint32_t len = (uint32_t)strlen(pszFullPath);
378 char *src = pszFullPath + len - 1;
379
380 while(src > pszFullPath)
381 {
382 if (*src == RTPATH_DELIMITER)
383 break;
384 src--;
385 }
386 if (*src == RTPATH_DELIMITER)
387 {
388 bool fHaveWildcards = false;
389 char *temp = src;
390
391 while(*temp)
392 {
393 char uc = *temp;
394 if (uc == '*' || uc == '?' || uc == '>' || uc == '<' || uc == '"')
395 {
396 fHaveWildcards = true;
397 break;
398 }
399 temp++;
400 }
401
402 if (fHaveWildcards)
403 {
404 pszWildCardComponent = src;
405 *pszWildCardComponent = 0;
406 }
407 }
408 }
409
410 /** @todo don't check when creating files or directories; waste of time */
411 rc = RTPathQueryInfo(pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
412 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
413 {
414 uint32_t len = (uint32_t)strlen(pszFullPath);
415 char *src = pszFullPath + len - 1;
416
417 Log(("Handle case insenstive guest fs on top of host case sensitive fs for %s\n", pszFullPath));
418
419 /* Find partial path that's valid */
420 while(src > pszFullPath)
421 {
422 if (*src == RTPATH_DELIMITER)
423 {
424 *src = 0;
425 rc = RTPathQueryInfo (pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
426 *src = RTPATH_DELIMITER;
427 if (rc == VINF_SUCCESS)
428 {
429#ifdef DEBUG
430 *src = 0;
431 Log(("Found valid partial path %s\n", pszFullPath));
432 *src = RTPATH_DELIMITER;
433#endif
434 break;
435 }
436 }
437
438 src--;
439 }
440 Assert(*src == RTPATH_DELIMITER && RT_SUCCESS(rc));
441 if ( *src == RTPATH_DELIMITER
442 && RT_SUCCESS(rc))
443 {
444 src++;
445 for(;;)
446 {
447 char *end = src;
448 bool fEndOfString = true;
449
450 while(*end)
451 {
452 if (*end == RTPATH_DELIMITER)
453 break;
454 end++;
455 }
456
457 if (*end == RTPATH_DELIMITER)
458 {
459 fEndOfString = false;
460 *end = 0;
461 rc = RTPathQueryInfo(src, &info, RTFSOBJATTRADD_NOTHING);
462 Assert(rc == VINF_SUCCESS || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND);
463 }
464 else
465 if (end == src)
466 rc = VINF_SUCCESS; /* trailing delimiter */
467 else
468 rc = VERR_FILE_NOT_FOUND;
469
470 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
471 {
472 /* path component is invalid; try to correct the casing */
473 rc = vbsfCorrectCasing(pszFullPath, src);
474 if (RT_FAILURE(rc))
475 {
476 if (!fEndOfString)
477 *end = RTPATH_DELIMITER; /* restore the original full path */
478 break;
479 }
480 }
481
482 if (fEndOfString)
483 break;
484
485 *end = RTPATH_DELIMITER;
486 src = end + 1;
487 }
488 if (RT_FAILURE(rc))
489 Log(("Unable to find suitable component rc=%d\n", rc));
490 }
491 else
492 rc = VERR_FILE_NOT_FOUND;
493
494 }
495 if (pszWildCardComponent)
496 *pszWildCardComponent = RTPATH_DELIMITER;
497
498 /* might be a new file so don't fail here! */
499 rc = VINF_SUCCESS;
500 }
501 *ppszFullPath = pszFullPath;
502
503 LogFlow(("vbsfBuildFullPath: %s rc=%Rrc\n", pszFullPath, rc));
504 }
505
506 return rc;
507}
508
509static void vbsfFreeFullPath (char *pszFullPath)
510{
511 RTMemFree (pszFullPath);
512}
513
514/**
515 * Convert shared folder create flags (see include/iprt/shflsvc.h) into iprt create flags.
516 *
517 * @returns iprt status code
518 * @param fShflFlags shared folder create flags
519 * @retval pfOpen iprt create flags
520 */
521static int vbsfConvertFileOpenFlags(unsigned fShflFlags, unsigned *pfOpen)
522{
523 unsigned fOpen = 0;
524 int rc = VINF_SUCCESS;
525
526 switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_RW))
527 {
528 default:
529 case SHFL_CF_ACCESS_NONE:
530 {
531 /** @todo treat this as read access, but theoretically this could be a no access request. */
532 fOpen |= RTFILE_O_READ;
533 Log(("FLAG: SHFL_CF_ACCESS_NONE\n"));
534 break;
535 }
536
537 case SHFL_CF_ACCESS_READ:
538 {
539 fOpen |= RTFILE_O_READ;
540 Log(("FLAG: SHFL_CF_ACCESS_READ\n"));
541 break;
542 }
543
544 case SHFL_CF_ACCESS_WRITE:
545 {
546 fOpen |= RTFILE_O_WRITE;
547 Log(("FLAG: SHFL_CF_ACCESS_WRITE\n"));
548 break;
549 }
550
551 case SHFL_CF_ACCESS_READWRITE:
552 {
553 fOpen |= RTFILE_O_READWRITE;
554 Log(("FLAG: SHFL_CF_ACCESS_READWRITE\n"));
555 break;
556 }
557 }
558
559 switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_ATTR))
560 {
561 default:
562 case SHFL_CF_ACCESS_ATTR_NONE:
563 {
564 fOpen |= RTFILE_O_ACCESS_ATTR_DEFAULT;
565 /** @todo for posix guests we should allow passing the mode. */
566 fOpen |= 0666 << RTFILE_O_CREATE_MODE_SHIFT;
567 Log(("FLAG: SHFL_CF_ACCESS_ATTR_NONE\n"));
568 break;
569 }
570
571 case SHFL_CF_ACCESS_ATTR_READ:
572 {
573 fOpen |= RTFILE_O_ACCESS_ATTR_READ;
574 /** @todo for posix guests we should allow passing the mode.
575 * Additionally this esoteric case - new file with only read
576 * access - should be tested with apps depending on this. */
577 fOpen |= 0444 << RTFILE_O_CREATE_MODE_SHIFT;
578 Log(("FLAG: SHFL_CF_ACCESS_ATTR_READ\n"));
579 break;
580 }
581
582 case SHFL_CF_ACCESS_ATTR_WRITE:
583 {
584 fOpen |= RTFILE_O_ACCESS_ATTR_WRITE;
585 /** @todo for posix guests we should allow passing the mode.
586 * Additionally this esoteric case - new file with only write
587 * access - should be tested with apps depending on this. */
588 fOpen |= 0222 << RTFILE_O_CREATE_MODE_SHIFT;
589 Log(("FLAG: SHFL_CF_ACCESS_ATTR_WRITE\n"));
590 break;
591 }
592
593 case SHFL_CF_ACCESS_ATTR_READWRITE:
594 {
595 fOpen |= RTFILE_O_ACCESS_ATTR_READWRITE;
596 /** @todo for posix guests we should allow passing the mode. */
597 fOpen |= 0666 << RTFILE_O_CREATE_MODE_SHIFT;
598 Log(("FLAG: SHFL_CF_ACCESS_ATTR_READWRITE\n"));
599 break;
600 }
601 }
602
603 /* Sharing mask */
604 switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_DENY))
605 {
606 default:
607 case SHFL_CF_ACCESS_DENYNONE:
608 fOpen |= RTFILE_O_DENY_NONE;
609 Log(("FLAG: SHFL_CF_ACCESS_DENYNONE\n"));
610 break;
611
612 case SHFL_CF_ACCESS_DENYREAD:
613 fOpen |= RTFILE_O_DENY_READ;
614 Log(("FLAG: SHFL_CF_ACCESS_DENYREAD\n"));
615 break;
616
617 case SHFL_CF_ACCESS_DENYWRITE:
618 fOpen |= RTFILE_O_DENY_WRITE;
619 Log(("FLAG: SHFL_CF_ACCESS_DENYWRITE\n"));
620 break;
621
622 case SHFL_CF_ACCESS_DENYALL:
623 fOpen |= RTFILE_O_DENY_ALL;
624 Log(("FLAG: SHFL_CF_ACCESS_DENYALL\n"));
625 break;
626 }
627
628 /* Open/Create action mask */
629 switch (BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
630 {
631 case SHFL_CF_ACT_OPEN_IF_EXISTS:
632 if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
633 {
634 fOpen |= RTFILE_O_OPEN_CREATE;
635 Log(("FLAGS: SHFL_CF_ACT_OPEN_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
636 }
637 else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
638 {
639 fOpen |= RTFILE_O_OPEN;
640 Log(("FLAGS: SHFL_CF_ACT_OPEN_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
641 }
642 else
643 {
644 Log(("FLAGS: invalid open/create action combination\n"));
645 rc = VERR_INVALID_PARAMETER;
646 }
647 break;
648 case SHFL_CF_ACT_FAIL_IF_EXISTS:
649 if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
650 {
651 fOpen |= RTFILE_O_CREATE;
652 Log(("FLAGS: SHFL_CF_ACT_FAIL_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
653 }
654 else
655 {
656 Log(("FLAGS: invalid open/create action combination\n"));
657 rc = VERR_INVALID_PARAMETER;
658 }
659 break;
660 case SHFL_CF_ACT_REPLACE_IF_EXISTS:
661 if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
662 {
663 fOpen |= RTFILE_O_CREATE_REPLACE;
664 Log(("FLAGS: SHFL_CF_ACT_REPLACE_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
665 }
666 else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
667 {
668 fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
669 Log(("FLAGS: SHFL_CF_ACT_REPLACE_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
670 }
671 else
672 {
673 Log(("FLAGS: invalid open/create action combination\n"));
674 rc = VERR_INVALID_PARAMETER;
675 }
676 break;
677 case SHFL_CF_ACT_OVERWRITE_IF_EXISTS:
678 if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
679 {
680 fOpen |= RTFILE_O_CREATE_REPLACE;
681 Log(("FLAGS: SHFL_CF_ACT_OVERWRITE_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
682 }
683 else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
684 {
685 fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
686 Log(("FLAGS: SHFL_CF_ACT_OVERWRITE_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
687 }
688 else
689 {
690 Log(("FLAGS: invalid open/create action combination\n"));
691 rc = VERR_INVALID_PARAMETER;
692 }
693 break;
694 default:
695 rc = VERR_INVALID_PARAMETER;
696 Log(("FLAG: SHFL_CF_ACT_MASK_IF_EXISTS - invalid parameter\n"));
697 }
698
699 if (RT_SUCCESS(rc))
700 {
701 *pfOpen = fOpen;
702 }
703 return rc;
704}
705
706/**
707 * Open a file or create and open a new one.
708 *
709 * @returns IPRT status code
710 * @param pszPath Path to the file or folder on the host.
711 * @param pParms->CreateFlags Creation or open parameters, see include/VBox/shflsvc.h
712 * @param pParms->Info When a new file is created this specifies the initial parameters.
713 * When a file is created or overwritten, it also specifies the
714 * initial size.
715 * @retval pParms->Result Shared folder status code, see include/VBox/shflsvc.h
716 * @retval pParms->Handle On success the (shared folder) handle of the file opened or
717 * created
718 * @retval pParms->Info On success the parameters of the file opened or created
719 */
720static int vbsfOpenFile (const char *pszPath, SHFLCREATEPARMS *pParms)
721{
722 LogFlow(("vbsfOpenFile: pszPath = %s, pParms = %p\n", pszPath, pParms));
723 Log(("SHFL create flags %08x\n", pParms->CreateFlags));
724
725 SHFLHANDLE handle = SHFL_HANDLE_NIL;
726 SHFLFILEHANDLE *pHandle = 0;
727 /* Open or create a file. */
728 unsigned fOpen = 0;
729 bool fNoError = false;
730 static int cErrors;
731
732 int rc = vbsfConvertFileOpenFlags(pParms->CreateFlags, &fOpen);
733 if (RT_SUCCESS(rc))
734 {
735 handle = vbsfAllocFileHandle();
736 }
737 if (SHFL_HANDLE_NIL != handle)
738 {
739 rc = VERR_NO_MEMORY; /* If this fails - rewritten immediately on success. */
740 pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_FILE);
741 }
742 if (0 != pHandle)
743 {
744 rc = RTFileOpen(&pHandle->file.Handle, pszPath, fOpen);
745 }
746 if (RT_FAILURE (rc))
747 {
748 switch (rc)
749 {
750 case VERR_FILE_NOT_FOUND:
751 pParms->Result = SHFL_FILE_NOT_FOUND;
752
753 /* This actually isn't an error, so correct the rc before return later,
754 because the driver (VBoxSF.sys) expects rc = VINF_SUCCESS and checks the result code. */
755 fNoError = true;
756 break;
757 case VERR_PATH_NOT_FOUND:
758 pParms->Result = SHFL_PATH_NOT_FOUND;
759
760 /* This actually isn't an error, so correct the rc before return later,
761 because the driver (VBoxSF.sys) expects rc = VINF_SUCCESS and checks the result code. */
762 fNoError = true;
763 break;
764 case VERR_ALREADY_EXISTS:
765 RTFSOBJINFO info;
766
767 /** @todo Possible race left here. */
768 if (RT_SUCCESS(RTPathQueryInfo (pszPath, &info, RTFSOBJATTRADD_NOTHING)))
769 {
770 pParms->Info = info;
771 }
772 pParms->Result = SHFL_FILE_EXISTS;
773
774 /* This actually isn't an error, so correct the rc before return later,
775 because the driver (VBoxSF.sys) expects rc = VINF_SUCCESS and checks the result code. */
776 fNoError = true;
777 break;
778 case VERR_TOO_MANY_OPEN_FILES:
779 if (cErrors < 32)
780 {
781 LogRel(("SharedFolders host service: Cannot open '%s' -- too many open files.\n", pszPath));
782#if defined RT_OS_LINUX || RT_OS_SOLARIS
783 if (cErrors < 1)
784 LogRel(("SharedFolders host service: Try to increase the limit for open files (ulimt -n)\n"));
785#endif
786 cErrors++;
787 }
788 pParms->Result = SHFL_NO_RESULT;
789 break;
790 default:
791 pParms->Result = SHFL_NO_RESULT;
792 }
793 }
794
795 if (RT_SUCCESS(rc))
796 {
797 /** @note The shared folder status code is very approximate, as the runtime
798 * does not really provide this information. */
799 pParms->Result = SHFL_FILE_EXISTS; /* We lost the information as to whether it was
800 created when we eliminated the race. */
801 if ( ( SHFL_CF_ACT_REPLACE_IF_EXISTS
802 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
803 || ( SHFL_CF_ACT_OVERWRITE_IF_EXISTS
804 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS)))
805 {
806 /* For now, we do not treat a failure here as fatal. */
807 /* @todo Also set the size for SHFL_CF_ACT_CREATE_IF_NEW if
808 SHFL_CF_ACT_FAIL_IF_EXISTS is set. */
809 RTFileSetSize(pHandle->file.Handle, pParms->Info.cbObject);
810 pParms->Result = SHFL_FILE_REPLACED;
811 }
812 if ( ( SHFL_CF_ACT_FAIL_IF_EXISTS
813 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
814 || ( SHFL_CF_ACT_CREATE_IF_NEW
815 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW)))
816 {
817 pParms->Result = SHFL_FILE_CREATED;
818 }
819#if 0
820 /* @todo */
821 /* Set new attributes. */
822 if ( ( SHFL_CF_ACT_REPLACE_IF_EXISTS
823 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
824 || ( SHFL_CF_ACT_CREATE_IF_NEW
825 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW)))
826 {
827 RTFileSetTimes(pHandle->file.Handle,
828 &pParms->Info.AccessTime,
829 &pParms->Info.ModificationTime,
830 &pParms->Info.ChangeTime,
831 &pParms->Info.BirthTime
832 );
833
834 RTFileSetMode (pHandle->file.Handle, pParms->Info.Attr.fMode);
835 }
836#endif
837 RTFSOBJINFO info;
838
839 /* Get file information */
840 rc = RTFileQueryInfo (pHandle->file.Handle, &info, RTFSOBJATTRADD_NOTHING);
841 if (RT_SUCCESS(rc))
842 {
843 pParms->Info = info;
844 }
845 }
846 if (RT_FAILURE(rc))
847 {
848 if ( (0 != pHandle)
849 && (NIL_RTFILE != pHandle->file.Handle)
850 && (0 != pHandle->file.Handle))
851 {
852 RTFileClose(pHandle->file.Handle);
853 pHandle->file.Handle = NIL_RTFILE;
854 }
855 if (SHFL_HANDLE_NIL != handle)
856 {
857 vbsfFreeFileHandle (handle);
858 }
859 }
860 else
861 {
862 pParms->Handle = handle;
863 }
864
865 /* Report the driver that all is okay, we're done here */
866 if (fNoError)
867 rc = VINF_SUCCESS;
868
869 LogFlow(("vbsfOpenFile: rc = %Rrc\n", rc));
870 return rc;
871}
872
873/**
874 * Open a folder or create and open a new one.
875 *
876 * @returns IPRT status code
877 * @param pszPath Path to the file or folder on the host.
878 * @param pParms->CreateFlags Creation or open parameters, see include/VBox/shflsvc.h
879 * @retval pParms->Result Shared folder status code, see include/VBox/shflsvc.h
880 * @retval pParms->Handle On success the (shared folder) handle of the folder opened or
881 * created
882 * @retval pParms->Info On success the parameters of the folder opened or created
883 *
884 * @note folders are created with fMode = 0777
885 */
886static int vbsfOpenDir (const char *pszPath, SHFLCREATEPARMS *pParms)
887{
888 LogFlow(("vbsfOpenDir: pszPath = %s, pParms = %p\n", pszPath, pParms));
889 Log(("SHFL create flags %08x\n", pParms->CreateFlags));
890
891 int rc = VERR_NO_MEMORY;
892 SHFLHANDLE handle = vbsfAllocDirHandle();
893 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_DIR);
894 if (0 != pHandle)
895 {
896 rc = VINF_SUCCESS;
897 pParms->Result = SHFL_FILE_EXISTS; /* May be overwritten with SHFL_FILE_CREATED. */
898 /** @todo Can anyone think of a sensible, race-less way to do this? Although
899 I suspect that the race is inherent, due to the API available... */
900 /* Try to create the folder first if "create if new" is specified. If this
901 fails, and "open if exists" is specified, then we ignore the failure and try
902 to open the folder anyway. */
903 if ( SHFL_CF_ACT_CREATE_IF_NEW
904 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW))
905 {
906 /** @todo render supplied attributes.
907 * bird: The guest should specify this. For windows guests RTFS_DOS_DIRECTORY should suffice. */
908 RTFMODE fMode = 0777;
909
910 pParms->Result = SHFL_FILE_CREATED;
911 rc = RTDirCreate(pszPath, fMode);
912 if (RT_FAILURE (rc))
913 {
914 switch (rc)
915 {
916 case VERR_ALREADY_EXISTS:
917 pParms->Result = SHFL_FILE_EXISTS;
918 break;
919 case VERR_PATH_NOT_FOUND:
920 pParms->Result = SHFL_PATH_NOT_FOUND;
921 break;
922 default:
923 pParms->Result = SHFL_NO_RESULT;
924 }
925 }
926 }
927 if ( RT_SUCCESS(rc)
928 || (SHFL_CF_ACT_OPEN_IF_EXISTS == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS)))
929 {
930 /* Open the directory now */
931 rc = RTDirOpen (&pHandle->dir.Handle, pszPath);
932 if (RT_SUCCESS(rc))
933 {
934 RTFSOBJINFO info;
935
936 rc = RTDirQueryInfo (pHandle->dir.Handle, &info, RTFSOBJATTRADD_NOTHING);
937 if (RT_SUCCESS(rc))
938 {
939 pParms->Info = info;
940 }
941 }
942 else
943 {
944 switch (rc)
945 {
946 case VERR_FILE_NOT_FOUND: /* Does this make sense? */
947 pParms->Result = SHFL_FILE_NOT_FOUND;
948 break;
949 case VERR_PATH_NOT_FOUND:
950 pParms->Result = SHFL_PATH_NOT_FOUND;
951 break;
952 case VERR_ACCESS_DENIED:
953 pParms->Result = SHFL_FILE_EXISTS;
954 break;
955 default:
956 pParms->Result = SHFL_NO_RESULT;
957 }
958 }
959 }
960 }
961 if (RT_FAILURE(rc))
962 {
963 if ( (0 != pHandle)
964 && (0 != pHandle->dir.Handle))
965 {
966 RTDirClose(pHandle->dir.Handle);
967 pHandle->dir.Handle = 0;
968 }
969 if (SHFL_HANDLE_NIL != handle)
970 {
971 vbsfFreeFileHandle (handle);
972 }
973 }
974 else
975 {
976 pParms->Handle = handle;
977 }
978 LogFlow(("vbsfOpenDir: rc = %Rrc\n", rc));
979 return rc;
980}
981
982static int vbsfCloseDir (SHFLFILEHANDLE *pHandle)
983{
984 int rc = VINF_SUCCESS;
985
986 LogFlow(("vbsfCloseDir: Handle = %08X Search Handle = %08X\n",
987 pHandle->dir.Handle, pHandle->dir.SearchHandle));
988
989 RTDirClose (pHandle->dir.Handle);
990
991 if (pHandle->dir.SearchHandle)
992 RTDirClose(pHandle->dir.SearchHandle);
993
994 if (pHandle->dir.pLastValidEntry)
995 {
996 RTMemFree(pHandle->dir.pLastValidEntry);
997 pHandle->dir.pLastValidEntry = NULL;
998 }
999
1000 LogFlow(("vbsfCloseDir: rc = %d\n", rc));
1001
1002 return rc;
1003}
1004
1005
1006static int vbsfCloseFile (SHFLFILEHANDLE *pHandle)
1007{
1008 int rc = VINF_SUCCESS;
1009
1010 LogFlow(("vbsfCloseFile: Handle = %08X\n",
1011 pHandle->file.Handle));
1012
1013 rc = RTFileClose (pHandle->file.Handle);
1014
1015 LogFlow(("vbsfCloseFile: rc = %d\n", rc));
1016
1017 return rc;
1018}
1019
1020/**
1021 * Look up file or folder information by host path.
1022 *
1023 * @returns iprt status code (currently VINF_SUCCESS)
1024 * @param pszFullPath The path of the file to be looked up
1025 * @retval pParms->Result Status of the operation (success or error)
1026 * @retval pParms->Info On success, information returned about the file
1027 */
1028static int vbsfLookupFile(char *pszPath, SHFLCREATEPARMS *pParms)
1029{
1030 RTFSOBJINFO info;
1031 int rc;
1032
1033 rc = RTPathQueryInfo (pszPath, &info, RTFSOBJATTRADD_NOTHING);
1034 LogFlow(("SHFL_CF_LOOKUP\n"));
1035 /* Client just wants to know if the object exists. */
1036 switch (rc)
1037 {
1038 case VINF_SUCCESS:
1039 {
1040 pParms->Info = info;
1041 pParms->Result = SHFL_FILE_EXISTS;
1042 break;
1043 }
1044
1045 case VERR_FILE_NOT_FOUND:
1046 {
1047 pParms->Result = SHFL_FILE_NOT_FOUND;
1048 rc = VINF_SUCCESS;
1049 break;
1050 }
1051
1052 case VERR_PATH_NOT_FOUND:
1053 {
1054 pParms->Result = SHFL_PATH_NOT_FOUND;
1055 rc = VINF_SUCCESS;
1056 break;
1057 }
1058 }
1059 return rc;
1060}
1061
1062/**
1063 * Create or open a file or folder. Perform character set and case
1064 * conversion on the file name if necessary.
1065 *
1066 * @returns IPRT status code, but see note below
1067 * @param pClient Data structure describing the client accessing the shared
1068 * folder
1069 * @param root The index of the shared folder in the table of mappings.
1070 * The host path of the shared folder is found using this.
1071 * @param pPath The path of the file or folder relative to the host path
1072 * indexed by root.
1073 * @param cbPath Presumably the length of the path in pPath. Actually
1074 * ignored, as pPath contains a length parameter.
1075 * @param pParms->Info If a new file is created or an old one overwritten, set
1076 * these attributes
1077 * @retval pParms->Result Shared folder result code, see include/VBox/shflsvc.h
1078 * @retval pParms->Handle Shared folder handle to the newly opened file
1079 * @retval pParms->Info Attributes of the file or folder opened
1080 *
1081 * @note This function returns success if a "non-exceptional" error occurred,
1082 * such as "no such file". In this case, the caller should check the
1083 * pParms->Result return value and whether pParms->Handle is valid.
1084 */
1085int vbsfCreate (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, SHFLCREATEPARMS *pParms)
1086{
1087 int rc = VINF_SUCCESS;
1088
1089 LogFlow(("vbsfCreate: pClient = %p, pPath = %p, cbPath = %d, pParms = %p CreateFlags=%x\n",
1090 pClient, pPath, cbPath, pParms, pParms->CreateFlags));
1091
1092 /* Check the client access rights to the root. */
1093 /** @todo */
1094
1095 /* Build a host full path for the given path, handle file name case issues (if the guest
1096 * expects case-insensitive paths but the host is case-sensitive) and convert ucs2 to utf8 if
1097 * necessary.
1098 */
1099 char *pszFullPath = NULL;
1100 uint32_t cbFullPathRoot = 0;
1101
1102 rc = vbsfBuildFullPath (pClient, root, pPath, cbPath, &pszFullPath, &cbFullPathRoot);
1103
1104 if (RT_SUCCESS (rc))
1105 {
1106 /* Reset return values in case client forgot to do so. */
1107 pParms->Result = SHFL_NO_RESULT;
1108 pParms->Handle = SHFL_HANDLE_NIL;
1109
1110 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_LOOKUP))
1111 {
1112 rc = vbsfLookupFile(pszFullPath, pParms);
1113 }
1114 else
1115 {
1116 /* Query path information. */
1117 RTFSOBJINFO info;
1118
1119 rc = RTPathQueryInfo (pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
1120 LogFlow(("RTPathQueryInfo returned %Rrc\n", rc));
1121
1122 if (RT_SUCCESS(rc))
1123 {
1124 /* Mark it as a directory in case the caller didn't. */
1125 /**
1126 * @todo I left this in in order not to change the behaviour of the
1127 * function too much. Is it really needed, and should it really be
1128 * here?
1129 */
1130 if (BIT_FLAG(info.Attr.fMode, RTFS_DOS_DIRECTORY))
1131 {
1132 pParms->CreateFlags |= SHFL_CF_DIRECTORY;
1133 }
1134
1135 /**
1136 * @todo This should be in the Windows Guest Additions, as no-one else
1137 * needs it.
1138 */
1139 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_OPEN_TARGET_DIRECTORY))
1140 {
1141 vbsfStripLastComponent (pszFullPath, cbFullPathRoot);
1142 pParms->CreateFlags &= ~SHFL_CF_ACT_MASK_IF_EXISTS;
1143 pParms->CreateFlags &= ~SHFL_CF_ACT_MASK_IF_NEW;
1144 pParms->CreateFlags |= SHFL_CF_DIRECTORY;
1145 pParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
1146 pParms->CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
1147 }
1148 }
1149
1150 rc = VINF_SUCCESS;
1151
1152 /* write access requested? */
1153 if (pParms->CreateFlags & ( SHFL_CF_ACT_REPLACE_IF_EXISTS
1154 | SHFL_CF_ACT_OVERWRITE_IF_EXISTS
1155 | SHFL_CF_ACT_CREATE_IF_NEW
1156 | SHFL_CF_ACCESS_WRITE))
1157 {
1158 /* is the guest allowed to write to this share? */
1159 bool fWritable;
1160 rc = vbsfMappingsQueryWritable (pClient, root, &fWritable);
1161 if (RT_FAILURE(rc) || !fWritable)
1162 rc = VERR_WRITE_PROTECT;
1163 }
1164
1165 if (RT_SUCCESS(rc))
1166 {
1167 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
1168 {
1169 rc = vbsfOpenDir (pszFullPath, pParms);
1170 }
1171 else
1172 {
1173 rc = vbsfOpenFile (pszFullPath, pParms);
1174 }
1175 }
1176 }
1177
1178 /* free the path string */
1179 vbsfFreeFullPath(pszFullPath);
1180 }
1181
1182 Log(("vbsfCreate: handle = %RX64 rc = %Rrc result=%x\n", (uint64_t)pParms->Handle, rc, pParms->Result));
1183
1184 return rc;
1185}
1186
1187int vbsfClose (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
1188{
1189 int rc = VINF_SUCCESS;
1190
1191 LogFlow(("vbsfClose: pClient = %p, Handle = %RX64\n",
1192 pClient, Handle));
1193
1194 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1195 Assert(pHandle);
1196 if (!pHandle)
1197 return VERR_INVALID_HANDLE;
1198
1199 switch (ShflHandleType (&pHandle->Header))
1200 {
1201 case SHFL_HF_TYPE_DIR:
1202 {
1203 rc = vbsfCloseDir (pHandle);
1204 break;
1205 }
1206 case SHFL_HF_TYPE_FILE:
1207 {
1208 rc = vbsfCloseFile (pHandle);
1209 break;
1210 }
1211 default:
1212 AssertFailed();
1213 break;
1214 }
1215 vbsfFreeFileHandle(Handle);
1216
1217 Log(("vbsfClose: rc = %Rrc\n", rc));
1218
1219 return rc;
1220}
1221
1222int vbsfRead (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer)
1223{
1224 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1225 size_t count = 0;
1226 int rc;
1227
1228 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1229 {
1230 AssertFailed();
1231 return VERR_INVALID_PARAMETER;
1232 }
1233
1234 Log(("vbsfRead %RX64 offset %RX64 bytes %x\n", Handle, offset, *pcbBuffer));
1235
1236 if (*pcbBuffer == 0)
1237 return VINF_SUCCESS; /* @todo correct? */
1238
1239
1240 rc = RTFileSeek(pHandle->file.Handle, offset, RTFILE_SEEK_BEGIN, NULL);
1241 if (rc != VINF_SUCCESS)
1242 {
1243 AssertRC(rc);
1244 return rc;
1245 }
1246
1247 rc = RTFileRead(pHandle->file.Handle, pBuffer, *pcbBuffer, &count);
1248 *pcbBuffer = (uint32_t)count;
1249 Log(("RTFileRead returned %Rrc bytes read %x\n", rc, count));
1250 return rc;
1251}
1252
1253int vbsfWrite (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer)
1254{
1255 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1256 size_t count = 0;
1257 int rc;
1258
1259 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1260 {
1261 AssertFailed();
1262 return VERR_INVALID_PARAMETER;
1263 }
1264
1265 Log(("vbsfWrite %RX64 offset %RX64 bytes %x\n", Handle, offset, *pcbBuffer));
1266
1267 /* Is the guest allowed to write to this share?
1268 * XXX Actually this check was still done in vbsfCreate() -- RTFILE_O_WRITE cannot be set if vbsfMappingsQueryWritable() failed. */
1269 bool fWritable;
1270 rc = vbsfMappingsQueryWritable (pClient, root, &fWritable);
1271 if (RT_FAILURE(rc) || !fWritable)
1272 return VERR_WRITE_PROTECT;
1273
1274 if (*pcbBuffer == 0)
1275 return VINF_SUCCESS; /** @todo correct? */
1276
1277 rc = RTFileSeek(pHandle->file.Handle, offset, RTFILE_SEEK_BEGIN, NULL);
1278 if (rc != VINF_SUCCESS)
1279 {
1280 AssertRC(rc);
1281 return rc;
1282 }
1283
1284 rc = RTFileWrite(pHandle->file.Handle, pBuffer, *pcbBuffer, &count);
1285 *pcbBuffer = (uint32_t)count;
1286 Log(("RTFileWrite returned %Rrc bytes written %x\n", rc, count));
1287 return rc;
1288}
1289
1290
1291int vbsfFlush(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
1292{
1293 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1294 int rc = VINF_SUCCESS;
1295
1296 if (pHandle == 0)
1297 {
1298 AssertFailed();
1299 return VERR_INVALID_HANDLE;
1300 }
1301
1302 Log(("vbsfFlush %RX64\n", Handle));
1303 rc = RTFileFlush(pHandle->file.Handle);
1304 AssertRC(rc);
1305 return rc;
1306}
1307
1308int vbsfDirList(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, SHFLSTRING *pPath, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer,
1309 uint32_t *pIndex, uint32_t *pcFiles)
1310{
1311 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR);
1312 PRTDIRENTRYEX pDirEntry = 0, pDirEntryOrg;
1313 uint32_t cbDirEntry, cbBufferOrg;
1314 int rc = VINF_SUCCESS;
1315 PSHFLDIRINFO pSFDEntry;
1316 PRTUTF16 pwszString;
1317 PRTDIR DirHandle;
1318 bool fUtf8;
1319
1320 fUtf8 = BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8) != 0;
1321
1322 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1323 {
1324 AssertFailed();
1325 return VERR_INVALID_PARAMETER;
1326 }
1327 Assert(pIndex && *pIndex == 0);
1328 DirHandle = pHandle->dir.Handle;
1329
1330 cbDirEntry = 4096;
1331 pDirEntryOrg = pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
1332 if (pDirEntry == 0)
1333 {
1334 AssertFailed();
1335 return VERR_NO_MEMORY;
1336 }
1337
1338 cbBufferOrg = *pcbBuffer;
1339 *pcbBuffer = 0;
1340 pSFDEntry = (PSHFLDIRINFO)pBuffer;
1341
1342 *pIndex = 1; /* not yet complete */
1343 *pcFiles = 0;
1344
1345 if (pPath)
1346 {
1347 if (pHandle->dir.SearchHandle == 0)
1348 {
1349 /* Build a host full path for the given path
1350 * and convert ucs2 to utf8 if necessary.
1351 */
1352 char *pszFullPath = NULL;
1353
1354 Assert(pHandle->dir.pLastValidEntry == 0);
1355
1356 rc = vbsfBuildFullPath (pClient, root, pPath, pPath->u16Size, &pszFullPath, NULL, true);
1357
1358 if (RT_SUCCESS (rc))
1359 {
1360 rc = RTDirOpenFiltered (&pHandle->dir.SearchHandle, pszFullPath, RTDIRFILTER_WINNT);
1361
1362 /* free the path string */
1363 vbsfFreeFullPath(pszFullPath);
1364
1365 if (RT_FAILURE (rc))
1366 goto end;
1367 }
1368 else
1369 goto end;
1370 }
1371 Assert(pHandle->dir.SearchHandle);
1372 DirHandle = pHandle->dir.SearchHandle;
1373 }
1374
1375 while(cbBufferOrg)
1376 {
1377 size_t cbDirEntrySize = cbDirEntry;
1378 uint32_t cbNeeded;
1379
1380 /* Do we still have a valid last entry for the active search? If so, then return it here */
1381 if (pHandle->dir.pLastValidEntry)
1382 {
1383 pDirEntry = pHandle->dir.pLastValidEntry;
1384 }
1385 else
1386 {
1387 pDirEntry = pDirEntryOrg;
1388
1389 rc = RTDirReadEx(DirHandle, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING);
1390 if (rc == VERR_NO_MORE_FILES)
1391 {
1392 *pIndex = 0; /* listing completed */
1393 break;
1394 }
1395
1396 if (VINF_SUCCESS != rc && rc != VWRN_NO_DIRENT_INFO)
1397 {
1398 AssertFailed();
1399 if (rc != VERR_NO_TRANSLATION)
1400 break;
1401 else
1402 continue;
1403 }
1404 }
1405
1406 cbNeeded = RT_OFFSETOF (SHFLDIRINFO, name.String);
1407 if (fUtf8)
1408 cbNeeded += pDirEntry->cbName + 1;
1409 else
1410 /* Overestimating, but that's ok */
1411 cbNeeded += (pDirEntry->cbName + 1) * 2;
1412
1413 if (cbBufferOrg < cbNeeded)
1414 {
1415 /* No room, so save this directory entry, or else it's lost forever */
1416 pHandle->dir.pLastValidEntry = pDirEntry;
1417
1418 if (*pcFiles == 0)
1419 {
1420 AssertFailed();
1421 return VINF_BUFFER_OVERFLOW; /* Return directly and don't free pDirEntry */
1422 }
1423 return VINF_SUCCESS; /* Return directly and don't free pDirEntry */
1424 }
1425
1426 pSFDEntry->Info = pDirEntry->Info;
1427 pSFDEntry->cucShortName = 0;
1428
1429 if (fUtf8)
1430 {
1431 void *src, *dst;
1432
1433 src = &pDirEntry->szName[0];
1434 dst = &pSFDEntry->name.String.utf8[0];
1435
1436 memcpy (dst, src, pDirEntry->cbName + 1);
1437
1438 pSFDEntry->name.u16Size = pDirEntry->cbName + 1;
1439 pSFDEntry->name.u16Length = pDirEntry->cbName;
1440 }
1441 else
1442 {
1443 pSFDEntry->name.String.ucs2[0] = 0;
1444 pwszString = pSFDEntry->name.String.ucs2;
1445 int rc2 = RTStrToUtf16Ex(pDirEntry->szName, RTSTR_MAX, &pwszString, pDirEntry->cbName+1, NULL);
1446 AssertRC(rc2);
1447
1448#ifdef RT_OS_DARWIN
1449/** @todo This belongs in rtPathToNative or in the windows shared folder file system driver...
1450 * The question is simply whether the NFD normalization is actually applied on a (virtaul) file
1451 * system level in darwin, or just by the user mode application libs. */
1452 {
1453 // Convert to
1454 // Normalization Form C (composed Unicode). We need this because
1455 // Mac OS X file system uses NFD (Normalization Form D :decomposed Unicode)
1456 // while most other OS', server-side programs usually expect NFC.
1457 uint16_t ucs2Length;
1458 CFRange rangeCharacters;
1459 CFMutableStringRef inStr = ::CFStringCreateMutable(NULL, 0);
1460
1461 ::CFStringAppendCharacters(inStr, (UniChar *)pwszString, RTUtf16Len (pwszString));
1462 ::CFStringNormalize(inStr, kCFStringNormalizationFormC);
1463 ucs2Length = ::CFStringGetLength(inStr);
1464
1465 rangeCharacters.location = 0;
1466 rangeCharacters.length = ucs2Length;
1467 ::CFStringGetCharacters(inStr, rangeCharacters, pwszString);
1468 pwszString[ucs2Length] = 0x0000; // NULL terminated
1469
1470 CFRelease(inStr);
1471 }
1472#endif
1473 pSFDEntry->name.u16Length = (uint32_t)RTUtf16Len (pSFDEntry->name.String.ucs2) * 2;
1474 pSFDEntry->name.u16Size = pSFDEntry->name.u16Length + 2;
1475
1476 Log(("SHFL: File name size %d\n", pSFDEntry->name.u16Size));
1477 Log(("SHFL: File name %ls\n", &pSFDEntry->name.String.ucs2));
1478
1479 // adjust cbNeeded (it was overestimated before)
1480 cbNeeded = RT_OFFSETOF (SHFLDIRINFO, name.String) + pSFDEntry->name.u16Size;
1481 }
1482
1483 pSFDEntry = (PSHFLDIRINFO)((uintptr_t)pSFDEntry + cbNeeded);
1484 *pcbBuffer += cbNeeded;
1485 cbBufferOrg-= cbNeeded;
1486
1487 *pcFiles += 1;
1488
1489 /* Free the saved last entry, that we've just returned */
1490 if (pHandle->dir.pLastValidEntry)
1491 {
1492 RTMemFree(pHandle->dir.pLastValidEntry);
1493 pHandle->dir.pLastValidEntry = NULL;
1494 }
1495
1496 if (flags & SHFL_LIST_RETURN_ONE)
1497 break; /* we're done */
1498 }
1499 Assert(rc != VINF_SUCCESS || *pcbBuffer > 0);
1500
1501end:
1502 if (pDirEntry)
1503 RTMemFree(pDirEntry);
1504
1505 return rc;
1506}
1507
1508int vbsfQueryFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1509{
1510 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1511 int rc = VINF_SUCCESS;
1512 RTFSOBJINFO *pObjInfo = (RTFSOBJINFO *)pBuffer;
1513
1514
1515 if (pHandle == 0 || pcbBuffer == 0 || pObjInfo == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1516 {
1517 AssertFailed();
1518 return VERR_INVALID_PARAMETER;
1519 }
1520
1521 /* @todo other options */
1522 Assert(flags == (SHFL_INFO_GET|SHFL_INFO_FILE));
1523
1524 *pcbBuffer = 0;
1525
1526 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_DIR)
1527 {
1528 rc = RTDirQueryInfo(pHandle->dir.Handle, pObjInfo, RTFSOBJATTRADD_NOTHING);
1529 }
1530 else
1531 {
1532 rc = RTFileQueryInfo(pHandle->file.Handle, pObjInfo, RTFSOBJATTRADD_NOTHING);
1533 }
1534 if (rc == VINF_SUCCESS)
1535 {
1536 *pcbBuffer = sizeof(RTFSOBJINFO);
1537 }
1538 else
1539 AssertFailed();
1540
1541 return rc;
1542}
1543
1544static int vbsfSetFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1545{
1546 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1547 int rc = VINF_SUCCESS;
1548 RTFSOBJINFO *pSFDEntry;
1549
1550 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1551 {
1552 AssertFailed();
1553 return VERR_INVALID_PARAMETER;
1554 }
1555
1556 *pcbBuffer = 0;
1557 pSFDEntry = (RTFSOBJINFO *)pBuffer;
1558
1559 Assert(flags == (SHFL_INFO_SET | SHFL_INFO_FILE));
1560
1561 /* Change only the time values that are not zero */
1562 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_DIR)
1563 {
1564 rc = RTDirSetTimes(pHandle->dir.Handle,
1565 (RTTimeSpecGetNano(&pSFDEntry->AccessTime)) ? &pSFDEntry->AccessTime : NULL,
1566 (RTTimeSpecGetNano(&pSFDEntry->ModificationTime)) ? &pSFDEntry->ModificationTime: NULL,
1567 (RTTimeSpecGetNano(&pSFDEntry->ChangeTime)) ? &pSFDEntry->ChangeTime: NULL,
1568 (RTTimeSpecGetNano(&pSFDEntry->BirthTime)) ? &pSFDEntry->BirthTime: NULL
1569 );
1570 }
1571 else
1572 {
1573 rc = RTFileSetTimes(pHandle->file.Handle,
1574 (RTTimeSpecGetNano(&pSFDEntry->AccessTime)) ? &pSFDEntry->AccessTime : NULL,
1575 (RTTimeSpecGetNano(&pSFDEntry->ModificationTime)) ? &pSFDEntry->ModificationTime: NULL,
1576 (RTTimeSpecGetNano(&pSFDEntry->ChangeTime)) ? &pSFDEntry->ChangeTime: NULL,
1577 (RTTimeSpecGetNano(&pSFDEntry->BirthTime)) ? &pSFDEntry->BirthTime: NULL
1578 );
1579 }
1580 if (rc != VINF_SUCCESS)
1581 {
1582 Log(("RTFileSetTimes failed with %Rrc\n", rc));
1583 Log(("AccessTime %RX64\n", RTTimeSpecGetNano(&pSFDEntry->AccessTime)));
1584 Log(("ModificationTime %RX64\n", RTTimeSpecGetNano(&pSFDEntry->ModificationTime)));
1585 Log(("ChangeTime %RX64\n", RTTimeSpecGetNano(&pSFDEntry->ChangeTime)));
1586 Log(("BirthTime %RX64\n", RTTimeSpecGetNano(&pSFDEntry->AccessTime)));
1587 /* temporary hack */
1588 rc = VINF_SUCCESS;
1589 }
1590
1591 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_FILE)
1592 {
1593 /* Change file attributes if necessary */
1594 if (pSFDEntry->Attr.fMode)
1595 {
1596 rc = RTFileSetMode((RTFILE)pHandle->file.Handle, pSFDEntry->Attr.fMode);
1597 if (rc != VINF_SUCCESS)
1598 {
1599 Log(("RTFileSetMode %x failed with %Rrc\n", pSFDEntry->Attr.fMode, rc));
1600 /* silent failure, because this tends to fail with e.g. windows guest & linux host */
1601 rc = VINF_SUCCESS;
1602 }
1603 }
1604 }
1605
1606 if (rc == VINF_SUCCESS)
1607 {
1608 uint32_t bufsize = sizeof(*pSFDEntry);
1609
1610 rc = vbsfQueryFileInfo(pClient, root, Handle, SHFL_INFO_GET|SHFL_INFO_FILE, &bufsize, (uint8_t *)pSFDEntry);
1611 if (rc == VINF_SUCCESS)
1612 {
1613 *pcbBuffer = sizeof(RTFSOBJINFO);
1614 }
1615 else
1616 AssertFailed();
1617 }
1618
1619 return rc;
1620}
1621
1622
1623static int vbsfSetEndOfFile(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1624{
1625 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1626 int rc = VINF_SUCCESS;
1627 RTFSOBJINFO *pSFDEntry;
1628
1629 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1630 {
1631 AssertFailed();
1632 return VERR_INVALID_PARAMETER;
1633 }
1634
1635 *pcbBuffer = 0;
1636 pSFDEntry = (RTFSOBJINFO *)pBuffer;
1637
1638 if (flags & SHFL_INFO_SIZE)
1639 {
1640 rc = RTFileSetSize(pHandle->file.Handle, pSFDEntry->cbObject);
1641 if (rc != VINF_SUCCESS)
1642 AssertFailed();
1643 }
1644 else
1645 AssertFailed();
1646
1647 if (rc == VINF_SUCCESS)
1648 {
1649 RTFSOBJINFO fileinfo;
1650
1651 /* Query the new object info and return it */
1652 rc = RTFileQueryInfo(pHandle->file.Handle, &fileinfo, RTFSOBJATTRADD_NOTHING);
1653 if (rc == VINF_SUCCESS)
1654 {
1655 *pSFDEntry = fileinfo;
1656 *pcbBuffer = sizeof(RTFSOBJINFO);
1657 }
1658 else
1659 AssertFailed();
1660 }
1661
1662 return rc;
1663}
1664
1665int vbsfQueryVolumeInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1666{
1667 int rc = VINF_SUCCESS;
1668 SHFLVOLINFO *pSFDEntry;
1669 char *pszFullPath = NULL;
1670 SHFLSTRING dummy;
1671
1672 if (pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(SHFLVOLINFO))
1673 {
1674 AssertFailed();
1675 return VERR_INVALID_PARAMETER;
1676 }
1677
1678 /* @todo other options */
1679 Assert(flags == (SHFL_INFO_GET|SHFL_INFO_VOLUME));
1680
1681 *pcbBuffer = 0;
1682 pSFDEntry = (PSHFLVOLINFO)pBuffer;
1683
1684 ShflStringInitBuffer(&dummy, sizeof(dummy));
1685 rc = vbsfBuildFullPath (pClient, root, &dummy, 0, &pszFullPath, NULL);
1686
1687 if (RT_SUCCESS (rc))
1688 {
1689 rc = RTFsQuerySizes(pszFullPath, &pSFDEntry->ullTotalAllocationBytes, &pSFDEntry->ullAvailableAllocationBytes, &pSFDEntry->ulBytesPerAllocationUnit, &pSFDEntry->ulBytesPerSector);
1690 if (rc != VINF_SUCCESS)
1691 goto exit;
1692
1693 rc = RTFsQuerySerial(pszFullPath, &pSFDEntry->ulSerial);
1694 if (rc != VINF_SUCCESS)
1695 goto exit;
1696
1697 rc = RTFsQueryProperties(pszFullPath, &pSFDEntry->fsProperties);
1698 if (rc != VINF_SUCCESS)
1699 goto exit;
1700
1701 *pcbBuffer = sizeof(SHFLVOLINFO);
1702 }
1703 else AssertFailed();
1704
1705exit:
1706 AssertMsg(rc == VINF_SUCCESS, ("failure: rc = %Rrc\n", rc));
1707 /* free the path string */
1708 vbsfFreeFullPath(pszFullPath);
1709 return rc;
1710}
1711
1712int vbsfQueryFSInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1713{
1714 if (pcbBuffer == 0 || pBuffer == 0)
1715 {
1716 AssertFailed();
1717 return VERR_INVALID_PARAMETER;
1718 }
1719
1720 if (flags & SHFL_INFO_FILE)
1721 return vbsfQueryFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1722
1723 if (flags & SHFL_INFO_VOLUME)
1724 return vbsfQueryVolumeInfo(pClient, root, flags, pcbBuffer, pBuffer);
1725
1726 AssertFailed();
1727 return VERR_INVALID_PARAMETER;
1728}
1729
1730int vbsfSetFSInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1731{
1732 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE|SHFL_HF_TYPE_VOLUME);
1733
1734 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1735 {
1736 AssertFailed();
1737 return VERR_INVALID_PARAMETER;
1738 }
1739
1740 /* is the guest allowed to write to this share? */
1741 bool fWritable;
1742 int rc = vbsfMappingsQueryWritable (pClient, root, &fWritable);
1743 if (RT_FAILURE(rc) || !fWritable)
1744 return VERR_WRITE_PROTECT;
1745
1746 if (flags & SHFL_INFO_FILE)
1747 return vbsfSetFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1748
1749 if (flags & SHFL_INFO_SIZE)
1750 return vbsfSetEndOfFile(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1751
1752// if (flags & SHFL_INFO_VOLUME)
1753// return vbsfVolumeInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1754 AssertFailed();
1755 return VERR_INVALID_PARAMETER;
1756}
1757
1758int vbsfLock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
1759{
1760 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1761 uint32_t fRTLock = 0;
1762 int rc;
1763
1764 Assert((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL);
1765
1766 if (pHandle == 0)
1767 {
1768 AssertFailed();
1769 return VERR_INVALID_HANDLE;
1770 }
1771 if ( ((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL)
1772 || (flags & SHFL_LOCK_ENTIRE)
1773 )
1774 {
1775 AssertFailed();
1776 return VERR_INVALID_PARAMETER;
1777 }
1778
1779 /* Lock type */
1780 switch(flags & SHFL_LOCK_MODE_MASK)
1781 {
1782 case SHFL_LOCK_SHARED:
1783 fRTLock = RTFILE_LOCK_READ;
1784 break;
1785
1786 case SHFL_LOCK_EXCLUSIVE:
1787 fRTLock = RTFILE_LOCK_READ | RTFILE_LOCK_WRITE;
1788 break;
1789
1790 default:
1791 AssertFailed();
1792 return VERR_INVALID_PARAMETER;
1793 }
1794
1795 /* Lock wait type */
1796 if (flags & SHFL_LOCK_WAIT)
1797 fRTLock |= RTFILE_LOCK_WAIT;
1798 else
1799 fRTLock |= RTFILE_LOCK_IMMEDIATELY;
1800
1801#ifdef RT_OS_WINDOWS
1802 rc = RTFileLock(pHandle->file.Handle, fRTLock, offset, length);
1803 if (rc != VINF_SUCCESS)
1804 Log(("RTFileLock %RTfile %RX64 %RX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
1805#else
1806 Log(("vbsfLock: Pretend success handle=%x\n", Handle));
1807 rc = VINF_SUCCESS;
1808#endif
1809 return rc;
1810}
1811
1812int vbsfUnlock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
1813{
1814 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1815 int rc;
1816
1817 Assert((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL);
1818
1819 if (pHandle == 0)
1820 {
1821 return VERR_INVALID_HANDLE;
1822 }
1823 if ( ((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL)
1824 || (flags & SHFL_LOCK_ENTIRE)
1825 )
1826 {
1827 return VERR_INVALID_PARAMETER;
1828 }
1829
1830#ifdef RT_OS_WINDOWS
1831 rc = RTFileUnlock(pHandle->file.Handle, offset, length);
1832 if (rc != VINF_SUCCESS)
1833 Log(("RTFileUnlock %RTfile %RX64 %RTX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
1834#else
1835 Log(("vbsfUnlock: Pretend success handle=%x\n", Handle));
1836 rc = VINF_SUCCESS;
1837#endif
1838
1839 return rc;
1840}
1841
1842
1843int vbsfRemove(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, uint32_t flags)
1844{
1845 int rc = VINF_SUCCESS;
1846
1847 /* Validate input */
1848 if ( flags & ~(SHFL_REMOVE_FILE|SHFL_REMOVE_DIR)
1849 || cbPath == 0
1850 || pPath == 0)
1851 {
1852 AssertFailed();
1853 return VERR_INVALID_PARAMETER;
1854 }
1855
1856 /* Build a host full path for the given path
1857 * and convert ucs2 to utf8 if necessary.
1858 */
1859 char *pszFullPath = NULL;
1860
1861 rc = vbsfBuildFullPath (pClient, root, pPath, cbPath, &pszFullPath, NULL);
1862 if (RT_SUCCESS (rc))
1863 {
1864 /* is the guest allowed to write to this share? */
1865 bool fWritable;
1866 rc = vbsfMappingsQueryWritable (pClient, root, &fWritable);
1867 if (RT_FAILURE(rc) || !fWritable)
1868 rc = VERR_WRITE_PROTECT;
1869
1870 if (RT_SUCCESS (rc))
1871 {
1872 if (flags & SHFL_REMOVE_FILE)
1873 rc = RTFileDelete(pszFullPath);
1874 else
1875 rc = RTDirRemove(pszFullPath);
1876 }
1877
1878#ifndef DEBUG_dmik
1879 // VERR_ACCESS_DENIED for example?
1880 // Assert(rc == VINF_SUCCESS || rc == VERR_DIR_NOT_EMPTY);
1881#endif
1882 /* free the path string */
1883 vbsfFreeFullPath(pszFullPath);
1884 }
1885 return rc;
1886}
1887
1888
1889int vbsfRename(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pSrc, SHFLSTRING *pDest, uint32_t flags)
1890{
1891 int rc = VINF_SUCCESS;
1892
1893 /* Validate input */
1894 if ( flags & ~(SHFL_REMOVE_FILE|SHFL_REMOVE_DIR|SHFL_RENAME_REPLACE_IF_EXISTS)
1895 || pSrc == 0
1896 || pDest == 0)
1897 {
1898 AssertFailed();
1899 return VERR_INVALID_PARAMETER;
1900 }
1901
1902 /* Build a host full path for the given path
1903 * and convert ucs2 to utf8 if necessary.
1904 */
1905 char *pszFullPathSrc = NULL;
1906 char *pszFullPathDest = NULL;
1907
1908 rc = vbsfBuildFullPath (pClient, root, pSrc, pSrc->u16Size, &pszFullPathSrc, NULL);
1909 if (rc != VINF_SUCCESS)
1910 return rc;
1911
1912 rc = vbsfBuildFullPath (pClient, root, pDest, pDest->u16Size, &pszFullPathDest, NULL);
1913 if (RT_SUCCESS (rc))
1914 {
1915 Log(("Rename %s to %s\n", pszFullPathSrc, pszFullPathDest));
1916
1917 /* is the guest allowed to write to this share? */
1918 bool fWritable;
1919 rc = vbsfMappingsQueryWritable (pClient, root, &fWritable);
1920 if (RT_FAILURE(rc) || !fWritable)
1921 rc = VERR_WRITE_PROTECT;
1922
1923 if (RT_SUCCESS (rc))
1924 {
1925 if (flags & SHFL_RENAME_FILE)
1926 {
1927 rc = RTFileMove(pszFullPathSrc, pszFullPathDest, (flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTFILEMOVE_FLAGS_REPLACE : 0);
1928 }
1929 else
1930 {
1931 /* NT ignores the REPLACE flag and simply return and already exists error. */
1932 rc = RTDirRename(pszFullPathSrc, pszFullPathDest, (flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTPATHRENAME_FLAGS_REPLACE : 0);
1933 }
1934 }
1935
1936#ifndef DEBUG_dmik
1937 AssertRC(rc);
1938#endif
1939 /* free the path string */
1940 vbsfFreeFullPath(pszFullPathDest);
1941 }
1942 /* free the path string */
1943 vbsfFreeFullPath(pszFullPathSrc);
1944 return rc;
1945}
1946
1947/*
1948 * Clean up our mess by freeing all handles that are still valid.
1949 *
1950 */
1951int vbsfDisconnect(SHFLCLIENTDATA *pClient)
1952{
1953 for (int i=0;i<SHFLHANDLE_MAX;i++)
1954 {
1955 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(i, SHFL_HF_TYPE_MASK);
1956
1957 if (pHandle)
1958 {
1959 Log(("Open handle %08x\n", i));
1960 vbsfClose(pClient, SHFL_HANDLE_ROOT /* incorrect, but it's not important */, (SHFLHANDLE)i);
1961 }
1962 }
1963 return VINF_SUCCESS;
1964}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette