VirtualBox

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

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

Don't assert on expected errors.

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