VirtualBox

source: vbox/trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c@ 30570

Last change on this file since 30570 was 30527, checked in by vboxsync, 15 years ago

Additions/Solaris/SharedFolders: optionally honor fsync requests from the guest.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.5 KB
Line 
1/** @file
2 * VirtualBox File System for Solaris Guests, provider implementation.
3 * Portions contributed by: Ronald.
4 */
5
6/*
7 * Copyright (C) 2008 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17/*
18 * Provider interfaces for shared folder file system.
19 */
20
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <sys/mntent.h>
24#include <sys/param.h>
25#include <sys/modctl.h>
26#include <sys/mount.h>
27#include <sys/policy.h>
28#include <sys/atomic.h>
29#include <sys/sysmacros.h>
30#include <sys/ddi.h>
31#include <sys/sunddi.h>
32#include <sys/dirent.h>
33#include "vboxfs_prov.h"
34#ifdef u
35#undef u
36#endif
37#include "../../common/VBoxGuestLib/VBoxCalls.h"
38
39#define SFPROV_VERSION 1
40
41static VBSFCLIENT vbox_client;
42
43/*
44 * utility to create strings
45 */
46static SHFLSTRING *
47sfprov_string(char *path, int *sz)
48{
49 SHFLSTRING *str;
50 int len = strlen(path);
51
52 *sz = len + 1 + sizeof (*str) - sizeof (str->String);
53 str = kmem_zalloc(*sz, KM_SLEEP);
54 str->u16Size = len + 1;
55 str->u16Length = len;
56 strcpy(str->String.utf8, path);
57 return (str);
58}
59
60sfp_connection_t *
61sfprov_connect(int version)
62{
63 /*
64 * only one version for now, so must match
65 */
66 int rc = -1;
67 if (version != SFPROV_VERSION)
68 {
69 cmn_err(CE_WARN, "sfprov_connect: wrong version");
70 return NULL;
71 }
72 rc = vboxInit();
73 if (RT_SUCCESS(rc))
74 {
75 rc = vboxConnect(&vbox_client);
76 if (RT_SUCCESS(rc))
77 {
78 rc = vboxCallSetUtf8(&vbox_client);
79 if (RT_SUCCESS(rc))
80 {
81 return ((sfp_connection_t *)&vbox_client);
82 }
83 else
84 cmn_err(CE_WARN, "sfprov_connect: vboxCallSetUtf8() failed");
85
86 vboxDisconnect(&vbox_client);
87 }
88 else
89 cmn_err(CE_WARN, "sfprov_connect: vboxConnect() failed rc=%d", rc);
90 vboxUninit();
91 }
92 else
93 cmn_err(CE_WARN, "sfprov_connect: vboxInit() failed rc=%d", rc);
94}
95
96void
97sfprov_disconnect(sfp_connection_t *conn)
98{
99 if (conn != (sfp_connection_t *)&vbox_client)
100 cmn_err(CE_WARN, "sfprov_disconnect: bad argument");
101 vboxDisconnect(&vbox_client);
102 vboxUninit();
103}
104
105
106/*
107 * representation of an active mount point
108 */
109struct sfp_mount {
110 VBSFMAP map;
111};
112
113int
114sfprov_mount(sfp_connection_t *conn, char *path, sfp_mount_t **mnt)
115{
116 sfp_mount_t *m;
117 SHFLSTRING *str;
118 int size;
119 int rc;
120
121 m = kmem_zalloc(sizeof (*m), KM_SLEEP);
122 str = sfprov_string(path, &size);
123 rc = vboxCallMapFolder(&vbox_client, str, &m->map);
124 if (!RT_SUCCESS(rc)) {
125 cmn_err(CE_WARN, "sfprov_mount: vboxCallMapFolder() failed");
126 kmem_free(m, sizeof (*m));
127 *mnt = NULL;
128 rc = EINVAL;
129 } else {
130 *mnt = m;
131 rc = 0;
132 }
133 kmem_free(str, size);
134 return (rc);
135}
136
137int
138sfprov_unmount(sfp_mount_t *mnt)
139{
140 int rc;
141
142 rc = vboxCallUnmapFolder(&vbox_client, &mnt->map);
143 if (!RT_SUCCESS(rc)) {
144 cmn_err(CE_WARN, "sfprov_mount: vboxCallUnmapFolder() failed");
145 rc = EINVAL;
146 } else {
147 rc = 0;
148 }
149 kmem_free(mnt, sizeof (*mnt));
150 return (rc);
151}
152
153/*
154 * query information about a mounted file system
155 */
156int
157sfprov_get_blksize(sfp_mount_t *mnt, uint64_t *blksize)
158{
159 int rc;
160 SHFLVOLINFO info;
161 uint32_t bytes = sizeof(SHFLVOLINFO);
162
163 rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
164 (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
165 if (RT_FAILURE(rc))
166 return (EINVAL);
167 *blksize = info.ulBytesPerAllocationUnit;
168 return (0);
169}
170
171int
172sfprov_get_blksused(sfp_mount_t *mnt, uint64_t *blksused)
173{
174 int rc;
175 SHFLVOLINFO info;
176 uint32_t bytes = sizeof(SHFLVOLINFO);
177
178 rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
179 (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
180 if (RT_FAILURE(rc))
181 return (EINVAL);
182 *blksused = (info.ullTotalAllocationBytes -
183 info.ullAvailableAllocationBytes) / info.ulBytesPerAllocationUnit;
184 return (0);
185}
186
187int
188sfprov_get_blksavail(sfp_mount_t *mnt, uint64_t *blksavail)
189{
190 int rc;
191 SHFLVOLINFO info;
192 uint32_t bytes = sizeof(SHFLVOLINFO);
193
194 rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
195 (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
196 if (RT_FAILURE(rc))
197 return (EINVAL);
198 *blksavail =
199 info.ullAvailableAllocationBytes / info.ulBytesPerAllocationUnit;
200 return (0);
201}
202
203int
204sfprov_get_maxnamesize(sfp_mount_t *mnt, uint32_t *maxnamesize)
205{
206 int rc;
207 SHFLVOLINFO info;
208 uint32_t bytes = sizeof(SHFLVOLINFO);
209
210 rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
211 (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
212 if (RT_FAILURE(rc))
213 return (EINVAL);
214 *maxnamesize = info.fsProperties.cbMaxComponent;
215 return (0);
216}
217
218int
219sfprov_get_readonly(sfp_mount_t *mnt, uint32_t *readonly)
220{
221 int rc;
222 SHFLVOLINFO info;
223 uint32_t bytes = sizeof(SHFLVOLINFO);
224
225 rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
226 (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
227 if (RT_FAILURE(rc))
228 return (EINVAL);
229 *readonly = info.fsProperties.fReadOnly;
230 return (0);
231}
232
233/*
234 * File operations: open/close/read/write/etc.
235 *
236 * open/create can return any relevant errno, however ENOENT
237 * generally means that the host file didn't exist.
238 */
239struct sfp_file {
240 SHFLHANDLE handle;
241 VBSFMAP map; /* need this again for the close operation */
242};
243
244int
245sfprov_create(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
246{
247 int rc;
248 SHFLCREATEPARMS parms;
249 SHFLSTRING *str;
250 int size;
251 sfp_file_t *newfp;
252
253 str = sfprov_string(path, &size);
254 parms.Handle = 0;
255 parms.Info.cbObject = 0;
256 parms.CreateFlags = SHFL_CF_ACT_CREATE_IF_NEW |
257 SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACCESS_READWRITE;
258 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
259 kmem_free(str, size);
260
261 if (RT_FAILURE(rc))
262 return (EINVAL);
263 if (parms.Handle == SHFL_HANDLE_NIL) {
264 if (parms.Result == SHFL_FILE_EXISTS)
265 return (EEXIST);
266 return (ENOENT);
267 }
268 newfp = kmem_alloc(sizeof(sfp_file_t), KM_SLEEP);
269 newfp->handle = parms.Handle;
270 newfp->map = mnt->map;
271 *fp = newfp;
272 return (0);
273}
274
275int
276sfprov_open(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
277{
278 int rc;
279 SHFLCREATEPARMS parms;
280 SHFLSTRING *str;
281 int size;
282 sfp_file_t *newfp;
283
284 /*
285 * First we attempt to open it read/write. If that fails we
286 * try read only.
287 */
288 bzero(&parms, sizeof(parms));
289 str = sfprov_string(path, &size);
290 parms.Handle = SHFL_HANDLE_NIL;
291 parms.Info.cbObject = 0;
292 parms.CreateFlags = SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READWRITE;
293 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
294 if (RT_FAILURE(rc) && rc != VERR_ACCESS_DENIED) {
295 kmem_free(str, size);
296 return RTErrConvertToErrno(rc);
297 }
298 if (parms.Handle == SHFL_HANDLE_NIL) {
299 if (parms.Result == SHFL_PATH_NOT_FOUND ||
300 parms.Result == SHFL_FILE_NOT_FOUND) {
301 kmem_free(str, size);
302 return (ENOENT);
303 }
304 parms.CreateFlags =
305 SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ;
306 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
307 if (RT_FAILURE(rc)) {
308 kmem_free(str, size);
309 return RTErrConvertToErrno(rc);
310 }
311 if (parms.Handle == SHFL_HANDLE_NIL) {
312 kmem_free(str, size);
313 return (ENOENT);
314 }
315 }
316 newfp = kmem_alloc(sizeof(sfp_file_t), KM_SLEEP);
317 newfp->handle = parms.Handle;
318 newfp->map = mnt->map;
319 *fp = newfp;
320 return (0);
321}
322
323int
324sfprov_trunc(sfp_mount_t *mnt, char *path)
325{
326 int rc;
327 SHFLCREATEPARMS parms;
328 SHFLSTRING *str;
329 int size;
330
331 /*
332 * open it read/write.
333 */
334 str = sfprov_string(path, &size);
335 parms.Handle = 0;
336 parms.Info.cbObject = 0;
337 parms.CreateFlags = SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READWRITE |
338 SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
339 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
340
341 if (RT_FAILURE(rc)) {
342 kmem_free(str, size);
343 return (EINVAL);
344 }
345 (void)vboxCallClose(&vbox_client, &mnt->map, parms.Handle);
346 return (0);
347}
348
349int
350sfprov_close(sfp_file_t *fp)
351{
352 int rc;
353
354 rc = vboxCallClose(&vbox_client, &fp->map, fp->handle);
355 kmem_free(fp, sizeof(sfp_file_t));
356 return (0);
357}
358
359int
360sfprov_read(sfp_file_t *fp, char *buffer, uint64_t offset, uint32_t *numbytes)
361{
362 int rc;
363
364 rc = vboxCallRead(&vbox_client, &fp->map, fp->handle, offset,
365 numbytes, (uint8_t *)buffer, 0); /* what is that last arg? */
366 if (RT_FAILURE(rc))
367 return (EINVAL);
368 return (0);
369}
370
371int
372sfprov_write(sfp_file_t *fp, char *buffer, uint64_t offset, uint32_t *numbytes)
373{
374 int rc;
375
376 rc = vboxCallWrite(&vbox_client, &fp->map, fp->handle, offset,
377 numbytes, (uint8_t *)buffer, 0); /* what is that last arg? */
378 if (RT_FAILURE(rc))
379 return (EINVAL);
380 return (0);
381}
382
383int
384sfprov_fsync(sfp_file_t *fp)
385{
386 int rc;
387
388 rc = vboxCallFlush(&vbox_client, &fp->map, fp->handle);
389 if (RT_FAILURE(rc))
390 return (EIO);
391 return (0);
392}
393
394
395static int
396sfprov_getinfo(sfp_mount_t *mnt, char *path, RTFSOBJINFO *info)
397{
398 int rc;
399 SHFLCREATEPARMS parms;
400 SHFLSTRING *str;
401 int size;
402
403 str = sfprov_string(path, &size);
404 parms.Handle = 0;
405 parms.Info.cbObject = 0;
406 parms.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
407 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
408 kmem_free(str, size);
409
410 if (RT_FAILURE(rc))
411 return (EINVAL);
412 if (parms.Result != SHFL_FILE_EXISTS)
413 return (ENOENT);
414 *info = parms.Info;
415 return (0);
416}
417
418/*
419 * get information about a file (or directory)
420 */
421static void
422sfprov_mode_from_fmode(mode_t *mode, RTFMODE fMode)
423{
424 mode_t m = 0;
425
426 if (RTFS_IS_DIRECTORY(fMode))
427 m |= S_IFDIR;
428 else if (RTFS_IS_FILE(fMode))
429 m |= S_IFREG;
430 else if (RTFS_IS_FIFO(fMode))
431 m |= S_IFIFO;
432 else if (RTFS_IS_DEV_CHAR(fMode))
433 m |= S_IFCHR;
434 else if (RTFS_IS_DEV_BLOCK(fMode))
435 m |= S_IFBLK;
436 else if (RTFS_IS_SYMLINK(fMode))
437 m |= S_IFLNK;
438 else if (RTFS_IS_SOCKET(fMode))
439 m |= S_IFSOCK;
440
441 if (fMode & RTFS_UNIX_IRUSR)
442 m |= S_IRUSR;
443 if (fMode & RTFS_UNIX_IWUSR)
444 m |= S_IWUSR;
445 if (fMode & RTFS_UNIX_IXUSR)
446 m |= S_IXUSR;
447 if (fMode & RTFS_UNIX_IRGRP)
448 m |= S_IRGRP;
449 if (fMode & RTFS_UNIX_IWGRP)
450 m |= S_IWGRP;
451 if (fMode & RTFS_UNIX_IXGRP)
452 m |= S_IXGRP;
453 if (fMode & RTFS_UNIX_IROTH)
454 m |= S_IROTH;
455 if (fMode & RTFS_UNIX_IWOTH)
456 m |= S_IWOTH;
457 if (fMode & RTFS_UNIX_IXOTH)
458 m |= S_IXOTH;
459 if (fMode & RTFS_UNIX_ISUID)
460 m |= S_ISUID;
461 if (fMode & RTFS_UNIX_ISGID)
462 m |= S_ISGID;
463 if (fMode & RTFS_UNIX_ISTXT)
464 m |= S_ISVTX;
465 *mode = m;
466}
467
468/*
469 * get information about a file (or directory)
470 */
471int
472sfprov_get_mode(sfp_mount_t *mnt, char *path, mode_t *mode)
473{
474 int rc;
475 RTFSOBJINFO info;
476
477 rc = sfprov_getinfo(mnt, path, &info);
478 if (rc)
479 return (rc);
480 sfprov_mode_from_fmode(mode, info.Attr.fMode);
481 return (0);
482}
483
484int
485sfprov_get_size(sfp_mount_t *mnt, char *path, uint64_t *size)
486{
487 int rc;
488 RTFSOBJINFO info;
489
490 rc = sfprov_getinfo(mnt, path, &info);
491 if (rc)
492 return (rc);
493 *size = info.cbObject;
494 return (0);
495}
496
497static void
498sfprov_ftime_from_timespec(timestruc_t *time, RTTIMESPEC *ts)
499{
500 uint64_t nanosec = RTTimeSpecGetNano(ts);
501 time->tv_sec = nanosec / UINT64_C(1000000000);
502 time->tv_nsec = nanosec % UINT64_C(1000000000);
503}
504
505int
506sfprov_get_atime(sfp_mount_t *mnt, char *path, timestruc_t *time)
507{
508 int rc;
509 RTFSOBJINFO info;
510
511 rc = sfprov_getinfo(mnt, path, &info);
512 if (rc)
513 return (rc);
514 sfprov_ftime_from_timespec(time, &info.AccessTime);
515 return (0);
516}
517
518int
519sfprov_get_mtime(sfp_mount_t *mnt, char *path, timestruc_t *time)
520{
521 int rc;
522 RTFSOBJINFO info;
523
524 rc = sfprov_getinfo(mnt, path, &info);
525 if (rc)
526 return (rc);
527 sfprov_ftime_from_timespec(time, &info.ModificationTime);
528 return (0);
529}
530
531int
532sfprov_get_ctime(sfp_mount_t *mnt, char *path, timestruc_t *time)
533{
534 int rc;
535 RTFSOBJINFO info;
536
537 rc = sfprov_getinfo(mnt, path, &info);
538 if (rc)
539 return (rc);
540 sfprov_ftime_from_timespec(time, &info.ChangeTime);
541 return (0);
542}
543
544int
545sfprov_get_attr(
546 sfp_mount_t *mnt,
547 char *path,
548 mode_t *mode,
549 uint64_t *size,
550 timestruc_t *atime,
551 timestruc_t *mtime,
552 timestruc_t *ctime)
553{
554 int rc;
555 RTFSOBJINFO info;
556
557 rc = sfprov_getinfo(mnt, path, &info);
558 if (rc)
559 return (rc);
560
561 if (mode)
562 sfprov_mode_from_fmode(mode, info.Attr.fMode);
563 if (size != NULL)
564 *size = info.cbObject;
565 if (atime != NULL)
566 sfprov_ftime_from_timespec(atime, &info.AccessTime);
567 if (mtime != NULL)
568 sfprov_ftime_from_timespec(mtime, &info.ModificationTime);
569 if (ctime != NULL)
570 sfprov_ftime_from_timespec(ctime, &info.ChangeTime);
571
572 return (0);
573}
574
575static void
576sfprov_timespec_from_ftime(RTTIMESPEC *ts, timestruc_t time)
577{
578 uint64_t nanosec = UINT64_C(1000000000) * time.tv_sec + time.tv_nsec;
579 RTTimeSpecSetNano(ts, nanosec);
580}
581
582int
583sfprov_set_attr(
584 sfp_mount_t *mnt,
585 char *path,
586 uint_t mask,
587 mode_t mode,
588 timestruc_t atime,
589 timestruc_t mtime,
590 timestruc_t ctime)
591{
592 int rc, err;
593 SHFLCREATEPARMS parms;
594 SHFLSTRING *str;
595 RTFSOBJINFO info;
596 uint32_t bytes;
597 int str_size;
598
599 str = sfprov_string(path, &str_size);
600 parms.Handle = 0;
601 parms.Info.cbObject = 0;
602 parms.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS
603 | SHFL_CF_ACT_FAIL_IF_NEW
604 | SHFL_CF_ACCESS_ATTR_WRITE;
605
606 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
607
608 if (RT_FAILURE(rc)) {
609 cmn_err(CE_WARN, "sfprov_set_attr: vboxCallCreate(%s) failed rc=%d",
610 path, rc);
611 err = EINVAL;
612 goto fail2;
613 }
614 if (parms.Result != SHFL_FILE_EXISTS) {
615 err = ENOENT;
616 goto fail1;
617 }
618
619 RT_ZERO(info);
620 if (mask & AT_MODE) {
621#define mode_set(r) ((mode & (S_##r)) ? RTFS_UNIX_##r : 0)
622
623 info.Attr.fMode = mode_set (ISUID);
624 info.Attr.fMode |= mode_set (ISGID);
625 info.Attr.fMode |= (mode & S_ISVTX) ? RTFS_UNIX_ISTXT : 0;
626 info.Attr.fMode |= mode_set (IRUSR);
627 info.Attr.fMode |= mode_set (IWUSR);
628 info.Attr.fMode |= mode_set (IXUSR);
629 info.Attr.fMode |= mode_set (IRGRP);
630 info.Attr.fMode |= mode_set (IWGRP);
631 info.Attr.fMode |= mode_set (IXGRP);
632 info.Attr.fMode |= mode_set (IROTH);
633 info.Attr.fMode |= mode_set (IWOTH);
634 info.Attr.fMode |= mode_set (IXOTH);
635
636 if (S_ISDIR(mode))
637 info.Attr.fMode |= RTFS_TYPE_DIRECTORY;
638 else if (S_ISREG(mode))
639 info.Attr.fMode |= RTFS_TYPE_FILE;
640 else if (S_ISFIFO(mode))
641 info.Attr.fMode |= RTFS_TYPE_FIFO;
642 else if (S_ISCHR(mode))
643 info.Attr.fMode |= RTFS_TYPE_DEV_CHAR;
644 else if (S_ISBLK(mode))
645 info.Attr.fMode |= RTFS_TYPE_DEV_BLOCK;
646 else if (S_ISLNK(mode))
647 info.Attr.fMode |= RTFS_TYPE_SYMLINK;
648 else if (S_ISSOCK(mode))
649 info.Attr.fMode |= RTFS_TYPE_SOCKET;
650 else
651 info.Attr.fMode |= RTFS_TYPE_FILE;
652 }
653
654 if (mask & AT_ATIME)
655 sfprov_timespec_from_ftime(&info.AccessTime, atime);
656 if (mask & AT_MTIME)
657 sfprov_timespec_from_ftime(&info.ModificationTime, mtime);
658 if (mask & AT_CTIME)
659 sfprov_timespec_from_ftime(&info.ChangeTime, ctime);
660
661 bytes = sizeof(info);
662 rc = vboxCallFSInfo(&vbox_client, &mnt->map, parms.Handle,
663 (SHFL_INFO_SET | SHFL_INFO_FILE), &bytes, (SHFLDIRINFO *)&info);
664 if (RT_FAILURE(rc)) {
665 cmn_err(CE_WARN, "sfprov_set_attr: vboxCallFSInfo(%s, FILE) failed rc=%d",
666 path, rc);
667 err = RTErrConvertToErrno(rc);
668 goto fail1;
669 }
670
671 err = 0;
672
673fail1:
674 rc = vboxCallClose(&vbox_client, &mnt->map, parms.Handle);
675 if (RT_FAILURE(rc)) {
676 cmn_err(CE_WARN, "sfprov_set_attr: vboxCallClose(%s) failed rc=%d",
677 path, rc);
678 }
679fail2:
680 kmem_free(str, str_size);
681 return err;
682}
683
684int
685sfprov_set_size(sfp_mount_t *mnt, char *path, uint64_t size)
686{
687 int rc, err;
688 SHFLCREATEPARMS parms;
689 SHFLSTRING *str;
690 RTFSOBJINFO info;
691 uint32_t bytes;
692 int str_size;
693
694 str = sfprov_string(path, &str_size);
695 parms.Handle = 0;
696 parms.Info.cbObject = 0;
697 parms.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS
698 | SHFL_CF_ACT_FAIL_IF_NEW
699 | SHFL_CF_ACCESS_WRITE;
700
701 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
702
703 if (RT_FAILURE(rc)) {
704 cmn_err(CE_WARN, "sfprov_set_size: vboxCallCreate(%s) failed rc=%d",
705 path, rc);
706 err = EINVAL;
707 goto fail2;
708 }
709 if (parms.Result != SHFL_FILE_EXISTS) {
710 err = ENOENT;
711 goto fail1;
712 }
713
714 RT_ZERO(info);
715 info.cbObject = size;
716 bytes = sizeof(info);
717 rc = vboxCallFSInfo(&vbox_client, &mnt->map, parms.Handle,
718 (SHFL_INFO_SET | SHFL_INFO_SIZE), &bytes, (SHFLDIRINFO *)&info);
719 if (RT_FAILURE(rc)) {
720 cmn_err(CE_WARN, "sfprov_set_size: vboxCallFSInfo(%s, SIZE) failed rc=%d",
721 path, rc);
722 err = RTErrConvertToErrno(rc);
723 goto fail1;
724 }
725
726 err = 0;
727
728fail1:
729 rc = vboxCallClose(&vbox_client, &mnt->map, parms.Handle);
730 if (RT_FAILURE(rc)) {
731 cmn_err(CE_WARN, "sfprov_set_size: vboxCallClose(%s) failed rc=%d",
732 path, rc);
733 }
734fail2:
735 kmem_free(str, str_size);
736 return err;
737}
738
739/*
740 * Directory operations
741 */
742int
743sfprov_mkdir(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
744{
745 int rc;
746 SHFLCREATEPARMS parms;
747 SHFLSTRING *str;
748 int size;
749 sfp_file_t *newfp;
750
751 str = sfprov_string(path, &size);
752 parms.Handle = 0;
753 parms.Info.cbObject = 0;
754 parms.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW |
755 SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READ;
756 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
757 kmem_free(str, size);
758
759 if (RT_FAILURE(rc))
760 return (EINVAL);
761 if (parms.Handle == SHFL_HANDLE_NIL) {
762 if (parms.Result == SHFL_FILE_EXISTS)
763 return (EEXIST);
764 return (ENOENT);
765 }
766 newfp = kmem_alloc(sizeof(sfp_file_t), KM_SLEEP);
767 newfp->handle = parms.Handle;
768 newfp->map = mnt->map;
769 *fp = newfp;
770 return (0);
771}
772
773int
774sfprov_remove(sfp_mount_t *mnt, char *path)
775{
776 int rc;
777 SHFLSTRING *str;
778 int size;
779
780 str = sfprov_string(path, &size);
781 rc = vboxCallRemove(&vbox_client, &mnt->map, str, SHFL_REMOVE_FILE);
782 kmem_free(str, size);
783 if (RT_FAILURE(rc))
784 return (EINVAL);
785 return (0);
786}
787
788int
789sfprov_rmdir(sfp_mount_t *mnt, char *path)
790{
791 int rc;
792 SHFLSTRING *str;
793 int size;
794
795 str = sfprov_string(path, &size);
796 rc = vboxCallRemove(&vbox_client, &mnt->map, str, SHFL_REMOVE_DIR);
797 kmem_free(str, size);
798 if (RT_FAILURE(rc))
799 return (RTErrConvertToErrno(rc));
800 return (0);
801}
802
803int
804sfprov_rename(sfp_mount_t *mnt, char *from, char *to, uint_t is_dir)
805{
806 int rc;
807 SHFLSTRING *old, *new;
808 int old_size, new_size;
809
810 old = sfprov_string(from, &old_size);
811 new = sfprov_string(to, &new_size);
812 rc = vboxCallRename(&vbox_client, &mnt->map, old, new,
813 (is_dir ? SHFL_RENAME_DIR : SHFL_RENAME_FILE) |
814 SHFL_RENAME_REPLACE_IF_EXISTS);
815 kmem_free(old, old_size);
816 kmem_free(new, new_size);
817 if (RT_FAILURE(rc))
818 return (RTErrConvertToErrno(rc));
819 return (0);
820}
821
822
823/*
824 * Read all filenames in a directory.
825 *
826 * - success - all entries read and returned
827 * - ENOENT - Couldn't open the directory for reading
828 * - EINVAL - Internal error of some kind
829 *
830 * On successful return, *dirents points to a list of sffs_dirents_t;
831 * for each dirent, all fields except the d_ino will be set appropriately.
832 * The caller is responsible for freeing the dirents buffer.
833 */
834int
835sfprov_readdir(
836 sfp_mount_t *mnt,
837 char *path,
838 sffs_dirents_t **dirents,
839 sffs_stats_t **stats)
840{
841 int error;
842 char *cp;
843 int len;
844 SHFLSTRING *mask_str = NULL; /* must be path with "/*" appended */
845 int mask_size;
846 sfp_file_t *fp;
847 uint32_t infobuff_alloc = 16384;
848 SHFLDIRINFO *infobuff = NULL, *info;
849 uint32_t numbytes;
850 uint32_t nents;
851 uint32_t size;
852 uint32_t cnt;
853 sffs_dirents_t *cur_buf;
854 sffs_stats_t *cur_stats;
855 struct dirent64 *dirent;
856 sffs_stat_t *stat;
857 unsigned short reclen;
858
859 *dirents = NULL;
860 *stats = NULL;
861
862 error = sfprov_open(mnt, path, &fp);
863 if (error != 0)
864 return (ENOENT);
865
866 /*
867 * Allocate the first dirents and stats buffers.
868 */
869 *dirents = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP);
870 if (*dirents == NULL) {
871 error = (ENOSPC);
872 goto done;
873 }
874 cur_buf = *dirents;
875 cur_buf->sf_next = NULL;
876 cur_buf->sf_len = 0;
877
878 *stats = kmem_alloc(sizeof(**stats), KM_SLEEP);
879 if (*stats == NULL) {
880 error = (ENOSPC);
881 goto done;
882 }
883 cur_stats = *stats;
884 cur_stats->sf_next = NULL;
885 cur_stats->sf_num = 0;
886
887 /*
888 * Create mask that VBox expects. This needs to be the directory path,
889 * plus a "*" wildcard to get all files.
890 */
891 len = strlen(path) + 3;
892 cp = kmem_alloc(len, KM_SLEEP);
893 if (cp == NULL) {
894 error = (ENOSPC);
895 goto done;
896 }
897 strcpy(cp, path);
898 strcat(cp, "/*");
899 mask_str = sfprov_string(cp, &mask_size);
900 kmem_free(cp, len);
901
902 /*
903 * Now loop using vboxCallDirInfo
904 */
905 infobuff = kmem_alloc(infobuff_alloc, KM_SLEEP);
906 if (infobuff == NULL) {
907 error = (ENOSPC);
908 goto done;
909 }
910
911 cnt = 0;
912 for (;;) {
913 numbytes = infobuff_alloc;
914 error = vboxCallDirInfo(&vbox_client, &fp->map, fp->handle,
915 mask_str, 0, 0, &numbytes, infobuff, &nents);
916 switch (error) {
917
918 case VINF_SUCCESS:
919 /* fallthrough */
920 case VERR_NO_MORE_FILES:
921 break;
922
923 case VERR_NO_TRANSLATION:
924 /* XXX ??? */
925 break;
926
927 default:
928 error = RTErrConvertToErrno(error);
929 goto done;
930 }
931
932 /*
933 * Create the dirent_t's and save the stats for each name
934 */
935 for (info = infobuff; (char *) info < (char *) infobuff + numbytes; nents--) {
936 /* expand buffers if we need more space */
937 reclen = DIRENT64_RECLEN(strlen(info->name.String.utf8));
938 if (SFFS_DIRENTS_OFF + cur_buf->sf_len + reclen > SFFS_DIRENTS_SIZE) {
939 cur_buf->sf_next = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP);
940 if (cur_buf->sf_next == NULL) {
941 error = ENOSPC;
942 goto done;
943 }
944 cur_buf = cur_buf->sf_next;
945 cur_buf->sf_next = NULL;
946 cur_buf->sf_len = 0;
947 }
948
949 if (cur_stats->sf_num >= SFFS_STATS_LEN) {
950 cur_stats->sf_next = kmem_alloc(sizeof(**stats), KM_SLEEP);
951 if (cur_stats->sf_next == NULL) {
952 error = (ENOSPC);
953 goto done;
954 }
955 cur_stats = cur_stats->sf_next;
956 cur_stats->sf_next = NULL;
957 cur_stats->sf_num = 0;
958 }
959
960 /* create the dirent with the name, offset, and len */
961 dirent = (dirent64_t *)
962 (((char *) &cur_buf->sf_entries[0]) + cur_buf->sf_len);
963 strcpy(&dirent->d_name[0], info->name.String.utf8);
964 dirent->d_reclen = reclen;
965 dirent->d_off = cnt;
966
967 cur_buf->sf_len += reclen;
968 ++cnt;
969
970 /* save the stats */
971 stat = &cur_stats->sf_stats[cur_stats->sf_num];
972 ++cur_stats->sf_num;
973
974 sfprov_mode_from_fmode(&stat->sf_mode, info->Info.Attr.fMode);
975 stat->sf_size = info->Info.cbObject;
976 sfprov_ftime_from_timespec(&stat->sf_atime, &info->Info.AccessTime);
977 sfprov_ftime_from_timespec(&stat->sf_mtime, &info->Info.ModificationTime);
978 sfprov_ftime_from_timespec(&stat->sf_ctime, &info->Info.ChangeTime);
979
980 /* next info */
981 size = offsetof (SHFLDIRINFO, name.String) + info->name.u16Size;
982 info = (SHFLDIRINFO *) ((uintptr_t) info + size);
983 }
984 ASSERT(nents == 0);
985 ASSERT((char *) info == (char *) infobuff + numbytes);
986
987 if (error == VERR_NO_MORE_FILES)
988 break;
989 }
990 error = 0;
991
992done:
993 if (error != 0) {
994 while (*dirents) {
995 cur_buf = (*dirents)->sf_next;
996 kmem_free(*dirents, SFFS_DIRENTS_SIZE);
997 *dirents = cur_buf;
998 }
999 while (*stats) {
1000 cur_stats = (*stats)->sf_next;
1001 kmem_free(*stats, sizeof(**stats));
1002 *stats = cur_stats;
1003 }
1004 }
1005 if (infobuff != NULL)
1006 kmem_free(infobuff, infobuff_alloc);
1007 if (mask_str != NULL)
1008 kmem_free(mask_str, mask_size);
1009 sfprov_close(fp);
1010 return (error);
1011}
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