VirtualBox

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

Last change on this file since 11938 was 9927, checked in by vboxsync, 16 years ago

@todo

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.1 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 = 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 (VBOX_FAILURE(rc))
133 goto end;
134
135 for(;;)
136 {
137 uint32_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 (VBOX_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 (VBOX_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 = cbUtf8Root; /* Must index the path delimiter. */
226 }
227
228 RTStrFree (utf8Root);
229 }
230 else
231 {
232 Log (("vbsfBuildFullPath: RTUtf16ToUtf8 failed with %Vrc\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 (VBOX_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 = 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 (VBOX_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 = 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 (VBOX_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 = 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 = 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 && VBOX_SUCCESS(rc));
441 if ( *src == RTPATH_DELIMITER
442 && VBOX_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 (VBOX_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 (VBOX_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=%Vrc\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 /* Sharing mask */
560 switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_DENY))
561 {
562 default:
563 case SHFL_CF_ACCESS_DENYNONE:
564 fOpen |= RTFILE_O_DENY_NONE;
565 Log(("FLAG: SHFL_CF_ACCESS_DENYNONE\n"));
566 break;
567
568 case SHFL_CF_ACCESS_DENYREAD:
569 fOpen |= RTFILE_O_DENY_READ;
570 Log(("FLAG: SHFL_CF_ACCESS_DENYREAD\n"));
571 break;
572
573 case SHFL_CF_ACCESS_DENYWRITE:
574 fOpen |= RTFILE_O_DENY_WRITE;
575 Log(("FLAG: SHFL_CF_ACCESS_DENYWRITE\n"));
576 break;
577
578 case SHFL_CF_ACCESS_DENYALL:
579 fOpen |= RTFILE_O_DENY_ALL;
580 Log(("FLAG: SHFL_CF_ACCESS_DENYALL\n"));
581 break;
582 }
583
584 /* Open/Create action mask */
585 switch (BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
586 {
587 case SHFL_CF_ACT_OPEN_IF_EXISTS:
588 if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
589 {
590 fOpen |= RTFILE_O_OPEN_CREATE;
591 Log(("FLAGS: SHFL_CF_ACT_OPEN_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
592 }
593 else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
594 {
595 fOpen |= RTFILE_O_OPEN;
596 Log(("FLAGS: SHFL_CF_ACT_OPEN_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
597 }
598 else
599 {
600 Log(("FLAGS: invalid open/create action combination\n"));
601 rc = VERR_INVALID_PARAMETER;
602 }
603 break;
604 case SHFL_CF_ACT_FAIL_IF_EXISTS:
605 if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
606 {
607 fOpen |= RTFILE_O_CREATE;
608 Log(("FLAGS: SHFL_CF_ACT_FAIL_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
609 }
610 else
611 {
612 Log(("FLAGS: invalid open/create action combination\n"));
613 rc = VERR_INVALID_PARAMETER;
614 }
615 break;
616 case SHFL_CF_ACT_REPLACE_IF_EXISTS:
617 if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
618 {
619 fOpen |= RTFILE_O_CREATE_REPLACE;
620 Log(("FLAGS: SHFL_CF_ACT_REPLACE_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
621 }
622 else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
623 {
624 fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
625 Log(("FLAGS: SHFL_CF_ACT_REPLACE_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
626 }
627 else
628 {
629 Log(("FLAGS: invalid open/create action combination\n"));
630 rc = VERR_INVALID_PARAMETER;
631 }
632 break;
633 case SHFL_CF_ACT_OVERWRITE_IF_EXISTS:
634 if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
635 {
636 fOpen |= RTFILE_O_CREATE_REPLACE;
637 Log(("FLAGS: SHFL_CF_ACT_OVERWRITE_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
638 }
639 else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
640 {
641 fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
642 Log(("FLAGS: SHFL_CF_ACT_OVERWRITE_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
643 }
644 else
645 {
646 Log(("FLAGS: invalid open/create action combination\n"));
647 rc = VERR_INVALID_PARAMETER;
648 }
649 break;
650 default:
651 rc = VERR_INVALID_PARAMETER;
652 Log(("FLAG: SHFL_CF_ACT_MASK_IF_EXISTS - invalid parameter\n"));
653 }
654
655 if (RT_SUCCESS(rc))
656 {
657 *pfOpen = fOpen;
658 }
659 return rc;
660}
661
662/**
663 * Open a file or create and open a new one.
664 *
665 * @returns IPRT status code
666 * @param pszPath Path to the file or folder on the host.
667 * @param pParms->CreateFlags Creation or open parameters, see include/VBox/shflsvc.h
668 * @param pParms->Info When a new file is created this specifies the initial parameters.
669 * When a file is created or overwritten, it also specifies the
670 * initial size.
671 * @retval pParms->Result Shared folder status code, see include/VBox/shflsvc.h
672 * @retval pParms->Handle On success the (shared folder) handle of the file opened or
673 * created
674 * @retval pParms->Info On success the parameters of the file opened or created
675 */
676static int vbsfOpenFile (const char *pszPath, SHFLCREATEPARMS *pParms)
677{
678 LogFlow(("vbsfOpenFile: pszPath = %s, pParms = %p\n", pszPath, pParms));
679 Log(("SHFL create flags %08x\n", pParms->CreateFlags));
680
681 SHFLHANDLE handle = SHFL_HANDLE_NIL;
682 SHFLFILEHANDLE *pHandle = 0;
683 /* Open or create a file. */
684 unsigned fOpen = 0;
685 bool fNoError = false;
686
687 int rc = vbsfConvertFileOpenFlags(pParms->CreateFlags, &fOpen);
688 if (RT_SUCCESS(rc))
689 {
690 handle = vbsfAllocFileHandle();
691 }
692 if (SHFL_HANDLE_NIL != handle)
693 {
694 rc = VERR_NO_MEMORY; /* If this fails - rewritten immediately on success. */
695 pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_FILE);
696 }
697 if (0 != pHandle)
698 {
699 rc = RTFileOpen(&pHandle->file.Handle, pszPath, fOpen);
700 }
701 if (RT_FAILURE (rc))
702 {
703 switch (rc)
704 {
705 case VERR_FILE_NOT_FOUND:
706 pParms->Result = SHFL_FILE_NOT_FOUND;
707
708 /* This actually isn't an error, so correct the rc before return later,
709 because the driver (VBoxSF.sys) expects rc = VINF_SUCCESS and checks the result code. */
710 fNoError = true;
711 break;
712 case VERR_PATH_NOT_FOUND:
713 pParms->Result = SHFL_PATH_NOT_FOUND;
714
715 /* This actually isn't an error, so correct the rc before return later,
716 because the driver (VBoxSF.sys) expects rc = VINF_SUCCESS and checks the result code. */
717 fNoError = true;
718 break;
719 case VERR_ALREADY_EXISTS:
720 RTFSOBJINFO info;
721
722 /** @todo Possible race left here. */
723 if (RT_SUCCESS(RTPathQueryInfo (pszPath, &info, RTFSOBJATTRADD_NOTHING)))
724 {
725 pParms->Info = info;
726 }
727 pParms->Result = SHFL_FILE_EXISTS;
728
729 /* This actually isn't an error, so correct the rc before return later,
730 because the driver (VBoxSF.sys) expects rc = VINF_SUCCESS and checks the result code. */
731 fNoError = true;
732 break;
733 default:
734 pParms->Result = SHFL_NO_RESULT;
735 }
736 }
737
738 if (RT_SUCCESS(rc))
739 {
740 /** @note The shared folder status code is very approximate, as the runtime
741 * does not really provide this information. */
742 pParms->Result = SHFL_FILE_EXISTS; /* We lost the information as to whether it was
743 created when we eliminated the race. */
744 if ( ( SHFL_CF_ACT_REPLACE_IF_EXISTS
745 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
746 || ( SHFL_CF_ACT_OVERWRITE_IF_EXISTS
747 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS)))
748 {
749 /* For now, we do not treat a failure here as fatal. */
750 /* @todo Also set the size for SHFL_CF_ACT_CREATE_IF_NEW if
751 SHFL_CF_ACT_FAIL_IF_EXISTS is set. */
752 RTFileSetSize(pHandle->file.Handle, pParms->Info.cbObject);
753 pParms->Result = SHFL_FILE_REPLACED;
754 }
755 if ( ( SHFL_CF_ACT_FAIL_IF_EXISTS
756 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
757 || ( SHFL_CF_ACT_CREATE_IF_NEW
758 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW)))
759 {
760 pParms->Result = SHFL_FILE_CREATED;
761 }
762#if 0
763 /* @todo */
764 /* Set new attributes. */
765 if ( ( SHFL_CF_ACT_REPLACE_IF_EXISTS
766 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
767 || ( SHFL_CF_ACT_CREATE_IF_NEW
768 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW)))
769 {
770 RTFileSetTimes(pHandle->file.Handle,
771 &pParms->Info.AccessTime,
772 &pParms->Info.ModificationTime,
773 &pParms->Info.ChangeTime,
774 &pParms->Info.BirthTime
775 );
776
777 RTFileSetMode (pHandle->file.Handle, pParms->Info.Attr.fMode);
778 }
779#endif
780 RTFSOBJINFO info;
781
782 /* Get file information */
783 rc = RTFileQueryInfo (pHandle->file.Handle, &info, RTFSOBJATTRADD_NOTHING);
784 if (RT_SUCCESS(rc))
785 {
786 pParms->Info = info;
787 }
788 }
789 if (RT_FAILURE(rc))
790 {
791 if ( (0 != pHandle)
792 && (NIL_RTFILE != pHandle->file.Handle)
793 && (0 != pHandle->file.Handle))
794 {
795 RTFileClose(pHandle->file.Handle);
796 pHandle->file.Handle = NIL_RTFILE;
797 }
798 if (SHFL_HANDLE_NIL != handle)
799 {
800 vbsfFreeFileHandle (handle);
801 }
802 }
803 else
804 {
805 pParms->Handle = handle;
806 }
807
808 /* Report the driver that all is okay, we're done here */
809 if (fNoError)
810 rc = VINF_SUCCESS;
811
812 LogFlow(("vbsfOpenFile: rc = %Vrc\n", rc));
813 return rc;
814}
815
816/**
817 * Open a folder or create and open a new one.
818 *
819 * @returns IPRT status code
820 * @param pszPath Path to the file or folder on the host.
821 * @param pParms->CreateFlags Creation or open parameters, see include/VBox/shflsvc.h
822 * @retval pParms->Result Shared folder status code, see include/VBox/shflsvc.h
823 * @retval pParms->Handle On success the (shared folder) handle of the folder opened or
824 * created
825 * @retval pParms->Info On success the parameters of the folder opened or created
826 *
827 * @note folders are created with fMode = 0777
828 */
829static int vbsfOpenDir (const char *pszPath, SHFLCREATEPARMS *pParms)
830{
831 LogFlow(("vbsfOpenDir: pszPath = %s, pParms = %p\n", pszPath, pParms));
832 Log(("SHFL create flags %08x\n", pParms->CreateFlags));
833
834 int rc = VERR_NO_MEMORY;
835 SHFLHANDLE handle = vbsfAllocDirHandle();
836 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_DIR);
837 if (0 != pHandle)
838 {
839 rc = VINF_SUCCESS;
840 pParms->Result = SHFL_FILE_EXISTS; /* May be overwritten with SHFL_FILE_CREATED. */
841 /** @todo Can anyone think of a sensible, race-less way to do this? Although
842 I suspect that the race is inherent, due to the API available... */
843 /* Try to create the folder first if "create if new" is specified. If this
844 fails, and "open if exists" is specified, then we ignore the failure and try
845 to open the folder anyway. */
846 if ( SHFL_CF_ACT_CREATE_IF_NEW
847 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW))
848 {
849 /** @todo render supplied attributes.
850 * bird: The guest should specify this. For windows guests RTFS_DOS_DIRECTORY should suffice. */
851 RTFMODE fMode = 0777;
852
853 pParms->Result = SHFL_FILE_CREATED;
854 rc = RTDirCreate(pszPath, fMode);
855 if (RT_FAILURE (rc))
856 {
857 switch (rc)
858 {
859 case VERR_ALREADY_EXISTS:
860 pParms->Result = SHFL_FILE_EXISTS;
861 break;
862 case VERR_PATH_NOT_FOUND:
863 pParms->Result = SHFL_PATH_NOT_FOUND;
864 break;
865 default:
866 pParms->Result = SHFL_NO_RESULT;
867 }
868 }
869 }
870 if ( RT_SUCCESS(rc)
871 || (SHFL_CF_ACT_OPEN_IF_EXISTS == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS)))
872 {
873 /* Open the directory now */
874 rc = RTDirOpen (&pHandle->dir.Handle, pszPath);
875 if (RT_SUCCESS(rc))
876 {
877 RTFSOBJINFO info;
878
879 rc = RTDirQueryInfo (pHandle->dir.Handle, &info, RTFSOBJATTRADD_NOTHING);
880 if (RT_SUCCESS(rc))
881 {
882 pParms->Info = info;
883 }
884 }
885 else
886 {
887 switch (rc)
888 {
889 case VERR_FILE_NOT_FOUND: /* Does this make sense? */
890 pParms->Result = SHFL_FILE_NOT_FOUND;
891 break;
892 case VERR_PATH_NOT_FOUND:
893 pParms->Result = SHFL_PATH_NOT_FOUND;
894 break;
895 case VERR_ACCESS_DENIED:
896 pParms->Result = SHFL_FILE_EXISTS;
897 break;
898 default:
899 pParms->Result = SHFL_NO_RESULT;
900 }
901 }
902 }
903 }
904 if (RT_FAILURE(rc))
905 {
906 if ( (0 != pHandle)
907 && (0 != pHandle->dir.Handle))
908 {
909 RTDirClose(pHandle->dir.Handle);
910 pHandle->dir.Handle = 0;
911 }
912 if (SHFL_HANDLE_NIL != handle)
913 {
914 vbsfFreeFileHandle (handle);
915 }
916 }
917 else
918 {
919 pParms->Handle = handle;
920 }
921 LogFlow(("vbsfOpenDir: rc = %Vrc\n", rc));
922 return rc;
923}
924
925static int vbsfCloseDir (SHFLFILEHANDLE *pHandle)
926{
927 int rc = VINF_SUCCESS;
928
929 LogFlow(("vbsfCloseDir: Handle = %08X Search Handle = %08X\n",
930 pHandle->dir.Handle, pHandle->dir.SearchHandle));
931
932 RTDirClose (pHandle->dir.Handle);
933
934 if (pHandle->dir.SearchHandle)
935 RTDirClose(pHandle->dir.SearchHandle);
936
937 if (pHandle->dir.pLastValidEntry)
938 {
939 RTMemFree(pHandle->dir.pLastValidEntry);
940 pHandle->dir.pLastValidEntry = NULL;
941 }
942
943 LogFlow(("vbsfCloseDir: rc = %d\n", rc));
944
945 return rc;
946}
947
948
949static int vbsfCloseFile (SHFLFILEHANDLE *pHandle)
950{
951 int rc = VINF_SUCCESS;
952
953 LogFlow(("vbsfCloseFile: Handle = %08X\n",
954 pHandle->file.Handle));
955
956 rc = RTFileClose (pHandle->file.Handle);
957
958 LogFlow(("vbsfCloseFile: rc = %d\n", rc));
959
960 return rc;
961}
962
963/**
964 * Look up file or folder information by host path.
965 *
966 * @returns iprt status code (currently VINF_SUCCESS)
967 * @param pszFullPath The path of the file to be looked up
968 * @retval pParms->Result Status of the operation (success or error)
969 * @retval pParms->Info On success, information returned about the file
970 */
971static int vbsfLookupFile(char *pszPath, SHFLCREATEPARMS *pParms)
972{
973 RTFSOBJINFO info;
974 int rc;
975
976 rc = RTPathQueryInfo (pszPath, &info, RTFSOBJATTRADD_NOTHING);
977 LogFlow(("SHFL_CF_LOOKUP\n"));
978 /* Client just wants to know if the object exists. */
979 switch (rc)
980 {
981 case VINF_SUCCESS:
982 {
983 pParms->Info = info;
984 pParms->Result = SHFL_FILE_EXISTS;
985 break;
986 }
987
988 case VERR_FILE_NOT_FOUND:
989 {
990 pParms->Result = SHFL_FILE_NOT_FOUND;
991 rc = VINF_SUCCESS;
992 break;
993 }
994
995 case VERR_PATH_NOT_FOUND:
996 {
997 pParms->Result = SHFL_PATH_NOT_FOUND;
998 rc = VINF_SUCCESS;
999 break;
1000 }
1001 }
1002 return rc;
1003}
1004
1005/**
1006 * Create or open a file or folder. Perform character set and case
1007 * conversion on the file name if necessary.
1008 *
1009 * @returns IPRT status code, but see note below
1010 * @param pClient Data structure describing the client accessing the shared
1011 * folder
1012 * @param root The index of the shared folder in the table of mappings.
1013 * The host path of the shared folder is found using this.
1014 * @param pPath The path of the file or folder relative to the host path
1015 * indexed by root.
1016 * @param cbPath Presumably the length of the path in pPath. Actually
1017 * ignored, as pPath contains a length parameter.
1018 * @param pParms->Info If a new file is created or an old one overwritten, set
1019 * these attributes
1020 * @retval pParms->Result Shared folder result code, see include/VBox/shflsvc.h
1021 * @retval pParms->Handle Shared folder handle to the newly opened file
1022 * @retval pParms->Info Attributes of the file or folder opened
1023 *
1024 * @note This function returns success if a "non-exceptional" error occurred,
1025 * such as "no such file". In this case, the caller should check the
1026 * pParms->Result return value and whether pParms->Handle is valid.
1027 */
1028int vbsfCreate (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, SHFLCREATEPARMS *pParms)
1029{
1030 int rc = VINF_SUCCESS;
1031
1032 LogFlow(("vbsfCreate: pClient = %p, pPath = %p, cbPath = %d, pParms = %p CreateFlags=%x\n",
1033 pClient, pPath, cbPath, pParms, pParms->CreateFlags));
1034
1035 /* Check the client access rights to the root. */
1036 /** @todo */
1037
1038 /* Build a host full path for the given path, handle file name case issues (if the guest
1039 * expects case-insensitive paths but the host is case-sensitive) and convert ucs2 to utf8 if
1040 * necessary.
1041 */
1042 char *pszFullPath = NULL;
1043 uint32_t cbFullPathRoot = 0;
1044
1045 rc = vbsfBuildFullPath (pClient, root, pPath, cbPath, &pszFullPath, &cbFullPathRoot);
1046
1047 if (VBOX_SUCCESS (rc))
1048 {
1049 /* Reset return values in case client forgot to do so. */
1050 pParms->Result = SHFL_NO_RESULT;
1051 pParms->Handle = SHFL_HANDLE_NIL;
1052
1053 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_LOOKUP))
1054 {
1055 rc = vbsfLookupFile(pszFullPath, pParms);
1056 }
1057 else
1058 {
1059 /* Query path information. */
1060 RTFSOBJINFO info;
1061
1062 rc = RTPathQueryInfo (pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
1063 LogFlow(("RTPathQueryInfo returned %Vrc\n", rc));
1064
1065 if (RT_SUCCESS(rc))
1066 {
1067 /* Mark it as a directory in case the caller didn't. */
1068 /**
1069 * @todo I left this in in order not to change the behaviour of the
1070 * function too much. Is it really needed, and should it really be
1071 * here?
1072 */
1073 if (BIT_FLAG(info.Attr.fMode, RTFS_DOS_DIRECTORY))
1074 {
1075 pParms->CreateFlags |= SHFL_CF_DIRECTORY;
1076 }
1077
1078 /**
1079 * @todo This should be in the Windows Guest Additions, as no-one else
1080 * needs it.
1081 */
1082 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_OPEN_TARGET_DIRECTORY))
1083 {
1084 vbsfStripLastComponent (pszFullPath, cbFullPathRoot);
1085 pParms->CreateFlags &= ~SHFL_CF_ACT_MASK_IF_EXISTS;
1086 pParms->CreateFlags &= ~SHFL_CF_ACT_MASK_IF_NEW;
1087 pParms->CreateFlags |= SHFL_CF_DIRECTORY;
1088 pParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
1089 pParms->CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
1090 }
1091 }
1092
1093 rc = VINF_SUCCESS;
1094
1095 /* write access requested? */
1096 if (pParms->CreateFlags & ( SHFL_CF_ACT_REPLACE_IF_EXISTS
1097 | SHFL_CF_ACT_OVERWRITE_IF_EXISTS
1098 | SHFL_CF_ACT_CREATE_IF_NEW
1099 | SHFL_CF_ACCESS_WRITE))
1100 {
1101 /* is the guest allowed to write to this share? */
1102 bool fWritable;
1103 rc = vbsfMappingsQueryWritable (pClient, root, &fWritable);
1104 if (RT_FAILURE(rc) || !fWritable)
1105 rc = VERR_WRITE_PROTECT;
1106 }
1107
1108 if (RT_SUCCESS(rc))
1109 {
1110 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
1111 {
1112 rc = vbsfOpenDir (pszFullPath, pParms);
1113 }
1114 else
1115 {
1116 rc = vbsfOpenFile (pszFullPath, pParms);
1117 }
1118 }
1119 }
1120
1121 /* free the path string */
1122 vbsfFreeFullPath(pszFullPath);
1123 }
1124
1125 Log(("vbsfCreate: handle = %RX64 rc = %Vrc result=%x\n", (uint64_t)pParms->Handle, rc, pParms->Result));
1126
1127 return rc;
1128}
1129
1130int vbsfClose (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
1131{
1132 int rc = VINF_SUCCESS;
1133
1134 LogFlow(("vbsfClose: pClient = %p, Handle = %RX64\n",
1135 pClient, Handle));
1136
1137 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1138 Assert(pHandle);
1139 if (!pHandle)
1140 return VERR_INVALID_HANDLE;
1141
1142 switch (ShflHandleType (&pHandle->Header))
1143 {
1144 case SHFL_HF_TYPE_DIR:
1145 {
1146 rc = vbsfCloseDir (pHandle);
1147 break;
1148 }
1149 case SHFL_HF_TYPE_FILE:
1150 {
1151 rc = vbsfCloseFile (pHandle);
1152 break;
1153 }
1154 default:
1155 AssertFailed();
1156 break;
1157 }
1158 vbsfFreeFileHandle(Handle);
1159
1160 Log(("vbsfClose: rc = %Rrc\n", rc));
1161
1162 return rc;
1163}
1164
1165int vbsfRead (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer)
1166{
1167 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1168 size_t count = 0;
1169 int rc;
1170
1171 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1172 {
1173 AssertFailed();
1174 return VERR_INVALID_PARAMETER;
1175 }
1176
1177 Log(("vbsfRead %RX64 offset %RX64 bytes %x\n", Handle, offset, *pcbBuffer));
1178
1179 if (*pcbBuffer == 0)
1180 return VINF_SUCCESS; /* @todo correct? */
1181
1182
1183 rc = RTFileSeek(pHandle->file.Handle, offset, RTFILE_SEEK_BEGIN, NULL);
1184 if (rc != VINF_SUCCESS)
1185 {
1186 AssertRC(rc);
1187 return rc;
1188 }
1189
1190 rc = RTFileRead(pHandle->file.Handle, pBuffer, *pcbBuffer, &count);
1191 *pcbBuffer = (uint32_t)count;
1192 Log(("RTFileRead returned %Vrc bytes read %x\n", rc, count));
1193 return rc;
1194}
1195
1196int vbsfWrite (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer)
1197{
1198 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1199 size_t count = 0;
1200 int rc;
1201
1202 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1203 {
1204 AssertFailed();
1205 return VERR_INVALID_PARAMETER;
1206 }
1207
1208 Log(("vbsfWrite %RX64 offset %RX64 bytes %x\n", Handle, offset, *pcbBuffer));
1209
1210 /* Is the guest allowed to write to this share?
1211 * XXX Actually this check was still done in vbsfCreate() -- RTFILE_O_WRITE cannot be set if vbsfMappingsQueryWritable() failed. */
1212 bool fWritable;
1213 rc = vbsfMappingsQueryWritable (pClient, root, &fWritable);
1214 if (RT_FAILURE(rc) || !fWritable)
1215 return VERR_WRITE_PROTECT;
1216
1217 if (*pcbBuffer == 0)
1218 return VINF_SUCCESS; /** @todo correct? */
1219
1220 rc = RTFileSeek(pHandle->file.Handle, offset, RTFILE_SEEK_BEGIN, NULL);
1221 if (rc != VINF_SUCCESS)
1222 {
1223 AssertRC(rc);
1224 return rc;
1225 }
1226
1227 rc = RTFileWrite(pHandle->file.Handle, pBuffer, *pcbBuffer, &count);
1228 *pcbBuffer = (uint32_t)count;
1229 Log(("RTFileWrite returned %Vrc bytes written %x\n", rc, count));
1230 return rc;
1231}
1232
1233
1234int vbsfFlush(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
1235{
1236 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1237 int rc = VINF_SUCCESS;
1238
1239 if (pHandle == 0)
1240 {
1241 AssertFailed();
1242 return VERR_INVALID_HANDLE;
1243 }
1244
1245 Log(("vbsfFlush %RX64\n", Handle));
1246 rc = RTFileFlush(pHandle->file.Handle);
1247 AssertRC(rc);
1248 return rc;
1249}
1250
1251int vbsfDirList(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, SHFLSTRING *pPath, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer,
1252 uint32_t *pIndex, uint32_t *pcFiles)
1253{
1254 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR);
1255 PRTDIRENTRYEX pDirEntry = 0, pDirEntryOrg;
1256 uint32_t cbDirEntry, cbBufferOrg;
1257 int rc = VINF_SUCCESS;
1258 PSHFLDIRINFO pSFDEntry;
1259 PRTUTF16 pwszString;
1260 PRTDIR DirHandle;
1261 bool fUtf8;
1262
1263 fUtf8 = BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8) != 0;
1264
1265 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1266 {
1267 AssertFailed();
1268 return VERR_INVALID_PARAMETER;
1269 }
1270 Assert(pIndex && *pIndex == 0);
1271 DirHandle = pHandle->dir.Handle;
1272
1273 cbDirEntry = 4096;
1274 pDirEntryOrg = pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
1275 if (pDirEntry == 0)
1276 {
1277 AssertFailed();
1278 return VERR_NO_MEMORY;
1279 }
1280
1281 cbBufferOrg = *pcbBuffer;
1282 *pcbBuffer = 0;
1283 pSFDEntry = (PSHFLDIRINFO)pBuffer;
1284
1285 *pIndex = 1; /* not yet complete */
1286 *pcFiles = 0;
1287
1288 if (pPath)
1289 {
1290 if (pHandle->dir.SearchHandle == 0)
1291 {
1292 /* Build a host full path for the given path
1293 * and convert ucs2 to utf8 if necessary.
1294 */
1295 char *pszFullPath = NULL;
1296
1297 Assert(pHandle->dir.pLastValidEntry == 0);
1298
1299 rc = vbsfBuildFullPath (pClient, root, pPath, pPath->u16Size, &pszFullPath, NULL, true);
1300
1301 if (VBOX_SUCCESS (rc))
1302 {
1303 rc = RTDirOpenFiltered (&pHandle->dir.SearchHandle, pszFullPath, RTDIRFILTER_WINNT);
1304
1305 /* free the path string */
1306 vbsfFreeFullPath(pszFullPath);
1307
1308 if (VBOX_FAILURE (rc))
1309 goto end;
1310 }
1311 else
1312 goto end;
1313 }
1314 Assert(pHandle->dir.SearchHandle);
1315 DirHandle = pHandle->dir.SearchHandle;
1316 }
1317
1318 while(cbBufferOrg)
1319 {
1320 uint32_t cbDirEntrySize = cbDirEntry;
1321 uint32_t cbNeeded;
1322
1323 /* Do we still have a valid last entry for the active search? If so, then return it here */
1324 if (pHandle->dir.pLastValidEntry)
1325 {
1326 pDirEntry = pHandle->dir.pLastValidEntry;
1327 }
1328 else
1329 {
1330 pDirEntry = pDirEntryOrg;
1331
1332 rc = RTDirReadEx(DirHandle, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING);
1333 if (rc == VERR_NO_MORE_FILES)
1334 {
1335 *pIndex = 0; /* listing completed */
1336 break;
1337 }
1338
1339 if (VINF_SUCCESS != rc && rc != VWRN_NO_DIRENT_INFO)
1340 {
1341 AssertFailed();
1342 if (rc != VERR_NO_TRANSLATION)
1343 break;
1344 else
1345 continue;
1346 }
1347 }
1348
1349 cbNeeded = RT_OFFSETOF (SHFLDIRINFO, name.String);
1350 if (fUtf8)
1351 cbNeeded += pDirEntry->cbName + 1;
1352 else
1353 /* Overestimating, but that's ok */
1354 cbNeeded += (pDirEntry->cbName + 1) * 2;
1355
1356 if (cbBufferOrg < cbNeeded)
1357 {
1358 /* No room, so save this directory entry, or else it's lost forever */
1359 pHandle->dir.pLastValidEntry = pDirEntry;
1360
1361 if (*pcFiles == 0)
1362 {
1363 AssertFailed();
1364 return VINF_BUFFER_OVERFLOW; /* Return directly and don't free pDirEntry */
1365 }
1366 return VINF_SUCCESS; /* Return directly and don't free pDirEntry */
1367 }
1368
1369 pSFDEntry->Info = pDirEntry->Info;
1370 pSFDEntry->cucShortName = 0;
1371
1372 if (fUtf8)
1373 {
1374 void *src, *dst;
1375
1376 src = &pDirEntry->szName[0];
1377 dst = &pSFDEntry->name.String.utf8[0];
1378
1379 memcpy (dst, src, pDirEntry->cbName + 1);
1380
1381 pSFDEntry->name.u16Size = pDirEntry->cbName + 1;
1382 pSFDEntry->name.u16Length = pDirEntry->cbName;
1383 }
1384 else
1385 {
1386 pSFDEntry->name.String.ucs2[0] = 0;
1387 pwszString = pSFDEntry->name.String.ucs2;
1388 int rc2 = RTStrToUtf16Ex(pDirEntry->szName, RTSTR_MAX, &pwszString, pDirEntry->cbName+1, NULL);
1389 AssertRC(rc2);
1390
1391#ifdef RT_OS_DARWIN
1392/** @todo This belongs in rtPathToNative or in the windows shared folder file system driver...
1393 * The question is simply whether the NFD normalization is actually applied on a (virtaul) file
1394 * system level in darwin, or just by the user mode application libs. */
1395 {
1396 // Convert to
1397 // Normalization Form C (composed Unicode). We need this because
1398 // Mac OS X file system uses NFD (Normalization Form D :decomposed Unicode)
1399 // while most other OS', server-side programs usually expect NFC.
1400 uint16_t ucs2Length;
1401 CFRange rangeCharacters;
1402 CFMutableStringRef inStr = ::CFStringCreateMutable(NULL, 0);
1403
1404 ::CFStringAppendCharacters(inStr, (UniChar *)pwszString, RTUtf16Len (pwszString));
1405 ::CFStringNormalize(inStr, kCFStringNormalizationFormC);
1406 ucs2Length = ::CFStringGetLength(inStr);
1407
1408 rangeCharacters.location = 0;
1409 rangeCharacters.length = ucs2Length;
1410 ::CFStringGetCharacters(inStr, rangeCharacters, pwszString);
1411 pwszString[ucs2Length] = 0x0000; // NULL terminated
1412
1413 CFRelease(inStr);
1414 }
1415#endif
1416 pSFDEntry->name.u16Length = RTUtf16Len (pSFDEntry->name.String.ucs2) * 2;
1417 pSFDEntry->name.u16Size = pSFDEntry->name.u16Length + 2;
1418
1419 Log(("SHFL: File name size %d\n", pSFDEntry->name.u16Size));
1420 Log(("SHFL: File name %ls\n", &pSFDEntry->name.String.ucs2));
1421
1422 // adjust cbNeeded (it was overestimated before)
1423 cbNeeded = RT_OFFSETOF (SHFLDIRINFO, name.String) + pSFDEntry->name.u16Size;
1424 }
1425
1426 pSFDEntry = (PSHFLDIRINFO)((uintptr_t)pSFDEntry + cbNeeded);
1427 *pcbBuffer += cbNeeded;
1428 cbBufferOrg-= cbNeeded;
1429
1430 *pcFiles += 1;
1431
1432 /* Free the saved last entry, that we've just returned */
1433 if (pHandle->dir.pLastValidEntry)
1434 {
1435 RTMemFree(pHandle->dir.pLastValidEntry);
1436 pHandle->dir.pLastValidEntry = NULL;
1437 }
1438
1439 if (flags & SHFL_LIST_RETURN_ONE)
1440 break; /* we're done */
1441 }
1442 Assert(rc != VINF_SUCCESS || *pcbBuffer > 0);
1443
1444end:
1445 if (pDirEntry)
1446 RTMemFree(pDirEntry);
1447
1448 return rc;
1449}
1450
1451int vbsfQueryFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1452{
1453 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1454 int rc = VINF_SUCCESS;
1455 RTFSOBJINFO *pObjInfo = (RTFSOBJINFO *)pBuffer;
1456
1457
1458 if (pHandle == 0 || pcbBuffer == 0 || pObjInfo == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1459 {
1460 AssertFailed();
1461 return VERR_INVALID_PARAMETER;
1462 }
1463
1464 /* @todo other options */
1465 Assert(flags == (SHFL_INFO_GET|SHFL_INFO_FILE));
1466
1467 *pcbBuffer = 0;
1468
1469 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_DIR)
1470 {
1471 rc = RTDirQueryInfo(pHandle->dir.Handle, pObjInfo, RTFSOBJATTRADD_NOTHING);
1472 }
1473 else
1474 {
1475 rc = RTFileQueryInfo(pHandle->file.Handle, pObjInfo, RTFSOBJATTRADD_NOTHING);
1476 }
1477 if (rc == VINF_SUCCESS)
1478 {
1479 *pcbBuffer = sizeof(RTFSOBJINFO);
1480 }
1481 else
1482 AssertFailed();
1483
1484 return rc;
1485}
1486
1487static int vbsfSetFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1488{
1489 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1490 int rc = VINF_SUCCESS;
1491 RTFSOBJINFO *pSFDEntry;
1492
1493 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1494 {
1495 AssertFailed();
1496 return VERR_INVALID_PARAMETER;
1497 }
1498
1499 *pcbBuffer = 0;
1500 pSFDEntry = (RTFSOBJINFO *)pBuffer;
1501
1502 Assert(flags == (SHFL_INFO_SET | SHFL_INFO_FILE));
1503
1504 /* Change only the time values that are not zero */
1505 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_DIR)
1506 {
1507 rc = RTDirSetTimes(pHandle->dir.Handle,
1508 (RTTimeSpecGetNano(&pSFDEntry->AccessTime)) ? &pSFDEntry->AccessTime : NULL,
1509 (RTTimeSpecGetNano(&pSFDEntry->ModificationTime)) ? &pSFDEntry->ModificationTime: NULL,
1510 (RTTimeSpecGetNano(&pSFDEntry->ChangeTime)) ? &pSFDEntry->ChangeTime: NULL,
1511 (RTTimeSpecGetNano(&pSFDEntry->BirthTime)) ? &pSFDEntry->BirthTime: NULL
1512 );
1513 }
1514 else
1515 {
1516 rc = RTFileSetTimes(pHandle->file.Handle,
1517 (RTTimeSpecGetNano(&pSFDEntry->AccessTime)) ? &pSFDEntry->AccessTime : NULL,
1518 (RTTimeSpecGetNano(&pSFDEntry->ModificationTime)) ? &pSFDEntry->ModificationTime: NULL,
1519 (RTTimeSpecGetNano(&pSFDEntry->ChangeTime)) ? &pSFDEntry->ChangeTime: NULL,
1520 (RTTimeSpecGetNano(&pSFDEntry->BirthTime)) ? &pSFDEntry->BirthTime: NULL
1521 );
1522 }
1523 if (rc != VINF_SUCCESS)
1524 {
1525 Log(("RTFileSetTimes failed with %Vrc\n", rc));
1526 Log(("AccessTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->AccessTime)));
1527 Log(("ModificationTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->ModificationTime)));
1528 Log(("ChangeTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->ChangeTime)));
1529 Log(("BirthTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->AccessTime)));
1530 /* temporary hack */
1531 rc = VINF_SUCCESS;
1532 }
1533
1534 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_FILE)
1535 {
1536 /* Change file attributes if necessary */
1537 if (pSFDEntry->Attr.fMode)
1538 {
1539 rc = RTFileSetMode((RTFILE)pHandle->file.Handle, pSFDEntry->Attr.fMode);
1540 if (rc != VINF_SUCCESS)
1541 {
1542 Log(("RTFileSetMode %x failed with %Vrc\n", pSFDEntry->Attr.fMode, rc));
1543 /* silent failure, because this tends to fail with e.g. windows guest & linux host */
1544 rc = VINF_SUCCESS;
1545 }
1546 }
1547 }
1548
1549 if (rc == VINF_SUCCESS)
1550 {
1551 uint32_t bufsize = sizeof(*pSFDEntry);
1552
1553 rc = vbsfQueryFileInfo(pClient, root, Handle, SHFL_INFO_GET|SHFL_INFO_FILE, &bufsize, (uint8_t *)pSFDEntry);
1554 if (rc == VINF_SUCCESS)
1555 {
1556 *pcbBuffer = sizeof(RTFSOBJINFO);
1557 }
1558 else
1559 AssertFailed();
1560 }
1561
1562 return rc;
1563}
1564
1565
1566static int vbsfSetEndOfFile(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1567{
1568 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1569 int rc = VINF_SUCCESS;
1570 RTFSOBJINFO *pSFDEntry;
1571
1572 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1573 {
1574 AssertFailed();
1575 return VERR_INVALID_PARAMETER;
1576 }
1577
1578 *pcbBuffer = 0;
1579 pSFDEntry = (RTFSOBJINFO *)pBuffer;
1580
1581 if (flags & SHFL_INFO_SIZE)
1582 {
1583 rc = RTFileSetSize(pHandle->file.Handle, pSFDEntry->cbObject);
1584 if (rc != VINF_SUCCESS)
1585 AssertFailed();
1586 }
1587 else
1588 AssertFailed();
1589
1590 if (rc == VINF_SUCCESS)
1591 {
1592 RTFSOBJINFO fileinfo;
1593
1594 /* Query the new object info and return it */
1595 rc = RTFileQueryInfo(pHandle->file.Handle, &fileinfo, RTFSOBJATTRADD_NOTHING);
1596 if (rc == VINF_SUCCESS)
1597 {
1598 *pSFDEntry = fileinfo;
1599 *pcbBuffer = sizeof(RTFSOBJINFO);
1600 }
1601 else
1602 AssertFailed();
1603 }
1604
1605 return rc;
1606}
1607
1608int vbsfQueryVolumeInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1609{
1610 int rc = VINF_SUCCESS;
1611 SHFLVOLINFO *pSFDEntry;
1612 char *pszFullPath = NULL;
1613 SHFLSTRING dummy;
1614
1615 if (pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(SHFLVOLINFO))
1616 {
1617 AssertFailed();
1618 return VERR_INVALID_PARAMETER;
1619 }
1620
1621 /* @todo other options */
1622 Assert(flags == (SHFL_INFO_GET|SHFL_INFO_VOLUME));
1623
1624 *pcbBuffer = 0;
1625 pSFDEntry = (PSHFLVOLINFO)pBuffer;
1626
1627 ShflStringInitBuffer(&dummy, sizeof(dummy));
1628 rc = vbsfBuildFullPath (pClient, root, &dummy, 0, &pszFullPath, NULL);
1629
1630 if (VBOX_SUCCESS (rc))
1631 {
1632 rc = RTFsQuerySizes(pszFullPath, &pSFDEntry->ullTotalAllocationBytes, &pSFDEntry->ullAvailableAllocationBytes, &pSFDEntry->ulBytesPerAllocationUnit, &pSFDEntry->ulBytesPerSector);
1633 if (rc != VINF_SUCCESS)
1634 goto exit;
1635
1636 rc = RTFsQuerySerial(pszFullPath, &pSFDEntry->ulSerial);
1637 if (rc != VINF_SUCCESS)
1638 goto exit;
1639
1640 rc = RTFsQueryProperties(pszFullPath, &pSFDEntry->fsProperties);
1641 if (rc != VINF_SUCCESS)
1642 goto exit;
1643
1644 *pcbBuffer = sizeof(SHFLVOLINFO);
1645 }
1646 else AssertFailed();
1647
1648exit:
1649 AssertMsg(rc == VINF_SUCCESS, ("failure: rc = %Vrc\n", rc));
1650 /* free the path string */
1651 vbsfFreeFullPath(pszFullPath);
1652 return rc;
1653}
1654
1655int vbsfQueryFSInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1656{
1657 if (pcbBuffer == 0 || pBuffer == 0)
1658 {
1659 AssertFailed();
1660 return VERR_INVALID_PARAMETER;
1661 }
1662
1663 if (flags & SHFL_INFO_FILE)
1664 return vbsfQueryFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1665
1666 if (flags & SHFL_INFO_VOLUME)
1667 return vbsfQueryVolumeInfo(pClient, root, flags, pcbBuffer, pBuffer);
1668
1669 AssertFailed();
1670 return VERR_INVALID_PARAMETER;
1671}
1672
1673int vbsfSetFSInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1674{
1675 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE|SHFL_HF_TYPE_VOLUME);
1676
1677 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1678 {
1679 AssertFailed();
1680 return VERR_INVALID_PARAMETER;
1681 }
1682
1683 /* is the guest allowed to write to this share? */
1684 bool fWritable;
1685 int rc = vbsfMappingsQueryWritable (pClient, root, &fWritable);
1686 if (RT_FAILURE(rc) || !fWritable)
1687 return VERR_WRITE_PROTECT;
1688
1689 if (flags & SHFL_INFO_FILE)
1690 return vbsfSetFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1691
1692 if (flags & SHFL_INFO_SIZE)
1693 return vbsfSetEndOfFile(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1694
1695// if (flags & SHFL_INFO_VOLUME)
1696// return vbsfVolumeInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1697 AssertFailed();
1698 return VERR_INVALID_PARAMETER;
1699}
1700
1701int vbsfLock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
1702{
1703 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1704 uint32_t fRTLock = 0;
1705 int rc;
1706
1707 Assert((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL);
1708
1709 if (pHandle == 0)
1710 {
1711 AssertFailed();
1712 return VERR_INVALID_HANDLE;
1713 }
1714 if ( ((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL)
1715 || (flags & SHFL_LOCK_ENTIRE)
1716 )
1717 {
1718 AssertFailed();
1719 return VERR_INVALID_PARAMETER;
1720 }
1721
1722 /* Lock type */
1723 switch(flags & SHFL_LOCK_MODE_MASK)
1724 {
1725 case SHFL_LOCK_SHARED:
1726 fRTLock = RTFILE_LOCK_READ;
1727 break;
1728
1729 case SHFL_LOCK_EXCLUSIVE:
1730 fRTLock = RTFILE_LOCK_READ | RTFILE_LOCK_WRITE;
1731 break;
1732
1733 default:
1734 AssertFailed();
1735 return VERR_INVALID_PARAMETER;
1736 }
1737
1738 /* Lock wait type */
1739 if (flags & SHFL_LOCK_WAIT)
1740 fRTLock |= RTFILE_LOCK_WAIT;
1741 else
1742 fRTLock |= RTFILE_LOCK_IMMEDIATELY;
1743
1744#ifdef RT_OS_WINDOWS
1745 rc = RTFileLock(pHandle->file.Handle, fRTLock, offset, length);
1746 if (rc != VINF_SUCCESS)
1747 Log(("RTFileLock %RTfile %RX64 %RX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
1748#else
1749 Log(("vbsfLock: Pretend success handle=%x\n", Handle));
1750 rc = VINF_SUCCESS;
1751#endif
1752 return rc;
1753}
1754
1755int vbsfUnlock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
1756{
1757 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1758 int rc;
1759
1760 Assert((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL);
1761
1762 if (pHandle == 0)
1763 {
1764 return VERR_INVALID_HANDLE;
1765 }
1766 if ( ((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL)
1767 || (flags & SHFL_LOCK_ENTIRE)
1768 )
1769 {
1770 return VERR_INVALID_PARAMETER;
1771 }
1772
1773#ifdef RT_OS_WINDOWS
1774 rc = RTFileUnlock(pHandle->file.Handle, offset, length);
1775 if (rc != VINF_SUCCESS)
1776 Log(("RTFileUnlock %RTfile %RX64 %RTX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
1777#else
1778 Log(("vbsfUnlock: Pretend success handle=%x\n", Handle));
1779 rc = VINF_SUCCESS;
1780#endif
1781
1782 return rc;
1783}
1784
1785
1786int vbsfRemove(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, uint32_t flags)
1787{
1788 int rc = VINF_SUCCESS;
1789
1790 /* Validate input */
1791 if ( flags & ~(SHFL_REMOVE_FILE|SHFL_REMOVE_DIR)
1792 || cbPath == 0
1793 || pPath == 0)
1794 {
1795 AssertFailed();
1796 return VERR_INVALID_PARAMETER;
1797 }
1798
1799 /* Build a host full path for the given path
1800 * and convert ucs2 to utf8 if necessary.
1801 */
1802 char *pszFullPath = NULL;
1803
1804 rc = vbsfBuildFullPath (pClient, root, pPath, cbPath, &pszFullPath, NULL);
1805 if (VBOX_SUCCESS (rc))
1806 {
1807 /* is the guest allowed to write to this share? */
1808 bool fWritable;
1809 rc = vbsfMappingsQueryWritable (pClient, root, &fWritable);
1810 if (RT_FAILURE(rc) || !fWritable)
1811 rc = VERR_WRITE_PROTECT;
1812
1813 if (VBOX_SUCCESS (rc))
1814 {
1815 if (flags & SHFL_REMOVE_FILE)
1816 rc = RTFileDelete(pszFullPath);
1817 else
1818 rc = RTDirRemove(pszFullPath);
1819 }
1820
1821#ifndef DEBUG_dmik
1822 // VERR_ACCESS_DENIED for example?
1823 // Assert(rc == VINF_SUCCESS || rc == VERR_DIR_NOT_EMPTY);
1824#endif
1825 /* free the path string */
1826 vbsfFreeFullPath(pszFullPath);
1827 }
1828 return rc;
1829}
1830
1831
1832int vbsfRename(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pSrc, SHFLSTRING *pDest, uint32_t flags)
1833{
1834 int rc = VINF_SUCCESS;
1835
1836 /* Validate input */
1837 if ( flags & ~(SHFL_REMOVE_FILE|SHFL_REMOVE_DIR|SHFL_RENAME_REPLACE_IF_EXISTS)
1838 || pSrc == 0
1839 || pDest == 0)
1840 {
1841 AssertFailed();
1842 return VERR_INVALID_PARAMETER;
1843 }
1844
1845 /* Build a host full path for the given path
1846 * and convert ucs2 to utf8 if necessary.
1847 */
1848 char *pszFullPathSrc = NULL;
1849 char *pszFullPathDest = NULL;
1850
1851 rc = vbsfBuildFullPath (pClient, root, pSrc, pSrc->u16Size, &pszFullPathSrc, NULL);
1852 if (rc != VINF_SUCCESS)
1853 return rc;
1854
1855 rc = vbsfBuildFullPath (pClient, root, pDest, pDest->u16Size, &pszFullPathDest, NULL);
1856 if (VBOX_SUCCESS (rc))
1857 {
1858 Log(("Rename %s to %s\n", pszFullPathSrc, pszFullPathDest));
1859
1860 /* is the guest allowed to write to this share? */
1861 bool fWritable;
1862 rc = vbsfMappingsQueryWritable (pClient, root, &fWritable);
1863 if (RT_FAILURE(rc) || !fWritable)
1864 rc = VERR_WRITE_PROTECT;
1865
1866 if (VBOX_SUCCESS (rc))
1867 {
1868 if (flags & SHFL_RENAME_FILE)
1869 {
1870 rc = RTFileMove(pszFullPathSrc, pszFullPathDest, (flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTFILEMOVE_FLAGS_REPLACE : 0);
1871 }
1872 else
1873 {
1874 /* NT ignores the REPLACE flag and simply return and already exists error. */
1875 rc = RTDirRename(pszFullPathSrc, pszFullPathDest, (flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTPATHRENAME_FLAGS_REPLACE : 0);
1876 }
1877 }
1878
1879#ifndef DEBUG_dmik
1880 AssertRC(rc);
1881#endif
1882 /* free the path string */
1883 vbsfFreeFullPath(pszFullPathDest);
1884 }
1885 /* free the path string */
1886 vbsfFreeFullPath(pszFullPathSrc);
1887 return rc;
1888}
1889
1890/*
1891 * Clean up our mess by freeing all handles that are still valid.
1892 *
1893 */
1894int vbsfDisconnect(SHFLCLIENTDATA *pClient)
1895{
1896 for (int i=0;i<SHFLHANDLE_MAX;i++)
1897 {
1898 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(i, SHFL_HF_TYPE_MASK);
1899
1900 if (pHandle)
1901 {
1902 Log(("Open handle %08x\n", i));
1903 vbsfClose(pClient, SHFL_HANDLE_ROOT /* incorrect, but it's not important */, (SHFLHANDLE)i);
1904 }
1905 }
1906 return VINF_SUCCESS;
1907}
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