VirtualBox

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

Last change on this file since 39107 was 38843, checked in by vboxsync, 13 years ago

Additions/solaris/SharedFolders: use RT_FAILURE instead of negating RT_SUCCESS for failure checks.

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