VirtualBox

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

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

Export HostServices

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