VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.6 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
19#include "mappings.h"
20#include "vbsf.h"
21#include "shflhandle.h"
22
23#include <iprt/alloc.h>
24#include <iprt/assert.h>
25#include <iprt/fs.h>
26#include <iprt/dir.h>
27#include <iprt/file.h>
28#include <iprt/path.h>
29#include <iprt/string.h>
30#include <iprt/uni.h>
31
32#undef LogFlow
33#define LogFlow Log
34
35void vbsfStripLastComponent (char *pszFullPath, uint32_t cbFullPathRoot)
36{
37 RTUNICP cp;
38
39 /* Do not strip root. */
40 char *s = pszFullPath + cbFullPathRoot;
41 char *delimSecondLast = NULL;
42 char *delimLast = NULL;
43
44 LogFlowFunc(("%s -> %s\n", pszFullPath, s));
45
46 for (;;)
47 {
48 cp = RTStrGetCp(s);
49
50 if (cp == RTUNICP_INVALID || cp == 0)
51 {
52 break;
53 }
54
55 if (cp == RTPATH_DELIMITER)
56 {
57 if (delimLast != NULL)
58 {
59 delimSecondLast = delimLast;
60 }
61
62 delimLast = s;
63 }
64
65 s = RTStrNextCp (s);
66 }
67
68 if (cp == 0)
69 {
70 if (delimLast + 1 == s)
71 {
72 if (delimSecondLast)
73 {
74 *delimSecondLast = 0;
75 }
76 else if (delimLast)
77 {
78 *delimLast = 0;
79 }
80 }
81 else
82 {
83 if (delimLast)
84 {
85 *delimLast = 0;
86 }
87 }
88 }
89
90 LogFlowFunc(("%s, %s, %s\n", pszFullPath, delimLast, delimSecondLast));
91}
92
93static int vbsfCorrectCasing(char *pszFullPath, char *pszStartComponent)
94{
95 PRTDIRENTRYEX pDirEntry = NULL;
96 uint32_t cbDirEntry, cbComponent;
97 int rc = VERR_FILE_NOT_FOUND;
98 PRTDIR hSearch = 0;
99 char szWildCard[4];
100
101 Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent));
102
103 cbComponent = strlen(pszStartComponent);
104
105 cbDirEntry = 4096;
106 pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
107 if (pDirEntry == 0)
108 {
109 AssertFailed();
110 return VERR_NO_MEMORY;
111 }
112
113 /** @todo this is quite inefficient, especially for directories with many files */
114 Assert(pszFullPath < pszStartComponent-1);
115 Assert(*(pszStartComponent-1) == RTPATH_DELIMITER);
116 *(pszStartComponent-1) = 0;
117 strcpy(pDirEntry->szName, pszFullPath);
118 szWildCard[0] = RTPATH_DELIMITER;
119 szWildCard[1] = '*';
120 szWildCard[2] = 0;
121 strcat(pDirEntry->szName, szWildCard);
122
123 rc = RTDirOpenFiltered (&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT);
124 *(pszStartComponent-1) = RTPATH_DELIMITER;
125 if (VBOX_FAILURE(rc))
126 goto end;
127
128 for(;;)
129 {
130 uint32_t cbDirEntrySize = cbDirEntry;
131
132 rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING);
133 if (rc == VERR_NO_MORE_FILES)
134 break;
135
136 if (VINF_SUCCESS != rc && rc != VWRN_NO_DIRENT_INFO)
137 {
138 AssertFailed();
139 if (rc != VERR_NO_TRANSLATION)
140 break;
141 else
142 continue;
143 }
144
145 Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0]));
146 if ( pDirEntry->cbName == cbComponent
147 && !RTStrICmp(pszStartComponent, &pDirEntry->szName[0]))
148 {
149 Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent));
150 strcpy(pszStartComponent, &pDirEntry->szName[0]);
151 rc = VINF_SUCCESS;
152 break;
153 }
154 }
155
156end:
157 if (VBOX_FAILURE(rc))
158 Log(("vbsfCorrectCasing %s failed with %d\n", pszStartComponent, rc));
159
160 if (pDirEntry)
161 RTMemFree(pDirEntry);
162
163 if (hSearch)
164 RTDirClose(hSearch);
165 return rc;
166}
167
168static int vbsfBuildFullPath (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath,
169 uint32_t cbPath, char **ppszFullPath, uint32_t *pcbFullPathRoot, bool fWildCard = false)
170{
171 int rc = VINF_SUCCESS;
172
173 char *pszFullPath = NULL;
174
175 /* Query UCS2 root prefix for the path, cbRoot is the length in bytes including trailing (RTUCS2)0. */
176 uint32_t cbRoot = 0;
177 const RTUCS2 *pszRoot = vbsfMappingsQueryHostRoot (root, &cbRoot);
178
179 if (!pszRoot || cbRoot == 0)
180 {
181 return VERR_INVALID_PARAMETER;
182 }
183
184 if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
185 {
186 int rc;
187 char *utf8Root;
188
189 rc = RTUtf16ToUtf8 (pszRoot, &utf8Root);
190 if (VBOX_SUCCESS (rc))
191 {
192 size_t cbUtf8Root, cbUtf8FullPath;
193 char *utf8FullPath;
194
195 cbUtf8Root = strlen (utf8Root);
196 cbUtf8FullPath = cbUtf8Root + 1 + pPath->u16Length + 1;
197 utf8FullPath = (char *) RTMemAllocZ (cbUtf8FullPath);
198
199 if (!utf8FullPath)
200 {
201 rc = VERR_NO_MEMORY;
202 *ppszFullPath = NULL;
203 }
204 else
205 {
206 memcpy (utf8FullPath, utf8Root, cbUtf8Root);
207 memcpy (utf8FullPath + cbUtf8Root + 1,
208 &pPath->String.utf8[0],
209 pPath->u16Length);
210
211 utf8FullPath[cbUtf8Root] = '/';
212 utf8FullPath[cbUtf8FullPath - 1] = 0;
213 pszFullPath = utf8FullPath;
214
215 if (pcbFullPathRoot)
216 *pcbFullPathRoot = cbUtf8Root; /* Must index the path delimiter. */
217 }
218
219 RTStrFree (utf8Root);
220 }
221 else
222 {
223 Log (("vbsfBuildFullPath: RTUtf16ToUtf8 failed with %Vrc\n", rc));
224 }
225 }
226 else
227 {
228 /* Client sends us UCS2, so convert it to UTF8. */
229 Log(("Root %ls path %.*ls\n", pszRoot, pPath->u16Length/sizeof(pPath->String.ucs2[0]), pPath->String.ucs2));
230
231 /* Allocate buffer that will be able to contain
232 * the root prefix and the pPath converted to UTF8.
233 * Expect a 2 bytes UCS2 to be converted to 8 bytes UTF8
234 * in worst case.
235 */
236 uint32_t cbFullPath = (cbRoot/sizeof (RTUCS2) + ShflStringLength (pPath)) * 4;
237
238 pszFullPath = (char *)RTMemAllocZ (cbFullPath);
239
240 if (!pszFullPath)
241 {
242 rc = VERR_NO_MEMORY;
243 }
244 else
245 {
246 uint32_t cb = cbFullPath;
247
248 rc = RTStrUcs2ToUtf8Ex (&pszFullPath, cb, pszRoot);
249 if (VBOX_FAILURE(rc))
250 {
251 AssertFailed();
252 return rc;
253 }
254
255 char *dst = pszFullPath;
256
257 cbRoot = strlen(dst);
258 if (dst[cbRoot - 1] != RTPATH_DELIMITER)
259 {
260 dst[cbRoot] = RTPATH_DELIMITER;
261 cbRoot++;
262 }
263
264 if (pcbFullPathRoot)
265 *pcbFullPathRoot = cbRoot - 1; /* Must index the path delimiter. */
266
267 dst += cbRoot;
268 cb -= cbRoot;
269
270 if (pPath->u16Length)
271 {
272 /* Convert and copy components. */
273 RTUCS2 *src = &pPath->String.ucs2[0];
274
275 /* Correct path delimiters */
276 if (pClient->PathDelimiter != RTPATH_DELIMITER)
277 {
278 LogFlow(("Correct path delimiter in %ls\n", src));
279 while (*src)
280 {
281 if (*src == pClient->PathDelimiter)
282 *src = RTPATH_DELIMITER;
283 src++;
284 }
285 src = &pPath->String.ucs2[0];
286 LogFlow(("Corrected string %ls\n", src));
287 }
288 if (*src == RTPATH_DELIMITER)
289 src++; /* we already appended a delimiter to the first part */
290
291 rc = RTStrUcs2ToUtf8Ex (&dst, cb, src);
292 if (VBOX_FAILURE(rc))
293 {
294 AssertFailed();
295 return rc;
296 }
297
298 uint32_t l = strlen (dst);
299
300 cb -= l;
301 dst += l;
302
303 Assert(cb > 0);
304 }
305
306 /* Nul terminate the string */
307 *dst = 0;
308 }
309 }
310
311 if (VBOX_SUCCESS (rc))
312 {
313 /* When the host file system is case sensitive and the guest expects a case insensitive fs, then problems can occur */
314 if ( vbsfIsHostMappingCaseSensitive (root)
315 && !vbsfIsGuestMappingCaseSensitive(root))
316 {
317 RTFSOBJINFO info;
318 char *pszWildCardComponent = NULL;
319
320 if (fWildCard)
321 {
322 /* strip off the last path component, that contains the wildcard(s) */
323 uint32_t len = strlen(pszFullPath);
324 char *src = pszFullPath + len - 1;
325
326 while(src > pszFullPath)
327 {
328 if (*src == RTPATH_DELIMITER)
329 break;
330 src--;
331 }
332 if (*src == RTPATH_DELIMITER)
333 {
334 bool fHaveWildcards = false;
335 char *temp = src;
336
337 while(*temp)
338 {
339 char uc = *temp;
340 if (uc == '*' || uc == '?' || uc == '>' || uc == '<' || uc == '"')
341 {
342 fHaveWildcards = true;
343 break;
344 }
345 temp++;
346 }
347
348 if (fHaveWildcards)
349 {
350 pszWildCardComponent = src;
351 *pszWildCardComponent = 0;
352 }
353 }
354 }
355
356 /** @todo don't check when creating files or directories; waste of time */
357 rc = RTPathQueryInfo(pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
358 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
359 {
360 uint32_t len = strlen(pszFullPath);
361 char *src = pszFullPath + len - 1;
362
363 Log(("Handle case insenstive guest fs on top of host case sensitive fs for %s\n", pszFullPath));
364
365 /* Find partial path that's valid */
366 while(src > pszFullPath)
367 {
368 if (*src == RTPATH_DELIMITER)
369 {
370 *src = 0;
371 rc = RTPathQueryInfo (pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
372 *src = RTPATH_DELIMITER;
373 if (rc == VINF_SUCCESS)
374 {
375#ifdef DEBUG
376 *src = 0;
377 Log(("Found valid partial path %s\n", pszFullPath));
378 *src = RTPATH_DELIMITER;
379#endif
380 break;
381 }
382 }
383
384 src--;
385 }
386 Assert(*src == RTPATH_DELIMITER && VBOX_SUCCESS(rc));
387 if ( *src == RTPATH_DELIMITER
388 && VBOX_SUCCESS(rc))
389 {
390 src++;
391 for(;;)
392 {
393 char *end = src;
394 bool fEndOfString = true;
395
396 while(*end)
397 {
398 if (*end == RTPATH_DELIMITER)
399 break;
400 end++;
401 }
402
403 if (*end == RTPATH_DELIMITER)
404 {
405 fEndOfString = false;
406 *end = 0;
407 rc = RTPathQueryInfo(src, &info, RTFSOBJATTRADD_NOTHING);
408 Assert(rc == VINF_SUCCESS || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND);
409 }
410 else
411 if (end == src)
412 rc = VINF_SUCCESS; /* trailing delimiter */
413 else
414 rc = VERR_FILE_NOT_FOUND;
415
416 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
417 {
418 /* path component is invalid; try to correct the casing */
419 rc = vbsfCorrectCasing(pszFullPath, src);
420 if (VBOX_FAILURE(rc))
421 {
422 if (!fEndOfString)
423 *end = RTPATH_DELIMITER; /* restore the original full path */
424 break;
425 }
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 Log2(("RTPathQueryInfo returned %Vrc\n", rc));
823
824 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_LOOKUP))
825 {
826 Log2(("SHFL_CF_LOOKUP\n"));
827 /* Client just wants to know if the object exists. */
828 switch (rc)
829 {
830 case VINF_SUCCESS:
831 {
832 pParms->Info = info;
833 pParms->Result = SHFL_FILE_EXISTS;
834 break;
835 }
836
837 case VERR_FILE_NOT_FOUND:
838 {
839 pParms->Result = SHFL_FILE_NOT_FOUND;
840 rc = VINF_SUCCESS;
841 break;
842 }
843
844 case VERR_PATH_NOT_FOUND:
845 {
846 pParms->Result = SHFL_PATH_NOT_FOUND;
847 rc = VINF_SUCCESS;
848 break;
849 }
850 }
851 }
852 else if (rc == VINF_SUCCESS)
853 {
854 /* File object exists. */
855 pParms->Result = SHFL_FILE_EXISTS;
856
857 /* Mark it as a directory in case the caller didn't. */
858 if (BIT_FLAG(info.Attr.fMode, RTFS_DOS_DIRECTORY))
859 {
860 pParms->CreateFlags |= SHFL_CF_DIRECTORY;
861 }
862
863 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_OPEN_TARGET_DIRECTORY))
864 {
865 pParms->Info = info;
866 vbsfStripLastComponent (pszFullPath, cbFullPathRoot);
867 rc = vbsfOpenExisting (pszFullPath, pParms);
868 }
869 else
870 {
871 if ( BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY)
872 && !BIT_FLAG(info.Attr.fMode, RTFS_DOS_DIRECTORY))
873 {
874 /* Caller wanted a directory but the existing object is not a directory.
875 * Do not open the object then.
876 */
877 ; /* do nothing */
878 }
879 else
880 {
881 switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
882 {
883 case SHFL_CF_ACT_OPEN_IF_EXISTS:
884 {
885 pParms->Info = info;
886 rc = vbsfOpenExisting (pszFullPath, pParms);
887 break;
888 }
889
890 case SHFL_CF_ACT_FAIL_IF_EXISTS:
891 {
892 /* NIL handle value will tell client that object was not opened.
893 * Just copy information about the object.
894 */
895 pParms->Info = info;
896 break;
897 }
898
899 case SHFL_CF_ACT_REPLACE_IF_EXISTS:
900 {
901 rc = vbsfOpenReplace (pszFullPath, pParms, true, &info);
902 break;
903 }
904
905 case SHFL_CF_ACT_OVERWRITE_IF_EXISTS:
906 {
907 rc = vbsfOpenReplace (pszFullPath, pParms, false, &info);
908 pParms->Info = info;
909 break;
910 }
911
912 default:
913 {
914 rc = VERR_INVALID_PARAMETER;
915 }
916 }
917 }
918 }
919 }
920 else
921 if (rc == VERR_FILE_NOT_FOUND)
922 {
923 Log2(("pParms->CreateFlags = %x\n", pParms->CreateFlags));
924
925 rc = VINF_SUCCESS;
926
927 /* File object does not exist. */
928 pParms->Result = SHFL_FILE_NOT_FOUND;
929
930 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_OPEN_TARGET_DIRECTORY))
931 {
932 switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW))
933 {
934 case SHFL_CF_ACT_CREATE_IF_NEW:
935 {
936 rc = vbsfOpenCreate (pszFullPath, pParms);
937 break;
938 }
939
940 case SHFL_CF_ACT_FAIL_IF_NEW:
941 {
942 /* NIL handle value will tell client that object was not created. */
943 pParms->Result = SHFL_PATH_NOT_FOUND;
944 break;
945 }
946
947 default:
948 {
949 rc = VERR_INVALID_PARAMETER;
950 break;
951 }
952 }
953 }
954 else
955 {
956 switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW))
957 {
958 case SHFL_CF_ACT_CREATE_IF_NEW:
959 {
960 rc = vbsfOpenCreate (pszFullPath, pParms);
961 break;
962 }
963
964 case SHFL_CF_ACT_FAIL_IF_NEW:
965 {
966 /* NIL handle value will tell client that object was not created. */
967 break;
968 }
969
970 default:
971 {
972 rc = VERR_INVALID_PARAMETER;
973 }
974 }
975 }
976 }
977 else
978 if (rc == VERR_PATH_NOT_FOUND)
979 {
980 rc = VINF_SUCCESS;
981
982 pParms->Result = SHFL_PATH_NOT_FOUND;
983 }
984
985 if (rc == VINF_SUCCESS && pParms->Handle != SHFL_HANDLE_NIL)
986 {
987 uint32_t bufsize = sizeof(pParms->Info);
988
989 rc = vbsfQueryFileInfo(pClient, root, pParms->Handle, SHFL_INFO_GET|SHFL_INFO_FILE, &bufsize, (uint8_t *)&pParms->Info);
990 AssertRC(rc);
991 }
992
993 /* free the path string */
994 vbsfFreeFullPath(pszFullPath);
995 }
996
997 Log(("vbsfCreate: handle = %RX64 rc = %Vrc\n", (uint64_t)pParms->Handle, rc));
998
999 return rc;
1000}
1001
1002int vbsfClose (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
1003{
1004 int rc = VINF_SUCCESS;
1005
1006 LogFlow(("vbsfClose: pClient = %p, Handle = %RX64\n",
1007 pClient, Handle));
1008
1009 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1010 Assert(pHandle);
1011 if (!pHandle)
1012 return VERR_INVALID_HANDLE;
1013
1014 switch (ShflHandleType (&pHandle->Header))
1015 {
1016 case SHFL_HF_TYPE_DIR:
1017 {
1018 rc = vbsfCloseDir (pHandle);
1019 break;
1020 }
1021 case SHFL_HF_TYPE_FILE:
1022 {
1023 rc = vbsfCloseFile (pHandle);
1024 break;
1025 }
1026 }
1027 vbsfFreeHandle(Handle);
1028
1029 Log(("vbsfClose: rc = %Rrc\n", rc));
1030
1031 return rc;
1032}
1033
1034int vbsfRead (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer)
1035{
1036 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1037 unsigned count = 0;
1038 int rc;
1039
1040 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1041 {
1042 AssertFailed();
1043 return VERR_INVALID_PARAMETER;
1044 }
1045
1046 Log(("vbsfRead %RX64 offset %RX64 bytes %x\n", Handle, offset, *pcbBuffer));
1047
1048 if (*pcbBuffer == 0)
1049 return VINF_SUCCESS; /* @todo correct? */
1050
1051
1052 rc = RTFileSeek(pHandle->file.Handle, offset, RTFILE_SEEK_BEGIN, NULL);
1053 if (rc != VINF_SUCCESS)
1054 {
1055 AssertRC(rc);
1056 return rc;
1057 }
1058
1059 rc = RTFileRead(pHandle->file.Handle, pBuffer, *pcbBuffer, &count);
1060 *pcbBuffer = count;
1061 Log(("RTFileRead returned %Vrc bytes read %x\n", rc, count));
1062 return rc;
1063}
1064
1065int vbsfWrite (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer)
1066{
1067 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1068 unsigned count = 0;
1069 int rc;
1070
1071 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1072 {
1073 AssertFailed();
1074 return VERR_INVALID_PARAMETER;
1075 }
1076
1077 Log(("vbsfWrite %RX64 offset %RX64 bytes %x\n", Handle, offset, *pcbBuffer));
1078
1079 if (*pcbBuffer == 0)
1080 return VINF_SUCCESS; /* @todo correct? */
1081
1082 rc = RTFileSeek(pHandle->file.Handle, offset, RTFILE_SEEK_BEGIN, NULL);
1083 if (rc != VINF_SUCCESS)
1084 {
1085 AssertRC(rc);
1086 return rc;
1087 }
1088
1089 rc = RTFileWrite(pHandle->file.Handle, pBuffer, *pcbBuffer, &count);
1090 *pcbBuffer = count;
1091 Log(("RTFileWrite returned %Vrc bytes written %x\n", rc, count));
1092 return rc;
1093}
1094
1095
1096int vbsfFlush(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
1097{
1098 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1099 int rc = VINF_SUCCESS;
1100
1101 if (pHandle == 0)
1102 {
1103 AssertFailed();
1104 return VERR_INVALID_HANDLE;
1105 }
1106
1107 Log(("vbsfFlush %RX64\n", Handle));
1108 rc = RTFileFlush(pHandle->file.Handle);
1109 AssertRC(rc);
1110 return rc;
1111}
1112
1113int vbsfDirList(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, SHFLSTRING *pPath, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer,
1114 uint32_t *pIndex, uint32_t *pcFiles)
1115{
1116 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR);
1117 PRTDIRENTRYEX pDirEntry = 0, pDirEntryOrg;
1118 uint32_t cbDirEntry, cbBufferOrg;
1119 int rc = VINF_SUCCESS;
1120 PSHFLDIRINFO pSFDEntry;
1121 PRTUCS2 puszString;
1122 PRTDIR DirHandle;
1123 bool fUtf8;
1124
1125 fUtf8 = BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8) != 0;
1126
1127 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1128 {
1129 AssertFailed();
1130 return VERR_INVALID_PARAMETER;
1131 }
1132 Assert(pIndex && *pIndex == 0);
1133 DirHandle = pHandle->dir.Handle;
1134
1135 cbDirEntry = 4096;
1136 pDirEntryOrg = pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
1137 if (pDirEntry == 0)
1138 {
1139 AssertFailed();
1140 return VERR_NO_MEMORY;
1141 }
1142
1143 cbBufferOrg = *pcbBuffer;
1144 *pcbBuffer = 0;
1145 pSFDEntry = (PSHFLDIRINFO)pBuffer;
1146
1147 *pIndex = 1; /* not yet complete */
1148 *pcFiles = 0;
1149
1150 if (pPath)
1151 {
1152 if (pHandle->dir.SearchHandle == 0)
1153 {
1154 /* Build a host full path for the given path
1155 * and convert ucs2 to utf8 if necessary.
1156 */
1157 char *pszFullPath = NULL;
1158
1159 Assert(pHandle->dir.pLastValidEntry == 0);
1160
1161 rc = vbsfBuildFullPath (pClient, root, pPath, pPath->u16Size, &pszFullPath, NULL, true);
1162
1163 if (VBOX_SUCCESS (rc))
1164 {
1165 rc = RTDirOpenFiltered (&pHandle->dir.SearchHandle, pszFullPath, RTDIRFILTER_WINNT);
1166
1167 /* free the path string */
1168 vbsfFreeFullPath(pszFullPath);
1169
1170 if (VBOX_FAILURE (rc))
1171 goto end;
1172 }
1173 else
1174 goto end;
1175 }
1176 Assert(pHandle->dir.SearchHandle);
1177 DirHandle = pHandle->dir.SearchHandle;
1178 }
1179
1180 while(cbBufferOrg)
1181 {
1182 uint32_t cbDirEntrySize = cbDirEntry;
1183 uint32_t cbNeeded;
1184
1185 /* Do we still have a valid last entry for the active search? If so, then return it here */
1186 if (pHandle->dir.pLastValidEntry)
1187 {
1188 pDirEntry = pHandle->dir.pLastValidEntry;
1189 }
1190 else
1191 {
1192 pDirEntry = pDirEntryOrg;
1193
1194 rc = RTDirReadEx(DirHandle, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING);
1195 if (rc == VERR_NO_MORE_FILES)
1196 {
1197 *pIndex = 0; /* listing completed */
1198 break;
1199 }
1200
1201 if (VINF_SUCCESS != rc && rc != VWRN_NO_DIRENT_INFO)
1202 {
1203 AssertFailed();
1204 if (rc != VERR_NO_TRANSLATION)
1205 break;
1206 else
1207 continue;
1208 }
1209 }
1210
1211 cbNeeded = RT_OFFSETOF (SHFLDIRINFO, name.String);
1212 if (fUtf8)
1213 cbNeeded += pDirEntry->cbName + 1;
1214 else
1215 /* Overestimating, but that's ok */
1216 cbNeeded += (pDirEntry->cbName + 1) * 2;
1217
1218 if (cbBufferOrg < cbNeeded)
1219 {
1220 /* No room, so save this directory entry, or else it's lost forever */
1221 pHandle->dir.pLastValidEntry = pDirEntry;
1222
1223 if (*pcFiles == 0)
1224 {
1225 AssertFailed();
1226 return VINF_BUFFER_OVERFLOW; /* Return directly and don't free pDirEntry */
1227 }
1228 return VINF_SUCCESS; /* Return directly and don't free pDirEntry */
1229 }
1230
1231 pSFDEntry->Info = pDirEntry->Info;
1232 pSFDEntry->cucShortName = 0;
1233
1234 if (fUtf8)
1235 {
1236 void *src, *dst;
1237
1238 src = &pDirEntry->szName[0];
1239 dst = &pSFDEntry->name.String.utf8[0];
1240
1241 memcpy (dst, src, pDirEntry->cbName + 1);
1242
1243 pSFDEntry->name.u16Size = pDirEntry->cbName + 1;
1244 pSFDEntry->name.u16Length = pDirEntry->cbName;
1245 }
1246 else
1247 {
1248 pSFDEntry->name.String.ucs2[0] = 0;
1249 puszString = pSFDEntry->name.String.ucs2;
1250 int rc2 = RTStrUtf8ToUcs2Ex(&puszString, pDirEntry->cbName+1, pDirEntry->szName);
1251 AssertRC(rc2);
1252
1253 pSFDEntry->name.u16Length = RTStrUcs2Len (pSFDEntry->name.String.ucs2) * 2;
1254 pSFDEntry->name.u16Size = pSFDEntry->name.u16Length + 2;
1255
1256 Log(("SHFL: File name size %d\n", pSFDEntry->name.u16Size));
1257 Log(("SHFL: File name %ls\n", &pSFDEntry->name.String.ucs2));
1258
1259 // adjust cbNeeded (it was overestimated before)
1260 cbNeeded = RT_OFFSETOF (SHFLDIRINFO, name.String) + pSFDEntry->name.u16Size;
1261 }
1262
1263 pSFDEntry = (PSHFLDIRINFO)((uintptr_t)pSFDEntry + cbNeeded);
1264 *pcbBuffer += cbNeeded;
1265 cbBufferOrg-= cbNeeded;
1266
1267 *pcFiles += 1;
1268
1269 /* Free the saved last entry, that we've just returned */
1270 if (pHandle->dir.pLastValidEntry)
1271 {
1272 RTMemFree(pHandle->dir.pLastValidEntry);
1273 pHandle->dir.pLastValidEntry = NULL;
1274 }
1275
1276 if (flags & SHFL_LIST_RETURN_ONE)
1277 break; /* we're done */
1278 }
1279 Assert(rc != VINF_SUCCESS || *pcbBuffer > 0);
1280
1281end:
1282 if (pDirEntry)
1283 RTMemFree(pDirEntry);
1284
1285 return rc;
1286}
1287
1288int vbsfQueryFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1289{
1290 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1291 int rc = VINF_SUCCESS;
1292 RTFSOBJINFO *pObjInfo = (RTFSOBJINFO *)pBuffer;
1293
1294
1295 if (pHandle == 0 || pcbBuffer == 0 || pObjInfo == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1296 {
1297 AssertFailed();
1298 return VERR_INVALID_PARAMETER;
1299 }
1300
1301 /* @todo other options */
1302 Assert(flags == (SHFL_INFO_GET|SHFL_INFO_FILE));
1303
1304 *pcbBuffer = 0;
1305
1306 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_DIR)
1307 {
1308 rc = RTDirQueryInfo(pHandle->dir.Handle, pObjInfo, RTFSOBJATTRADD_NOTHING);
1309 }
1310 else
1311 {
1312 rc = RTFileQueryInfo(pHandle->file.Handle, pObjInfo, RTFSOBJATTRADD_NOTHING);
1313 }
1314 if (rc == VINF_SUCCESS)
1315 {
1316 *pcbBuffer = sizeof(RTFSOBJINFO);
1317 }
1318 else
1319 AssertFailed();
1320
1321 return rc;
1322}
1323
1324int vbsfSetFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1325{
1326 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE);
1327 int rc = VINF_SUCCESS;
1328 RTFSOBJINFO *pSFDEntry;
1329
1330 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1331 {
1332 AssertFailed();
1333 return VERR_INVALID_PARAMETER;
1334 }
1335
1336 *pcbBuffer = 0;
1337 pSFDEntry = (RTFSOBJINFO *)pBuffer;
1338
1339 Assert(flags == (SHFL_INFO_SET | SHFL_INFO_FILE));
1340
1341 /* Change only the time values that are not zero */
1342 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_DIR)
1343 {
1344 rc = RTDirSetTimes(pHandle->dir.Handle,
1345 (RTTimeSpecGetNano(&pSFDEntry->AccessTime)) ? &pSFDEntry->AccessTime : NULL,
1346 (RTTimeSpecGetNano(&pSFDEntry->ModificationTime)) ? &pSFDEntry->ModificationTime: NULL,
1347 (RTTimeSpecGetNano(&pSFDEntry->ChangeTime)) ? &pSFDEntry->ChangeTime: NULL,
1348 (RTTimeSpecGetNano(&pSFDEntry->BirthTime)) ? &pSFDEntry->BirthTime: NULL
1349 );
1350 }
1351 else
1352 {
1353 rc = RTFileSetTimes(pHandle->file.Handle,
1354 (RTTimeSpecGetNano(&pSFDEntry->AccessTime)) ? &pSFDEntry->AccessTime : NULL,
1355 (RTTimeSpecGetNano(&pSFDEntry->ModificationTime)) ? &pSFDEntry->ModificationTime: NULL,
1356 (RTTimeSpecGetNano(&pSFDEntry->ChangeTime)) ? &pSFDEntry->ChangeTime: NULL,
1357 (RTTimeSpecGetNano(&pSFDEntry->BirthTime)) ? &pSFDEntry->BirthTime: NULL
1358 );
1359 }
1360 if (rc != VINF_SUCCESS)
1361 {
1362 Log(("RTFileSetTimes failed with %Vrc\n", rc));
1363 Log(("AccessTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->AccessTime)));
1364 Log(("ModificationTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->ModificationTime)));
1365 Log(("ChangeTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->ChangeTime)));
1366 Log(("BirthTime %VX64\n", RTTimeSpecGetNano(&pSFDEntry->AccessTime)));
1367 /* temporary hack */
1368 rc = VINF_SUCCESS;
1369 }
1370
1371 if (pHandle->Header.u32Flags & SHFL_HF_TYPE_FILE)
1372 {
1373 /* Change file attributes if necessary */
1374 if (pSFDEntry->Attr.fMode)
1375 {
1376 rc = RTFileSetMode((RTFILE)pHandle->file.Handle, pSFDEntry->Attr.fMode);
1377 if (rc != VINF_SUCCESS)
1378 {
1379 Log(("RTFileSetMode %x failed with %Vrc\n", pSFDEntry->Attr.fMode, rc));
1380 /* silent failure, because this tends to fail with e.g. windows guest & linux host */
1381 rc = VINF_SUCCESS;
1382 }
1383 }
1384 }
1385
1386 if (rc == VINF_SUCCESS)
1387 {
1388 uint32_t bufsize = sizeof(*pSFDEntry);
1389
1390 rc = vbsfQueryFileInfo(pClient, root, Handle, SHFL_INFO_GET|SHFL_INFO_FILE, &bufsize, (uint8_t *)pSFDEntry);
1391 if (rc == VINF_SUCCESS)
1392 {
1393 *pcbBuffer = sizeof(RTFSOBJINFO);
1394 }
1395 else
1396 AssertFailed();
1397 }
1398
1399 return rc;
1400}
1401
1402
1403int vbsfSetEndOfFile(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1404{
1405 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1406 int rc = VINF_SUCCESS;
1407 RTFSOBJINFO *pSFDEntry;
1408
1409 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(RTFSOBJINFO))
1410 {
1411 AssertFailed();
1412 return VERR_INVALID_PARAMETER;
1413 }
1414
1415 *pcbBuffer = 0;
1416 pSFDEntry = (RTFSOBJINFO *)pBuffer;
1417
1418 if (flags & SHFL_INFO_SIZE)
1419 {
1420 rc = RTFileSetSize(pHandle->file.Handle, pSFDEntry->cbObject);
1421 if (rc != VINF_SUCCESS)
1422 AssertFailed();
1423 }
1424 else
1425 AssertFailed();
1426
1427 if (rc == VINF_SUCCESS)
1428 {
1429 RTFSOBJINFO fileinfo;
1430
1431 /* Query the new object info and return it */
1432 rc = RTFileQueryInfo(pHandle->file.Handle, &fileinfo, RTFSOBJATTRADD_NOTHING);
1433 if (rc == VINF_SUCCESS)
1434 {
1435 *pSFDEntry = fileinfo;
1436 *pcbBuffer = sizeof(RTFSOBJINFO);
1437 }
1438 else
1439 AssertFailed();
1440 }
1441
1442 return rc;
1443}
1444
1445int vbsfQueryVolumeInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1446{
1447 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE|SHFL_HF_TYPE_VOLUME);
1448 int rc = VINF_SUCCESS;
1449 SHFLVOLINFO *pSFDEntry;
1450 char *pszFullPath = NULL;
1451 SHFLSTRING dummy;
1452
1453 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(SHFLVOLINFO))
1454 {
1455 AssertFailed();
1456 return VERR_INVALID_PARAMETER;
1457 }
1458
1459 /* @todo other options */
1460 Assert(flags == (SHFL_INFO_GET|SHFL_INFO_VOLUME));
1461
1462 *pcbBuffer = 0;
1463 pSFDEntry = (PSHFLVOLINFO)pBuffer;
1464
1465 ShflStringInitBuffer(&dummy, sizeof(dummy));
1466 rc = vbsfBuildFullPath (pClient, root, &dummy, 0, &pszFullPath, NULL);
1467
1468 if (VBOX_SUCCESS (rc))
1469 {
1470 rc = RTFsQuerySizes(pszFullPath, &pSFDEntry->ullTotalAllocationBytes, &pSFDEntry->ullAvailableAllocationBytes, &pSFDEntry->ulBytesPerAllocationUnit, &pSFDEntry->ulBytesPerSector);
1471 if (rc != VINF_SUCCESS)
1472 goto exit;
1473
1474 rc = RTFsQuerySerial(pszFullPath, &pSFDEntry->ulSerial);
1475 if (rc != VINF_SUCCESS)
1476 goto exit;
1477
1478 rc = RTFsQueryProperties(pszFullPath, &pSFDEntry->fsProperties);
1479 if (rc != VINF_SUCCESS)
1480 goto exit;
1481
1482 *pcbBuffer = sizeof(SHFLVOLINFO);
1483 }
1484 else AssertFailed();
1485
1486exit:
1487 AssertMsg(rc == VINF_SUCCESS, ("failure: rc = %Vrc\n", rc));
1488 /* free the path string */
1489 vbsfFreeFullPath(pszFullPath);
1490 return rc;
1491}
1492
1493int vbsfQueryFSInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1494{
1495 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE|SHFL_HF_TYPE_VOLUME);
1496
1497 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1498 {
1499 AssertFailed();
1500 return VERR_INVALID_PARAMETER;
1501 }
1502
1503 if (flags & SHFL_INFO_FILE)
1504 return vbsfQueryFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1505
1506 if (flags & SHFL_INFO_VOLUME)
1507 return vbsfQueryVolumeInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1508
1509 AssertFailed();
1510 return VERR_INVALID_PARAMETER;
1511}
1512
1513int vbsfSetFSInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
1514{
1515 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE|SHFL_HF_TYPE_VOLUME);
1516
1517 if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
1518 {
1519 AssertFailed();
1520 return VERR_INVALID_PARAMETER;
1521 }
1522 if (flags & SHFL_INFO_FILE)
1523 return vbsfSetFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1524
1525 if (flags & SHFL_INFO_SIZE)
1526 return vbsfSetEndOfFile(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1527
1528// if (flags & SHFL_INFO_VOLUME)
1529// return vbsfVolumeInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
1530 AssertFailed();
1531 return VERR_INVALID_PARAMETER;
1532}
1533
1534int vbsfLock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
1535{
1536 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1537 uint32_t fRTLock = 0;
1538 int rc;
1539
1540 Assert((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL);
1541
1542 if (pHandle == 0)
1543 {
1544 AssertFailed();
1545 return VERR_INVALID_HANDLE;
1546 }
1547 if ( ((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL)
1548 || (flags & SHFL_LOCK_ENTIRE)
1549 )
1550 {
1551 AssertFailed();
1552 return VERR_INVALID_PARAMETER;
1553 }
1554
1555 /* Lock type */
1556 switch(flags & SHFL_LOCK_MODE_MASK)
1557 {
1558 case SHFL_LOCK_SHARED:
1559 fRTLock = RTFILE_LOCK_READ;
1560 break;
1561
1562 case SHFL_LOCK_EXCLUSIVE:
1563 fRTLock = RTFILE_LOCK_READ | RTFILE_LOCK_WRITE;
1564 break;
1565
1566 default:
1567 AssertFailed();
1568 return VERR_INVALID_PARAMETER;
1569 }
1570
1571 /* Lock wait type */
1572 if (flags & SHFL_LOCK_WAIT)
1573 fRTLock |= RTFILE_LOCK_WAIT;
1574 else
1575 fRTLock |= RTFILE_LOCK_IMMEDIATELY;
1576
1577 rc = RTFileLock(pHandle->file.Handle, fRTLock, offset, length);
1578 if (rc != VINF_SUCCESS)
1579 Log(("RTFileUnlock %RTfile %RX64 %RX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
1580
1581 return rc;
1582}
1583
1584int vbsfUnlock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
1585{
1586 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(Handle, SHFL_HF_TYPE_FILE);
1587 int rc;
1588
1589 Assert((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL);
1590
1591 if (pHandle == 0)
1592 {
1593 return VERR_INVALID_HANDLE;
1594 }
1595 if ( ((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL)
1596 || (flags & SHFL_LOCK_ENTIRE)
1597 )
1598 {
1599 return VERR_INVALID_PARAMETER;
1600 }
1601
1602 rc = RTFileUnlock(pHandle->file.Handle, offset, length);
1603 if (rc != VINF_SUCCESS)
1604 Log(("RTFileUnlock %RTfile %RX64 %RTX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
1605
1606 return rc;
1607}
1608
1609
1610int vbsfRemove(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, uint32_t flags)
1611{
1612 int rc = VINF_SUCCESS;
1613
1614 /* Validate input */
1615 if ( flags & ~(SHFL_REMOVE_FILE|SHFL_REMOVE_DIR)
1616 || cbPath == 0
1617 || pPath == 0)
1618 {
1619 AssertFailed();
1620 return VERR_INVALID_PARAMETER;
1621 }
1622
1623 /* Build a host full path for the given path
1624 * and convert ucs2 to utf8 if necessary.
1625 */
1626 char *pszFullPath = NULL;
1627
1628 rc = vbsfBuildFullPath (pClient, root, pPath, cbPath, &pszFullPath, NULL);
1629
1630 if (VBOX_SUCCESS (rc))
1631 {
1632 if (flags & SHFL_REMOVE_FILE)
1633 rc = RTFileDelete(pszFullPath);
1634 else
1635 rc = RTDirRemove(pszFullPath);
1636
1637 Assert(rc == VINF_SUCCESS || rc == VERR_DIR_NOT_EMPTY);
1638 /* free the path string */
1639 vbsfFreeFullPath(pszFullPath);
1640 }
1641 return rc;
1642}
1643
1644
1645int vbsfRename(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pSrc, SHFLSTRING *pDest, uint32_t flags)
1646{
1647 int rc = VINF_SUCCESS;
1648
1649 /* Validate input */
1650 if ( flags & ~(SHFL_REMOVE_FILE|SHFL_REMOVE_DIR|SHFL_RENAME_REPLACE_IF_EXISTS)
1651 || pSrc == 0
1652 || pDest == 0)
1653 {
1654 AssertFailed();
1655 return VERR_INVALID_PARAMETER;
1656 }
1657
1658 /* Build a host full path for the given path
1659 * and convert ucs2 to utf8 if necessary.
1660 */
1661 char *pszFullPathSrc = NULL;
1662 char *pszFullPathDest = NULL;
1663
1664 rc = vbsfBuildFullPath (pClient, root, pSrc, pSrc->u16Size, &pszFullPathSrc, NULL);
1665 if (rc != VINF_SUCCESS)
1666 return rc;
1667
1668 rc = vbsfBuildFullPath (pClient, root, pDest, pDest->u16Size, &pszFullPathDest, NULL);
1669 if (VBOX_SUCCESS (rc))
1670 {
1671 Log(("Rename %s to %s\n", pszFullPathSrc, pszFullPathDest));
1672 if (flags & SHFL_RENAME_FILE)
1673 {
1674 rc = RTFileMove(pszFullPathSrc, pszFullPathDest, (flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTFILEMOVE_FLAGS_REPLACE : 0);
1675 }
1676 else
1677 {
1678 /* NT ignores the REPLACE flag and simply return and already exists error. */
1679 rc = RTDirRename(pszFullPathSrc, pszFullPathDest, (flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTPATHRENAME_FLAGS_REPLACE : 0);
1680 }
1681
1682 AssertRC(rc);
1683 /* free the path string */
1684 vbsfFreeFullPath(pszFullPathDest);
1685 }
1686 /* free the path string */
1687 vbsfFreeFullPath(pszFullPathSrc);
1688 return rc;
1689}
1690
1691/*
1692 * Clean up our mess by freeing all handles that are still valid.
1693 *
1694 */
1695int vbsfDisconnect(SHFLCLIENTDATA *pClient)
1696{
1697 for (int i=0;i<SHFLHANDLE_MAX;i++)
1698 {
1699 SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(i, SHFL_HF_TYPE_MASK);
1700
1701 if (pHandle)
1702 {
1703 Log(("Open handle %08x\n", i));
1704 vbsfClose(pClient, SHFL_HANDLE_ROOT /* incorrect, but it's not important */, (SHFLHANDLE)i);
1705 }
1706 }
1707 return VINF_SUCCESS;
1708}
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