VirtualBox

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

Last change on this file since 18130 was 18128, checked in by vboxsync, 16 years ago

IPRT, Shared Folders: Implemented file attributes access flags for RTFileOpen on Windows host (xTracker #3739).

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

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