VirtualBox

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

Last change on this file since 3944 was 3944, checked in by vboxsync, 17 years ago

Preparations for dealing with case sensitivity

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