VirtualBox

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

Last change on this file since 3999 was 3999, checked in by vboxsync, 18 years ago

bugfix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.4 KB
Line 
1/** @file
2 *
3 * Shared Folders:
4 * VBox Shared Folders.
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
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
36#undef LogFlow
37#define LogFlow Log
38
39void vbsfStripLastComponent (char *pszFullPath, uint32_t cbFullPathRoot)
40{
41 RTUNICP cp;
42
43 /* Do not strip root. */
44 char *s = pszFullPath + cbFullPathRoot;
45 char *delimSecondLast = NULL;
46 char *delimLast = NULL;
47
48 LogFlowFunc(("%s -> %s\n", pszFullPath, s));
49
50 for (;;)
51 {
52 cp = RTStrGetCp(s);
53
54 if (cp == RTUNICP_INVALID || cp == 0)
55 {
56 break;
57 }
58
59 if (cp == RTPATH_DELIMITER)
60 {
61 if (delimLast != NULL)
62 {
63 delimSecondLast = delimLast;
64 }
65
66 delimLast = s;
67 }
68
69 s = RTStrNextCp (s);
70 }
71
72 if (cp == 0)
73 {
74 if (delimLast + 1 == s)
75 {
76 if (delimSecondLast)
77 {
78 *delimSecondLast = 0;
79 }
80 else if (delimLast)
81 {
82 *delimLast = 0;
83 }
84 }
85 else
86 {
87 if (delimLast)
88 {
89 *delimLast = 0;
90 }
91 }
92 }
93
94 LogFlowFunc(("%s, %s, %s\n", pszFullPath, delimLast, delimSecondLast));
95}
96
97static int vbsfCorrectCasing(char *pszFullPath, char *pszStartComponent)
98{
99 PRTDIRENTRYEX pDirEntry = NULL;
100 uint32_t cbDirEntry, cbComponent;
101 int rc = VERR_FILE_NOT_FOUND;
102 PRTDIR hSearch = 0;
103 char szWildCard[4];
104
105 Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent));
106
107 cbComponent = strlen(pszStartComponent);
108
109 cbDirEntry = 4096;
110 pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
111 if (pDirEntry == 0)
112 {
113 AssertFailed();
114 return VERR_NO_MEMORY;
115 }
116
117 /** @todo this is quite inefficient, especially for directories with many files */
118 Assert(pszFullPath < pszStartComponent-1);
119 Assert(*(pszStartComponent-1) == RTPATH_DELIMITER);
120 *(pszStartComponent-1) = 0;
121 strcpy(pDirEntry->szName, pszFullPath);
122 szWildCard[0] = RTPATH_DELIMITER;
123 szWildCard[1] = '*';
124 szWildCard[2] = 0;
125 strcat(pDirEntry->szName, szWildCard);
126
127 rc = RTDirOpenFiltered (&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT);
128 *(pszStartComponent-1) = RTPATH_DELIMITER;
129 if (VBOX_FAILURE(rc))
130 goto end;
131
132 for(;;)
133 {
134 uint32_t cbDirEntrySize = cbDirEntry;
135
136 rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING);
137 if (rc == VERR_NO_MORE_FILES)
138 break;
139
140 if (VINF_SUCCESS != rc && rc != VWRN_NO_DIRENT_INFO)
141 {
142 AssertFailed();
143 if (rc != VERR_NO_TRANSLATION)
144 break;
145 else
146 continue;
147 }
148
149 Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0]));
150 if ( pDirEntry->cbName == cbComponent
151 && !RTStrICmp(pszStartComponent, &pDirEntry->szName[0]))
152 {
153 Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent));
154 strcpy(pszStartComponent, &pDirEntry->szName[0]);
155 rc = VINF_SUCCESS;
156 break;
157 }
158 }
159
160end:
161 if (VBOX_FAILURE(rc))
162 Log(("vbsfCorrectCasing %s failed with %d\n", pszStartComponent, rc));
163
164 if (pDirEntry)
165 RTMemFree(pDirEntry);
166
167 if (hSearch)
168 RTDirClose(hSearch);
169 return rc;
170}
171
172static int vbsfBuildFullPath (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath,
173 uint32_t cbPath, char **ppszFullPath, uint32_t *pcbFullPathRoot, bool fWildCard = false)
174{
175 int rc = VINF_SUCCESS;
176
177 char *pszFullPath = NULL;
178
179 /* Query UCS2 root prefix for the path, cbRoot is the length in bytes including trailing (RTUCS2)0. */
180 uint32_t cbRoot = 0;
181 const RTUCS2 *pszRoot = vbsfMappingsQueryHostRoot (root, &cbRoot);
182
183 if (!pszRoot || cbRoot == 0)
184 {
185 return VERR_INVALID_PARAMETER;
186 }
187
188 if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
189 {
190 int rc;
191 char *utf8Root;
192
193 rc = RTUtf16ToUtf8 (pszRoot, &utf8Root);
194 if (VBOX_SUCCESS (rc))
195 {
196 size_t cbUtf8Root, cbUtf8FullPath;
197 char *utf8FullPath;
198
199 cbUtf8Root = strlen (utf8Root);
200 cbUtf8FullPath = cbUtf8Root + 1 + pPath->u16Length + 1;
201 utf8FullPath = (char *) RTMemAllocZ (cbUtf8FullPath);
202
203 if (!utf8FullPath)
204 {
205 rc = VERR_NO_MEMORY;
206 *ppszFullPath = NULL;
207 }
208 else
209 {
210 memcpy (utf8FullPath, utf8Root, cbUtf8Root);
211 memcpy (utf8FullPath + cbUtf8Root + 1,
212 &pPath->String.utf8[0],
213 pPath->u16Length);
214
215 utf8FullPath[cbUtf8Root] = '/';
216 utf8FullPath[cbUtf8FullPath - 1] = 0;
217 pszFullPath = utf8FullPath;
218
219 if (pcbFullPathRoot)
220 *pcbFullPathRoot = cbUtf8Root; /* Must index the path delimiter. */
221 }
222
223 RTStrFree (utf8Root);
224 }
225 else
226 {
227 Log (("vbsfBuildFullPath: RTUtf16ToUtf8 failed with %Vrc\n", rc));
228 }
229 }
230 else
231 {
232 /* Client sends us UCS2, so convert it to UTF8. */
233 Log(("Root %ls path %.*ls\n", pszRoot, pPath->u16Length/sizeof(pPath->String.ucs2[0]), pPath->String.ucs2));
234
235 /* Allocate buffer that will be able to contain
236 * the root prefix and the pPath converted to UTF8.
237 * Expect a 2 bytes UCS2 to be converted to 8 bytes UTF8
238 * in worst case.
239 */
240 uint32_t cbFullPath = (cbRoot/sizeof (RTUCS2) + ShflStringLength (pPath)) * 4;
241
242 pszFullPath = (char *)RTMemAllocZ (cbFullPath);
243
244 if (!pszFullPath)
245 {
246 rc = VERR_NO_MEMORY;
247 }
248 else
249 {
250 uint32_t cb = cbFullPath;
251
252 rc = RTStrUcs2ToUtf8Ex (&pszFullPath, cb, pszRoot);
253 if (VBOX_FAILURE(rc))
254 {
255 AssertFailed();
256 return rc;
257 }
258
259 char *dst = pszFullPath;
260
261 cbRoot = strlen(dst);
262 if (dst[cbRoot - 1] != RTPATH_DELIMITER)
263 {
264 dst[cbRoot] = RTPATH_DELIMITER;
265 cbRoot++;
266 }
267
268 if (pcbFullPathRoot)
269 *pcbFullPathRoot = cbRoot - 1; /* Must index the path delimiter. */
270
271 dst += cbRoot;
272 cb -= cbRoot;
273
274 if (pPath->u16Length)
275 {
276 /* Convert and copy components. */
277 RTUCS2 *src = &pPath->String.ucs2[0];
278
279 /* Correct path delimiters */
280 if (pClient->PathDelimiter != RTPATH_DELIMITER)
281 {
282 LogFlow(("Correct path delimiter in %ls\n", src));
283 while (*src)
284 {
285 if (*src == pClient->PathDelimiter)
286 *src = RTPATH_DELIMITER;
287 src++;
288 }
289 src = &pPath->String.ucs2[0];
290 LogFlow(("Corrected string %ls\n", src));
291 }
292 if (*src == RTPATH_DELIMITER)
293 src++; /* we already appended a delimiter to the first part */
294
295 rc = RTStrUcs2ToUtf8Ex (&dst, cb, src);
296 if (VBOX_FAILURE(rc))
297 {
298 AssertFailed();
299 return rc;
300 }
301
302 uint32_t l = strlen (dst);
303
304 cb -= l;
305 dst += l;
306
307 Assert(cb > 0);
308 }
309
310 /* Nul terminate the string */
311 *dst = 0;
312 }
313 }
314
315 if (VBOX_SUCCESS (rc))
316 {
317 /* When the host file system is case sensitive and the guest expects a case insensitive fs, then problems can occur */
318 if ( vbsfIsHostMappingCaseSensitive (root)
319 && !vbsfIsGuestMappingCaseSensitive(root))
320 {
321 RTFSOBJINFO info;
322 char *pszWildCardComponent = NULL;
323
324 if (fWildCard)
325 {
326 /* strip off the last path component, that contains the wildcard(s) */
327 uint32_t len = strlen(pszFullPath);
328 char *src = pszFullPath + len - 1;
329
330 while(src > pszFullPath)
331 {
332 if (*src == RTPATH_DELIMITER)
333 break;
334 src--;
335 }
336 if (*src == RTPATH_DELIMITER)
337 {
338 bool fHaveWildcards = false;
339 char *temp = src;
340
341 while(*temp)
342 {
343 char uc = *temp;
344 if (uc == '*' || uc == '?' || uc == '>' || uc == '<' || uc == '"')
345 {
346 fHaveWildcards = true;
347 break;
348 }
349 temp++;
350 }
351
352 if (fHaveWildcards)
353 {
354 pszWildCardComponent = src;
355 *pszWildCardComponent = 0;
356 }
357 }
358 }
359
360 /** @todo don't check when creating files or directories; waste of time */
361 rc = RTPathQueryInfo(pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
362 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
363 {
364 uint32_t len = strlen(pszFullPath);
365 char *src = pszFullPath + len - 1;
366
367 Log(("Handle case insenstive guest fs on top of host case sensitive fs for %s\n", pszFullPath));
368
369 /* Find partial path that's valid */
370 while(src > pszFullPath)
371 {
372 if (*src == RTPATH_DELIMITER)
373 {
374 *src = 0;
375 rc = RTPathQueryInfo (pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
376 *src = RTPATH_DELIMITER;
377 if (rc == VINF_SUCCESS)
378 {
379#ifdef DEBUG
380 *src = 0;
381 Log(("Found valid partial path %s\n", pszFullPath));
382 *src = RTPATH_DELIMITER;
383#endif
384 break;
385 }
386 }
387
388 src--;
389 }
390 Assert(*src == RTPATH_DELIMITER && VBOX_SUCCESS(rc));
391 if ( *src == RTPATH_DELIMITER
392 && VBOX_SUCCESS(rc))
393 {
394 src++;
395 for(;;)
396 {
397 char *end = src;
398 bool fEndOfString = true;
399
400 while(*end)
401 {
402 if (*end == RTPATH_DELIMITER)
403 break;
404 end++;
405 }
406
407 if (*end == RTPATH_DELIMITER)
408 {
409 fEndOfString = false;
410 *end = 0;
411 rc = RTPathQueryInfo(src, &info, RTFSOBJATTRADD_NOTHING);
412 Assert(rc == VINF_SUCCESS || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND);
413 }
414 else
415 if (end == src)
416 rc = VINF_SUCCESS; /* trailing delimiter */
417 else
418 rc = VERR_FILE_NOT_FOUND;
419
420 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
421 {
422 /* path component is invalid; try to correct the casing */
423 rc = vbsfCorrectCasing(pszFullPath, src);
424 if (VBOX_FAILURE(rc))
425 break;
426 }
427
428 if (fEndOfString)
429 break;
430
431 *end = RTPATH_DELIMITER;
432 src = end + 1;
433 }
434 if (VBOX_FAILURE(rc))
435 Log(("Unable to find suitable component rc=%d\n", rc));
436 }
437 else
438 rc = VERR_FILE_NOT_FOUND;
439
440 }
441 if (pszWildCardComponent)
442 *pszWildCardComponent = RTPATH_DELIMITER;
443
444 /* might be a new file so don't fail here! */
445 rc = VINF_SUCCESS;
446 }
447 *ppszFullPath = pszFullPath;
448
449 LogFlow(("vbsfBuildFullPath: %s\n", pszFullPath));
450 }
451
452 return rc;
453}
454
455static void vbsfFreeFullPath (char *pszFullPath)
456{
457 RTMemFree (pszFullPath);
458}
459
460
461static int vbsfOpenFile (SHFLHANDLE *phHandle, const char *pszPath, SHFLCREATEPARMS *pParms, bool fCreate)
462{
463 int rc = VINF_SUCCESS;
464
465 LogFlow(("vbsfOpenFile: pszPath = %s, pParms = %p, fCreate = %d\n",
466 pszPath, pParms, fCreate));
467
468 /** @todo r=bird: You should've requested a better RTFileOpen API! This code could certainly have
469 * benefitted from it. I've done the long overdue adjustment of RTFileOpen so it better reflect
470 * what a decent OS should be able to do. I've also added some OS specific flags (non-blocking,
471 * delete sharing), and I'm not picky about adding more if that required. (I'm only picky about
472 * how they are treated on platforms which doesn't support them.)
473 * Because of the restrictions in the old version of RTFileOpen this code contains dangerous race
474 * conditions. File creation is one example where you may easily kill a file just created by
475 * another user.
476 */
477
478 /* Open or create a file. */
479 unsigned fOpen;
480
481 Log(("SHFL create flags %08x\n", pParms->CreateFlags));
482
483 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
484 {
485 fOpen = RTFILE_O_OPEN;
486 }
487 else
488 fOpen = fCreate? RTFILE_O_CREATE_REPLACE: RTFILE_O_OPEN;
489
490 switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACCESS_MASK_RW))
491 {
492 default:
493 case SHFL_CF_ACCESS_NONE:
494 {
495 /** @todo treat this as read access, but theoretically this could be a no access requested. */
496 fOpen |= RTFILE_O_READ;
497 Log(("FLAG: SHFL_CF_ACCESS_NONE\n"));
498 break;
499 }
500
501 case SHFL_CF_ACCESS_READ:
502 {
503 fOpen |= RTFILE_O_READ;
504 Log(("FLAG: SHFL_CF_ACCESS_READ\n"));
505 break;
506 }
507
508 case SHFL_CF_ACCESS_WRITE:
509 {
510 fOpen |= RTFILE_O_WRITE;
511 Log(("FLAG: SHFL_CF_ACCESS_WRITE\n"));
512 break;
513 }
514
515 case SHFL_CF_ACCESS_READWRITE:
516 {
517 fOpen |= RTFILE_O_READWRITE;
518 Log(("FLAG: SHFL_CF_ACCESS_READWRITE\n"));
519 break;
520 }
521 }
522
523 /* Sharing mask */
524 switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACCESS_MASK_DENY))
525 {
526 default:
527 case SHFL_CF_ACCESS_DENYNONE:
528 fOpen |= RTFILE_O_DENY_NONE;
529 Log(("FLAG: SHFL_CF_ACCESS_DENYNONE\n"));
530 break;
531
532 case SHFL_CF_ACCESS_DENYREAD:
533 fOpen |= RTFILE_O_DENY_READ;
534 Log(("FLAG: SHFL_CF_ACCESS_DENYREAD\n"));
535 break;
536
537 case SHFL_CF_ACCESS_DENYWRITE:
538 fOpen |= RTFILE_O_DENY_WRITE;
539 Log(("FLAG: SHFL_CF_ACCESS_DENYWRITE\n"));
540 break;
541
542 case SHFL_CF_ACCESS_DENYALL:
543 fOpen |= RTFILE_O_DENY_ALL;
544 Log(("FLAG: SHFL_CF_ACCESS_DENYALL\n"));
545 break;
546 }
547
548 SHFLHANDLE handle;
549 SHFLFILEHANDLE *pHandle;
550
551 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
552 {
553 handle = vbsfAllocDirHandle();
554 pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_DIR);
555 }
556 else
557 {
558 handle = vbsfAllocFileHandle();
559 pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_FILE);
560 }
561
562 if (pHandle == NULL)
563 {
564 rc = VERR_NO_MEMORY;
565 }
566 else
567 {
568 /* Must obviously create the directory, before trying to open it. */
569 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
570 {
571 if (fCreate)
572 {
573 /** @todo render supplied attributes.
574 * bird: The guest should specify this. For windows guests RTFS_DOS_DIRECTORY should suffice. */
575 RTFMODE fMode = 0777;
576
577 rc = RTDirCreate(pszPath, fMode);
578 if (VBOX_FAILURE(rc))
579 {
580 vbsfFreeHandle (handle);
581 return rc;
582 }
583 }
584 /* Open the directory now */
585 if (VBOX_SUCCESS(rc))
586 {
587 rc = RTDirOpen (&pHandle->dir.Handle, pszPath);
588 if (VBOX_FAILURE (rc))
589 {
590 vbsfFreeHandle (handle);
591 *phHandle = SHFL_HANDLE_NIL;
592 return rc;
593 }
594 }
595 }
596 else
597 {
598 rc = RTFileOpen(&pHandle->file.Handle, pszPath, fOpen);
599 }
600
601 if (VBOX_SUCCESS (rc))
602 {
603 *phHandle = handle;
604 }
605 else
606 {
607 vbsfFreeHandle (handle);
608 }
609 }
610
611 LogFlow(("vbsfOpenFile: rc = %Vrc\n", rc));
612
613
614 return rc;
615}
616
617static int vbsfOpenExisting (const char *pszFullPath, SHFLCREATEPARMS *pParms)
618{
619 int rc = VINF_SUCCESS;
620
621 LogFlow(("vbsfOpenExisting: pszFullPath = %s, pParms = %p\n",
622 pszFullPath, pParms));
623
624 /* Open file. */
625 SHFLHANDLE handle;
626
627 rc = vbsfOpenFile (&handle, pszFullPath, pParms, false);
628 if (VBOX_SUCCESS (rc))
629 {
630 pParms->Handle = handle;
631 }
632
633 LogFlow(("vbsfOpenExisting: rc = %d\n", rc));
634
635 return rc;
636}
637
638
639static int vbsfOpenReplace (const char *pszPath, SHFLCREATEPARMS *pParms, bool bReplace, RTFSOBJINFO *pInfo)
640{
641 int rc = VINF_SUCCESS;
642
643 LogFlow(("vbsfOpenReplace: pszPath = %s, pParms = %p, bReplace = %d\n",
644 pszPath, pParms, bReplace));
645
646 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
647 {
648 /* Replace operation is not applicable to a directory. */
649 rc = VERR_INVALID_PARAMETER;
650 }
651 else
652 {
653 SHFLHANDLE handle = SHFL_HANDLE_NIL;
654 SHFLFILEHANDLE *pHandle;
655
656 rc = vbsfOpenFile (&handle, pszPath, pParms, true);
657 // We are loosing an information regarding the cause of failure here
658 // -- malc
659 pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_FILE);
660 if (!pHandle)
661 {
662 AssertFailed();
663 rc = VERR_INVALID_HANDLE;
664 }
665
666 if (VBOX_SUCCESS (rc))
667 {
668
669 /* Set new file attributes */
670
671 rc = RTFileSetSize(pHandle->file.Handle, pParms->Info.cbObject);
672 if (rc != VINF_SUCCESS)
673 {
674 AssertMsg(rc == VINF_SUCCESS, ("RTFileSetSize failed with %d\n", rc));
675 return rc;
676 }
677
678 if (bReplace)
679 {
680#if 0
681 /* @todo */
682 /* Set new attributes. */
683 RTFileSetTimes(pHandle->file.Handle,
684 &pParms->Info.AccessTime,
685 &pParms->Info.ModificationTime,
686 &pParms->Info.ChangeTime,
687 &pParms->Info.BirthTime
688 );
689
690 RTFileSetMode (pHandle->file.Handle, pParms->Info.Attr.fMode);
691#endif
692 }
693
694 pParms->Result = SHFL_FILE_REPLACED;
695 pParms->Handle = handle;
696 }
697 }
698
699 LogFlow(("vbsfOpenReplace: rc = %Vrc\n", rc));
700
701 return rc;
702}
703
704static int vbsfOpenCreate (const char *pszPath, SHFLCREATEPARMS *pParms)
705{
706 int rc = VINF_SUCCESS;
707
708 LogFlow(("vbsfOpenCreate: pszPath = %s, pParms = %p\n",
709 pszPath, pParms));
710
711 SHFLHANDLE handle = SHFL_HANDLE_NIL;
712 SHFLFILEHANDLE *pHandle;
713
714 rc = vbsfOpenFile (&handle, pszPath, pParms, true);
715 pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_FILE | SHFL_HF_TYPE_DIR);
716 if (!pHandle)
717 {
718 AssertFailed();
719 rc = VERR_INVALID_HANDLE;
720 }
721
722 if (VBOX_SUCCESS (rc))
723 {
724#if 0
725 if (!BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
726 {
727 /* @todo */
728 RTFileSetSize(pHandle->file.Handle, pParms->Info.cbObject);
729
730 RTFileSetTimes(pHandle->file.Handle,
731 &pParms->Info.AccessTime,
732 &pParms->Info.ModificationTime,
733 &pParms->Info.ChangeTime,
734 &pParms->Info.BirthTime
735 );
736
737 RTFileSetMode (pHandle->file.Handle, pParms->Info.Attr.fMode);
738 }
739#endif
740
741 pParms->Result = SHFL_FILE_CREATED;
742 pParms->Handle = handle;
743 }
744
745 LogFlow(("vbsfOpenCreate: rc = %Vrc\n", rc));
746
747 return rc;
748}
749
750
751static int vbsfCloseDir (SHFLFILEHANDLE *pHandle)
752{
753 int rc = VINF_SUCCESS;
754
755 LogFlow(("vbsfCloseDir: Handle = %08X Search Handle = %08X\n",
756 pHandle->dir.Handle, pHandle->dir.SearchHandle));
757
758 RTDirClose (pHandle->dir.Handle);
759
760 if (pHandle->dir.SearchHandle)
761 RTDirClose(pHandle->dir.SearchHandle);
762
763 if (pHandle->dir.pLastValidEntry)
764 {
765 RTMemFree(pHandle->dir.pLastValidEntry);
766 pHandle->dir.pLastValidEntry = NULL;
767 }
768
769 LogFlow(("vbsfCloseDir: rc = %d\n", rc));
770
771 return rc;
772}
773
774
775static int vbsfCloseFile (SHFLFILEHANDLE *pHandle)
776{
777 int rc = VINF_SUCCESS;
778
779 LogFlow(("vbsfCloseFile: Handle = %08X\n",
780 pHandle->file.Handle));
781
782 rc = RTFileClose (pHandle->file.Handle);
783
784 LogFlow(("vbsfCloseFile: rc = %d\n", rc));
785
786 return rc;
787}
788
789
790int vbsfCreate (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, SHFLCREATEPARMS *pParms)
791{
792 int rc = VINF_SUCCESS;
793
794 LogFlow(("vbsfCreate: pClient = %p, pPath = %p, cbPath = %d, pParms = %p\n",
795 pClient, pPath, cbPath, pParms));
796
797 /* Check the client access rights to the root. */
798 /** @todo */
799
800 /* Build a host full path for the given path
801 * and convert ucs2 to utf8 if necessary.
802 */
803 char *pszFullPath = NULL;
804 uint32_t cbFullPathRoot = 0;
805
806 rc = vbsfBuildFullPath (pClient, root, pPath, cbPath, &pszFullPath, &cbFullPathRoot);
807
808 /* @todo This mess needs to change. RTFileOpen supports all the open/creation methods */
809
810 if (VBOX_SUCCESS (rc))
811 {
812 /* Reset return values in case client forgot to do so. */
813 pParms->Result = SHFL_NO_RESULT;
814 pParms->Handle = SHFL_HANDLE_NIL;
815
816 /* Query path information. */
817 RTFSOBJINFO info;
818
819 /** r=bird: This is likely to create race conditions.
820 * What is a file now can be a directory when you open it. */
821 rc = RTPathQueryInfo (pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
822
823 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_LOOKUP))
824 {
825 /* Client just wants to know if the object exists. */
826 switch (rc)
827 {
828 case VINF_SUCCESS:
829 {
830 pParms->Info = info;
831 pParms->Result = SHFL_FILE_EXISTS;
832 break;
833 }
834
835 case VERR_FILE_NOT_FOUND:
836 {
837 pParms->Result = SHFL_FILE_NOT_FOUND;
838 rc = VINF_SUCCESS;
839 break;
840 }
841
842 case VERR_PATH_NOT_FOUND:
843 {
844 pParms->Result = SHFL_PATH_NOT_FOUND;
845 rc = VINF_SUCCESS;
846 break;
847 }
848 }
849 }
850 else if (rc == VINF_SUCCESS)
851 {
852 /* File object exists. */
853 pParms->Result = SHFL_FILE_EXISTS;
854
855 /* Mark it as a directory in case the caller didn't. */
856 if (BIT_FLAG(info.Attr.fMode, RTFS_DOS_DIRECTORY))
857 {
858 pParms->CreateFlags |= SHFL_CF_DIRECTORY;
859 }
860
861 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_OPEN_TARGET_DIRECTORY))
862 {
863 pParms->Info = info;
864 vbsfStripLastComponent (pszFullPath, cbFullPathRoot);
865 rc = vbsfOpenExisting (pszFullPath, pParms);
866 }
867 else
868 {
869 if ( BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY)
870 && !BIT_FLAG(info.Attr.fMode, RTFS_DOS_DIRECTORY))
871 {
872 /* Caller wanted a directory but the existing object is not a directory.
873 * Do not open the object then.
874 */
875 ; /* do nothing */
876 }
877 else
878 {
879 switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
880 {
881 case SHFL_CF_ACT_OPEN_IF_EXISTS:
882 {
883 pParms->Info = info;
884 rc = vbsfOpenExisting (pszFullPath, pParms);
885 break;
886 }
887
888 case SHFL_CF_ACT_FAIL_IF_EXISTS:
889 {
890 /* NIL handle value will tell client that object was not opened.
891 * Just copy information about the object.
892 */
893 pParms->Info = info;
894 break;
895 }
896
897 case SHFL_CF_ACT_REPLACE_IF_EXISTS:
898 {
899 rc = vbsfOpenReplace (pszFullPath, pParms, true, &info);
900 break;
901 }
902
903 case SHFL_CF_ACT_OVERWRITE_IF_EXISTS:
904 {
905 rc = vbsfOpenReplace (pszFullPath, pParms, false, &info);
906 pParms->Info = info;
907 break;
908 }
909
910 default:
911 {
912 rc = VERR_INVALID_PARAMETER;
913 }
914 }
915 }
916 }
917 }
918 else if (rc == VERR_FILE_NOT_FOUND)
919 {
920 rc = VINF_SUCCESS;
921
922 /* File object does not exist. */
923 pParms->Result = SHFL_FILE_NOT_FOUND;
924
925 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_OPEN_TARGET_DIRECTORY))
926 {
927 switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW))
928 {
929 case SHFL_CF_ACT_CREATE_IF_NEW:
930 {
931 rc = vbsfOpenCreate (pszFullPath, pParms);
932 break;
933 }
934
935 case SHFL_CF_ACT_FAIL_IF_NEW:
936 {
937 /* NIL handle value will tell client that object was not created. */
938 pParms->Result = SHFL_PATH_NOT_FOUND;
939 break;
940 }
941
942 default:
943 {
944 rc = VERR_INVALID_PARAMETER;
945 break;
946 }
947 }
948 }
949 else
950 {
951 switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW))
952 {
953 case SHFL_CF_ACT_CREATE_IF_NEW:
954 {
955 rc = vbsfOpenCreate (pszFullPath, pParms);
956 break;
957 }
958
959 case SHFL_CF_ACT_FAIL_IF_NEW:
960 {
961 /* NIL handle value will tell client that object was not created. */
962 break;
963 }
964
965 default:
966 {
967 rc = VERR_INVALID_PARAMETER;
968 }
969 }
970 }
971 }
972 else if (rc == VERR_PATH_NOT_FOUND)
973 {
974 rc = VINF_SUCCESS;
975
976 pParms->Result = SHFL_PATH_NOT_FOUND;
977 }
978
979 if (rc == VINF_SUCCESS && pParms->Handle != SHFL_HANDLE_NIL)
980 {
981 uint32_t bufsize = sizeof(pParms->Info);
982
983 rc = vbsfQueryFileInfo(pClient, root, pParms->Handle, SHFL_INFO_GET|SHFL_INFO_FILE, &bufsize, (uint8_t *)&pParms->Info);
984 AssertRC(rc);
985 }
986
987 /* free the path string */
988 vbsfFreeFullPath(pszFullPath);
989 }
990
991 Log(("vbsfCreate: handle = %RX64 rc = %Vrc\n", (uint64_t)pParms->Handle, rc));
992
993 return rc;
994}
995
996int vbsfClose (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
997{
998 int rc = VINF_SUCCESS;
999
1000 LogFlow(("vbsfClose: pClient = %p, Handle = %RX64\n",
1001 pClient, Handle));
1002
1003 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1004 Assert(pHandle);
1005 if (!pHandle)
1006 return VERR_INVALID_HANDLE;
1007
1008 switch (ShflHandleType (&pHandle->Header))
1009 {
1010 case SHFL_HF_TYPE_DIR:
1011 {
1012 rc = vbsfCloseDir (pHandle);
1013 break;
1014 }
1015 case SHFL_HF_TYPE_FILE:
1016 {
1017 rc = vbsfCloseFile (pHandle);
1018 break;
1019 }
1020 }
1021 vbsfFreeHandle(Handle);
1022
1023 Log(("vbsfClose: rc = %Rrc\n", rc));
1024
1025 return rc;
1026}
1027
1028int vbsfRead (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer)
1029{
1030 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1031 unsigned count = 0;
1032 int rc;
1033
1034 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1035 {
1036 AssertFailed();
1037 return VERR_INVALID_PARAMETER;
1038 }
1039
1040 Log(("vbsfRead %RX64 offset %RX64 bytes %x\n", Handle, offset, *pcbBuffer));
1041
1042 if (*pcbBuffer == 0)
1043 return VINF_SUCCESS; /* @todo correct? */
1044
1045
1046 rc = RTFileSeek(pHandle->file.Handle, offset, RTFILE_SEEK_BEGIN, NULL);
1047 if (rc != VINF_SUCCESS)
1048 {
1049 AssertRC(rc);
1050 return rc;
1051 }
1052
1053 rc = RTFileRead(pHandle->file.Handle, pBuffer, *pcbBuffer, &count);
1054 *pcbBuffer = count;
1055 Log(("RTFileRead returned %Vrc bytes read %x\n", rc, count));
1056 return rc;
1057}
1058
1059int vbsfWrite (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer)
1060{
1061 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1062 unsigned count = 0;
1063 int rc;
1064
1065 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1066 {
1067 AssertFailed();
1068 return VERR_INVALID_PARAMETER;
1069 }
1070
1071 Log(("vbsfWrite %RX64 offset %RX64 bytes %x\n", Handle, offset, *pcbBuffer));
1072
1073 if (*pcbBuffer == 0)
1074 return VINF_SUCCESS; /* @todo correct? */
1075
1076 rc = RTFileSeek(pHandle->file.Handle, offset, RTFILE_SEEK_BEGIN, NULL);
1077 if (rc != VINF_SUCCESS)
1078 {
1079 AssertRC(rc);
1080 return rc;
1081 }
1082
1083 rc = RTFileWrite(pHandle->file.Handle, pBuffer, *pcbBuffer, &count);
1084 *pcbBuffer = count;
1085 Log(("RTFileWrite returned %Vrc bytes written %x\n", rc, count));
1086 return rc;
1087}
1088
1089
1090int vbsfFlush(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
1091{
1092 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1093 int rc = VINF_SUCCESS;
1094
1095 if (pHandle == 0)
1096 {
1097 AssertFailed();
1098 return VERR_INVALID_HANDLE;
1099 }
1100
1101 Log(("vbsfFlush %RX64\n", Handle));
1102 rc = RTFileFlush(pHandle->file.Handle);
1103 AssertRC(rc);
1104 return rc;
1105}
1106
1107int vbsfDirList(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, SHFLSTRING *pPath, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer,
1108 uint32_t *pIndex, uint32_t *pcFiles)
1109{
1110 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR);
1111 PRTDIRENTRYEX pDirEntry = 0, pDirEntryOrg;
1112 uint32_t cbDirEntry, cbBufferOrg;
1113 int rc = VINF_SUCCESS;
1114 PSHFLDIRINFO pSFDEntry;
1115 PRTUCS2 puszString;
1116 PRTDIR DirHandle;
1117 bool fUtf8;
1118
1119 fUtf8 = BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8) != 0;
1120
1121 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1122 {
1123 AssertFailed();
1124 return VERR_INVALID_PARAMETER;
1125 }
1126 Assert(pIndex && *pIndex == 0);
1127 DirHandle = pHandle->dir.Handle;
1128
1129 cbDirEntry = 4096;
1130 pDirEntryOrg = pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
1131 if (pDirEntry == 0)
1132 {
1133 AssertFailed();
1134 return VERR_NO_MEMORY;
1135 }
1136
1137 cbBufferOrg = *pcbBuffer;
1138 *pcbBuffer = 0;
1139 pSFDEntry = (PSHFLDIRINFO)pBuffer;
1140
1141 *pIndex = 1; /* not yet complete */
1142 *pcFiles = 0;
1143
1144 if (pPath)
1145 {
1146 if (pHandle->dir.SearchHandle == 0)
1147 {
1148 /* Build a host full path for the given path
1149 * and convert ucs2 to utf8 if necessary.
1150 */
1151 char *pszFullPath = NULL;
1152
1153 Assert(pHandle->dir.pLastValidEntry == 0);
1154
1155 rc = vbsfBuildFullPath (pClient, root, pPath, pPath->u16Size, &pszFullPath, NULL, true);
1156
1157 if (VBOX_SUCCESS (rc))
1158 {
1159 rc = RTDirOpenFiltered (&pHandle->dir.SearchHandle, pszFullPath, RTDIRFILTER_WINNT);
1160
1161 /* free the path string */
1162 vbsfFreeFullPath(pszFullPath);
1163
1164 if (VBOX_FAILURE (rc))
1165 goto end;
1166 }
1167 else
1168 goto end;
1169 }
1170 Assert(pHandle->dir.SearchHandle);
1171 DirHandle = pHandle->dir.SearchHandle;
1172 }
1173
1174 while(cbBufferOrg)
1175 {
1176 uint32_t cbDirEntrySize = cbDirEntry;
1177 uint32_t cbNeeded;
1178
1179 /* Do we still have a valid last entry for the active search? If so, then return it here */
1180 if (pHandle->dir.pLastValidEntry)
1181 {
1182 pDirEntry = pHandle->dir.pLastValidEntry;
1183 }
1184 else
1185 {
1186 pDirEntry = pDirEntryOrg;
1187
1188 rc = RTDirReadEx(DirHandle, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING);
1189 if (rc == VERR_NO_MORE_FILES)
1190 {
1191 *pIndex = 0; /* listing completed */
1192 break;
1193 }
1194
1195 if (VINF_SUCCESS != rc && rc != VWRN_NO_DIRENT_INFO)
1196 {
1197 AssertFailed();
1198 if (rc != VERR_NO_TRANSLATION)
1199 break;
1200 else
1201 continue;
1202 }
1203 }
1204
1205 cbNeeded = RT_OFFSETOF (SHFLDIRINFO, name.String);
1206 if (fUtf8)
1207 cbNeeded += pDirEntry->cbName + 1;
1208 else
1209 /* Overestimating, but that's ok */
1210 cbNeeded += (pDirEntry->cbName + 1) * 2;
1211
1212 if (cbBufferOrg < cbNeeded)
1213 {
1214 /* No room, so save this directory entry, or else it's lost forever */
1215 pHandle->dir.pLastValidEntry = pDirEntry;
1216
1217 if (*pcFiles == 0)
1218 {
1219 AssertFailed();
1220 return VINF_BUFFER_OVERFLOW; /* Return directly and don't free pDirEntry */
1221 }
1222 return VINF_SUCCESS; /* Return directly and don't free pDirEntry */
1223 }
1224
1225 pSFDEntry->Info = pDirEntry->Info;
1226 pSFDEntry->cucShortName = 0;
1227
1228 if (fUtf8)
1229 {
1230 void *src, *dst;
1231
1232 src = &pDirEntry->szName[0];
1233 dst = &pSFDEntry->name.String.utf8[0];
1234
1235 memcpy (dst, src, pDirEntry->cbName + 1);
1236
1237 pSFDEntry->name.u16Size = pDirEntry->cbName + 1;
1238 pSFDEntry->name.u16Length = pDirEntry->cbName;
1239 }
1240 else
1241 {
1242 pSFDEntry->name.String.ucs2[0] = 0;
1243 puszString = pSFDEntry->name.String.ucs2;
1244 int rc2 = RTStrUtf8ToUcs2Ex(&puszString, pDirEntry->cbName+1, pDirEntry->szName);
1245 AssertRC(rc2);
1246
1247 pSFDEntry->name.u16Length = RTStrUcs2Len (pSFDEntry->name.String.ucs2) * 2;
1248 pSFDEntry->name.u16Size = pSFDEntry->name.u16Length + 2;
1249
1250 Log(("SHFL: File name size %d\n", pSFDEntry->name.u16Size));
1251 Log(("SHFL: File name %ls\n", &pSFDEntry->name.String.ucs2));
1252
1253 // adjust cbNeeded (it was overestimated before)
1254 cbNeeded = RT_OFFSETOF (SHFLDIRINFO, name.String) + pSFDEntry->name.u16Size;
1255 }
1256
1257 pSFDEntry = (PSHFLDIRINFO)((uintptr_t)pSFDEntry + cbNeeded);
1258 *pcbBuffer += cbNeeded;
1259 cbBufferOrg-= cbNeeded;
1260
1261 *pcFiles += 1;
1262
1263 /* Free the saved last entry, that we've just returned */
1264 if (pHandle->dir.pLastValidEntry)
1265 {
1266 RTMemFree(pHandle->dir.pLastValidEntry);
1267 pHandle->dir.pLastValidEntry = NULL;
1268 }
1269
1270 if (flags & SHFL_LIST_RETURN_ONE)
1271 break; /* we're done */
1272 }
1273 Assert(rc != VINF_SUCCESS || *pcbBuffer > 0);
1274
1275end:
1276 if (pDirEntry)
1277 RTMemFree(pDirEntry);
1278
1279 return rc;
1280}
1281
1282int vbsfQueryFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1283{
1284 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1285 int rc = VINF_SUCCESS;
1286 RTFSOBJINFO *pObjInfo = (RTFSOBJINFO *)pBuffer;
1287
1288
1289 if (pHandle == 0 || pcbBuffer == 0 || pObjInfo == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1290 {
1291 AssertFailed();
1292 return VERR_INVALID_PARAMETER;
1293 }
1294
1295 /* @todo other options */
1296 Assert(flags == (SHFL_INFO_GET|SHFL_INFO_FILE));
1297
1298 *pcbBuffer = 0;
1299
1300 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_DIR)
1301 {
1302 rc = RTDirQueryInfo(pHandle->dir.Handle, pObjInfo, RTFSOBJATTRADD_NOTHING);
1303 }
1304 else
1305 {
1306 rc = RTFileQueryInfo(pHandle->file.Handle, pObjInfo, RTFSOBJATTRADD_NOTHING);
1307 }
1308 if (rc == VINF_SUCCESS)
1309 {
1310 *pcbBuffer = sizeof(RTFSOBJINFO);
1311 }
1312 else
1313 AssertFailed();
1314
1315 return rc;
1316}
1317
1318int vbsfSetFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1319{
1320 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1321 int rc = VINF_SUCCESS;
1322 RTFSOBJINFO *pSFDEntry;
1323
1324 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1325 {
1326 AssertFailed();
1327 return VERR_INVALID_PARAMETER;
1328 }
1329
1330 *pcbBuffer = 0;
1331 pSFDEntry = (RTFSOBJINFO *)pBuffer;
1332
1333 Assert(flags == (SHFL_INFO_SET | SHFL_INFO_FILE));
1334
1335 /* Change only the time values that are not zero */
1336 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_DIR)
1337 {
1338 rc = RTDirSetTimes(pHandle->dir.Handle,
1339 (RTTimeSpecGetNano(&pSFDEntry->AccessTime)) ? &pSFDEntry->AccessTime : NULL,
1340 (RTTimeSpecGetNano(&pSFDEntry->ModificationTime)) ? &pSFDEntry->ModificationTime: NULL,
1341 (RTTimeSpecGetNano(&pSFDEntry->ChangeTime)) ? &pSFDEntry->ChangeTime: NULL,
1342 (RTTimeSpecGetNano(&pSFDEntry->BirthTime)) ? &pSFDEntry->BirthTime: NULL
1343 );
1344 }
1345 else
1346 {
1347 rc = RTFileSetTimes(pHandle->file.Handle,
1348 (RTTimeSpecGetNano(&pSFDEntry->AccessTime)) ? &pSFDEntry->AccessTime : NULL,
1349 (RTTimeSpecGetNano(&pSFDEntry->ModificationTime)) ? &pSFDEntry->ModificationTime: NULL,
1350 (RTTimeSpecGetNano(&pSFDEntry->ChangeTime)) ? &pSFDEntry->ChangeTime: NULL,
1351 (RTTimeSpecGetNano(&pSFDEntry->BirthTime)) ? &pSFDEntry->BirthTime: NULL
1352 );
1353 }
1354 if (rc != VINF_SUCCESS)
1355 {
1356 Log(("RTFileSetTimes failed with %Vrc\n", rc));
1357 Log(("AccessTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->AccessTime)));
1358 Log(("ModificationTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->ModificationTime)));
1359 Log(("ChangeTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->ChangeTime)));
1360 Log(("BirthTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->AccessTime)));
1361 /* temporary hack */
1362 rc = VINF_SUCCESS;
1363 }
1364
1365 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_FILE)
1366 {
1367 /* Change file attributes if necessary */
1368 if (pSFDEntry->Attr.fMode)
1369 {
1370 rc = RTFileSetMode((RTFILE)pHandle->file.Handle, pSFDEntry->Attr.fMode);
1371 if (rc != VINF_SUCCESS)
1372 {
1373 Log(("RTFileSetMode %x failed with %Vrc\n", pSFDEntry->Attr.fMode, rc));
1374 /* silent failure, because this tends to fail with e.g. windows guest & linux host */
1375 rc = VINF_SUCCESS;
1376 }
1377 }
1378 }
1379
1380 if (rc == VINF_SUCCESS)
1381 {
1382 uint32_t bufsize = sizeof(*pSFDEntry);
1383
1384 rc = vbsfQueryFileInfo(pClient, root, Handle, SHFL_INFO_GET|SHFL_INFO_FILE, &bufsize, (uint8_t *)pSFDEntry);
1385 if (rc == VINF_SUCCESS)
1386 {
1387 *pcbBuffer = sizeof(RTFSOBJINFO);
1388 }
1389 else
1390 AssertFailed();
1391 }
1392
1393 return rc;
1394}
1395
1396
1397int vbsfSetEndOfFile(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1398{
1399 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1400 int rc = VINF_SUCCESS;
1401 RTFSOBJINFO *pSFDEntry;
1402
1403 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1404 {
1405 AssertFailed();
1406 return VERR_INVALID_PARAMETER;
1407 }
1408
1409 *pcbBuffer = 0;
1410 pSFDEntry = (RTFSOBJINFO *)pBuffer;
1411
1412 if (flags & SHFL_INFO_SIZE)
1413 {
1414 rc = RTFileSetSize(pHandle->file.Handle, pSFDEntry->cbObject);
1415 if (rc != VINF_SUCCESS)
1416 AssertFailed();
1417 }
1418 else
1419 AssertFailed();
1420
1421 if (rc == VINF_SUCCESS)
1422 {
1423 RTFSOBJINFO fileinfo;
1424
1425 /* Query the new object info and return it */
1426 rc = RTFileQueryInfo(pHandle->file.Handle, &fileinfo, RTFSOBJATTRADD_NOTHING);
1427 if (rc == VINF_SUCCESS)
1428 {
1429 *pSFDEntry = fileinfo;
1430 *pcbBuffer = sizeof(RTFSOBJINFO);
1431 }
1432 else
1433 AssertFailed();
1434 }
1435
1436 return rc;
1437}
1438
1439int vbsfQueryVolumeInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1440{
1441 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE|SHFL_HF_TYPE_VOLUME);
1442 int rc = VINF_SUCCESS;
1443 SHFLVOLINFO *pSFDEntry;
1444 char *pszFullPath = NULL;
1445 SHFLSTRING dummy;
1446
1447 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(SHFLVOLINFO))
1448 {
1449 AssertFailed();
1450 return VERR_INVALID_PARAMETER;
1451 }
1452
1453 /* @todo other options */
1454 Assert(flags == (SHFL_INFO_GET|SHFL_INFO_VOLUME));
1455
1456 *pcbBuffer = 0;
1457 pSFDEntry = (PSHFLVOLINFO)pBuffer;
1458
1459 ShflStringInitBuffer(&dummy, sizeof(dummy));
1460 rc = vbsfBuildFullPath (pClient, root, &dummy, 0, &pszFullPath, NULL);
1461
1462 if (VBOX_SUCCESS (rc))
1463 {
1464 rc = RTFsQuerySizes(pszFullPath, &pSFDEntry->ullTotalAllocationBytes, &pSFDEntry->ullAvailableAllocationBytes, &pSFDEntry->ulBytesPerAllocationUnit, &pSFDEntry->ulBytesPerSector);
1465 if (rc != VINF_SUCCESS)
1466 goto exit;
1467
1468 rc = RTFsQuerySerial(pszFullPath, &pSFDEntry->ulSerial);
1469 if (rc != VINF_SUCCESS)
1470 goto exit;
1471
1472 rc = RTFsQueryProperties(pszFullPath, &pSFDEntry->fsProperties);
1473 if (rc != VINF_SUCCESS)
1474 goto exit;
1475
1476 *pcbBuffer = sizeof(SHFLVOLINFO);
1477 }
1478 else AssertFailed();
1479
1480exit:
1481 AssertMsg(rc == VINF_SUCCESS, ("failure: rc = %Vrc\n", rc));
1482 /* free the path string */
1483 vbsfFreeFullPath(pszFullPath);
1484 return rc;
1485}
1486
1487int vbsfQueryFSInfo(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|SHFL_HF_TYPE_VOLUME);
1490
1491 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1492 {
1493 AssertFailed();
1494 return VERR_INVALID_PARAMETER;
1495 }
1496
1497 if (flags & SHFL_INFO_FILE)
1498 return vbsfQueryFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1499
1500 if (flags & SHFL_INFO_VOLUME)
1501 return vbsfQueryVolumeInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1502
1503 AssertFailed();
1504 return VERR_INVALID_PARAMETER;
1505}
1506
1507int vbsfSetFSInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1508{
1509 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE|SHFL_HF_TYPE_VOLUME);
1510
1511 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1512 {
1513 AssertFailed();
1514 return VERR_INVALID_PARAMETER;
1515 }
1516 if (flags & SHFL_INFO_FILE)
1517 return vbsfSetFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1518
1519 if (flags & SHFL_INFO_SIZE)
1520 return vbsfSetEndOfFile(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1521
1522// if (flags & SHFL_INFO_VOLUME)
1523// return vbsfVolumeInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1524 AssertFailed();
1525 return VERR_INVALID_PARAMETER;
1526}
1527
1528int vbsfLock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
1529{
1530 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1531 uint32_t fRTLock = 0;
1532 int rc;
1533
1534 Assert((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL);
1535
1536 if (pHandle == 0)
1537 {
1538 AssertFailed();
1539 return VERR_INVALID_HANDLE;
1540 }
1541 if ( ((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL)
1542 || (flags & SHFL_LOCK_ENTIRE)
1543 )
1544 {
1545 AssertFailed();
1546 return VERR_INVALID_PARAMETER;
1547 }
1548
1549 /* Lock type */
1550 switch(flags & SHFL_LOCK_MODE_MASK)
1551 {
1552 case SHFL_LOCK_SHARED:
1553 fRTLock = RTFILE_LOCK_READ;
1554 break;
1555
1556 case SHFL_LOCK_EXCLUSIVE:
1557 fRTLock = RTFILE_LOCK_READ | RTFILE_LOCK_WRITE;
1558 break;
1559
1560 default:
1561 AssertFailed();
1562 return VERR_INVALID_PARAMETER;
1563 }
1564
1565 /* Lock wait type */
1566 if (flags & SHFL_LOCK_WAIT)
1567 fRTLock |= RTFILE_LOCK_WAIT;
1568 else
1569 fRTLock |= RTFILE_LOCK_IMMEDIATELY;
1570
1571 rc = RTFileLock(pHandle->file.Handle, fRTLock, offset, length);
1572 if (rc != VINF_SUCCESS)
1573 Log(("RTFileUnlock %RTfile %RX64 %RX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
1574
1575 return rc;
1576}
1577
1578int vbsfUnlock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
1579{
1580 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1581 int rc;
1582
1583 Assert((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL);
1584
1585 if (pHandle == 0)
1586 {
1587 return VERR_INVALID_HANDLE;
1588 }
1589 if ( ((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL)
1590 || (flags & SHFL_LOCK_ENTIRE)
1591 )
1592 {
1593 return VERR_INVALID_PARAMETER;
1594 }
1595
1596 rc = RTFileUnlock(pHandle->file.Handle, offset, length);
1597 if (rc != VINF_SUCCESS)
1598 Log(("RTFileUnlock %RTfile %RX64 %RTX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
1599
1600 return rc;
1601}
1602
1603
1604int vbsfRemove(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, uint32_t flags)
1605{
1606 int rc = VINF_SUCCESS;
1607
1608 /* Validate input */
1609 if ( flags & ~(SHFL_REMOVE_FILE|SHFL_REMOVE_DIR)
1610 || cbPath == 0
1611 || pPath == 0)
1612 {
1613 AssertFailed();
1614 return VERR_INVALID_PARAMETER;
1615 }
1616
1617 /* Build a host full path for the given path
1618 * and convert ucs2 to utf8 if necessary.
1619 */
1620 char *pszFullPath = NULL;
1621
1622 rc = vbsfBuildFullPath (pClient, root, pPath, cbPath, &pszFullPath, NULL);
1623
1624 if (VBOX_SUCCESS (rc))
1625 {
1626 if (flags & SHFL_REMOVE_FILE)
1627 rc = RTFileDelete(pszFullPath);
1628 else
1629 rc = RTDirRemove(pszFullPath);
1630
1631 Assert(rc == VINF_SUCCESS || rc == VERR_DIR_NOT_EMPTY);
1632 /* free the path string */
1633 vbsfFreeFullPath(pszFullPath);
1634 }
1635 return rc;
1636}
1637
1638
1639int vbsfRename(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pSrc, SHFLSTRING *pDest, uint32_t flags)
1640{
1641 int rc = VINF_SUCCESS;
1642
1643 /* Validate input */
1644 if ( flags & ~(SHFL_REMOVE_FILE|SHFL_REMOVE_DIR|SHFL_RENAME_REPLACE_IF_EXISTS)
1645 || pSrc == 0
1646 || pDest == 0)
1647 {
1648 AssertFailed();
1649 return VERR_INVALID_PARAMETER;
1650 }
1651
1652 /* Build a host full path for the given path
1653 * and convert ucs2 to utf8 if necessary.
1654 */
1655 char *pszFullPathSrc = NULL;
1656 char *pszFullPathDest = NULL;
1657
1658 rc = vbsfBuildFullPath (pClient, root, pSrc, pSrc->u16Size, &pszFullPathSrc, NULL);
1659 if (rc != VINF_SUCCESS)
1660 return rc;
1661
1662 rc = vbsfBuildFullPath (pClient, root, pDest, pDest->u16Size, &pszFullPathDest, NULL);
1663 if (VBOX_SUCCESS (rc))
1664 {
1665 Log(("Rename %s to %s\n", pszFullPathSrc, pszFullPathDest));
1666 if (flags & SHFL_RENAME_FILE)
1667 {
1668 rc = RTFileMove(pszFullPathSrc, pszFullPathDest, (flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTFILEMOVE_FLAGS_REPLACE : 0);
1669 }
1670 else
1671 {
1672 /* NT ignores the REPLACE flag and simply return and already exists error. */
1673 rc = RTDirRename(pszFullPathSrc, pszFullPathDest, (flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTPATHRENAME_FLAGS_REPLACE : 0);
1674 }
1675
1676 AssertRC(rc);
1677 /* free the path string */
1678 vbsfFreeFullPath(pszFullPathDest);
1679 }
1680 /* free the path string */
1681 vbsfFreeFullPath(pszFullPathSrc);
1682 return rc;
1683}
1684
1685/*
1686 * Clean up our mess by freeing all handles that are still valid.
1687 *
1688 */
1689int vbsfDisconnect(SHFLCLIENTDATA *pClient)
1690{
1691 for (int i=0;i<SHFLHANDLE_MAX;i++)
1692 {
1693 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(i, SHFL_HF_TYPE_MASK);
1694
1695 if (pHandle)
1696 {
1697 Log(("Open handle %08x\n", i));
1698 vbsfClose(pClient, SHFL_HANDLE_ROOT /* incorrect, but it's not important */, (SHFLHANDLE)i);
1699 }
1700 }
1701 return VINF_SUCCESS;
1702}
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