VirtualBox

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

Last change on this file since 39295 was 39295, checked in by vboxsync, 14 years ago

Additions/solaris/SharedFolders: code refactor, no functional changes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.2 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.215389.xyz. 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_fsinfo(sfp_mount_t *mnt, sffs_fsinfo_t *fsinfo)
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
186 fsinfo->blksize = info.ulBytesPerAllocationUnit;
187 fsinfo->blksused = (info.ullTotalAllocationBytes - info.ullAvailableAllocationBytes) / info.ulBytesPerAllocationUnit;
188 fsinfo->blksavail = info.ullAvailableAllocationBytes / info.ulBytesPerAllocationUnit;
189 fsinfo->maxnamesize = info.fsProperties.cbMaxComponent;
190 fsinfo->readonly = info.fsProperties.fReadOnly;
191 return (0);
192}
193
194/*
195 * File operations: open/close/read/write/etc.
196 *
197 * open/create can return any relevant errno, however ENOENT
198 * generally means that the host file didn't exist.
199 */
200struct sfp_file {
201 SHFLHANDLE handle;
202 VBSFMAP map; /* need this again for the close operation */
203};
204
205int
206sfprov_create(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
207{
208
209 int rc;
210 SHFLCREATEPARMS parms;
211 SHFLSTRING *str;
212 int size;
213 sfp_file_t *newfp;
214
215 str = sfprov_string(path, &size);
216 parms.Handle = 0;
217 parms.Info.cbObject = 0;
218 parms.CreateFlags = SHFL_CF_ACT_CREATE_IF_NEW |
219 SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACCESS_READWRITE;
220 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
221 kmem_free(str, size);
222
223 if (RT_FAILURE(rc))
224 {
225 if (rc != VERR_ACCESS_DENIED && rc != VERR_WRITE_PROTECT)
226 cmn_err(CE_WARN, "sfprov_create: vboxCallCreate failed! path=%s rc=%d\n", path, rc);
227 return (sfprov_vbox2errno(rc));
228 }
229 if (parms.Handle == SHFL_HANDLE_NIL) {
230 if (parms.Result == SHFL_FILE_EXISTS)
231 return (EEXIST);
232 return (ENOENT);
233 }
234 newfp = kmem_alloc(sizeof(sfp_file_t), KM_SLEEP);
235 newfp->handle = parms.Handle;
236 newfp->map = mnt->map;
237 *fp = newfp;
238 return (0);
239}
240
241int
242sfprov_open(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
243{
244 int rc;
245 SHFLCREATEPARMS parms;
246 SHFLSTRING *str;
247 int size;
248 sfp_file_t *newfp;
249
250 /*
251 * First we attempt to open it read/write. If that fails we
252 * try read only.
253 */
254 bzero(&parms, sizeof(parms));
255 str = sfprov_string(path, &size);
256 parms.Handle = SHFL_HANDLE_NIL;
257 parms.Info.cbObject = 0;
258 parms.CreateFlags = SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READWRITE;
259 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
260 if (RT_FAILURE(rc) && rc != VERR_ACCESS_DENIED) {
261 kmem_free(str, size);
262 return (sfprov_vbox2errno(rc));
263 }
264 if (parms.Handle == SHFL_HANDLE_NIL) {
265 if (parms.Result == SHFL_PATH_NOT_FOUND ||
266 parms.Result == SHFL_FILE_NOT_FOUND) {
267 kmem_free(str, size);
268 return (ENOENT);
269 }
270 parms.CreateFlags =
271 SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ;
272 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
273 if (RT_FAILURE(rc)) {
274 kmem_free(str, size);
275 return (sfprov_vbox2errno(rc));
276 }
277 if (parms.Handle == SHFL_HANDLE_NIL) {
278 kmem_free(str, size);
279 return (ENOENT);
280 }
281 }
282 else
283 kmem_free(str, size);
284 newfp = kmem_alloc(sizeof(sfp_file_t), KM_SLEEP);
285 newfp->handle = parms.Handle;
286 newfp->map = mnt->map;
287 *fp = newfp;
288 return (0);
289}
290
291int
292sfprov_trunc(sfp_mount_t *mnt, char *path)
293{
294 int rc;
295 SHFLCREATEPARMS parms;
296 SHFLSTRING *str;
297 int size;
298
299 /*
300 * open it read/write.
301 */
302 str = sfprov_string(path, &size);
303 parms.Handle = 0;
304 parms.Info.cbObject = 0;
305 parms.CreateFlags = SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READWRITE |
306 SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
307 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
308 kmem_free(str, size);
309
310 if (RT_FAILURE(rc)) {
311 return (EINVAL);
312 }
313 (void)vboxCallClose(&vbox_client, &mnt->map, parms.Handle);
314 return (0);
315}
316
317int
318sfprov_close(sfp_file_t *fp)
319{
320 int rc;
321
322 rc = vboxCallClose(&vbox_client, &fp->map, fp->handle);
323 kmem_free(fp, sizeof(sfp_file_t));
324 return (0);
325}
326
327int
328sfprov_read(sfp_file_t *fp, char *buffer, uint64_t offset, uint32_t *numbytes)
329{
330 int rc;
331
332 rc = vboxCallRead(&vbox_client, &fp->map, fp->handle, offset,
333 numbytes, (uint8_t *)buffer, 0); /* what is that last arg? */
334 if (RT_FAILURE(rc))
335 return (EINVAL);
336 return (0);
337}
338
339int
340sfprov_write(sfp_file_t *fp, char *buffer, uint64_t offset, uint32_t *numbytes)
341{
342 int rc;
343
344 rc = vboxCallWrite(&vbox_client, &fp->map, fp->handle, offset,
345 numbytes, (uint8_t *)buffer, 0); /* what is that last arg? */
346 if (RT_FAILURE(rc))
347 return (EINVAL);
348 return (0);
349}
350
351int
352sfprov_fsync(sfp_file_t *fp)
353{
354 int rc;
355
356 rc = vboxCallFlush(&vbox_client, &fp->map, fp->handle);
357 if (RT_FAILURE(rc))
358 return (EIO);
359 return (0);
360}
361
362
363static int
364sfprov_getinfo(sfp_mount_t *mnt, char *path, PSHFLFSOBJINFO info)
365{
366 int rc;
367 SHFLCREATEPARMS parms;
368 SHFLSTRING *str;
369 int size;
370
371 str = sfprov_string(path, &size);
372 parms.Handle = 0;
373 parms.Info.cbObject = 0;
374 parms.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
375 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
376 kmem_free(str, size);
377
378 if (RT_FAILURE(rc))
379 return (EINVAL);
380 if (parms.Result != SHFL_FILE_EXISTS)
381 return (ENOENT);
382 *info = parms.Info;
383 return (0);
384}
385
386/*
387 * file/directory information conversions.
388 */
389static void
390sfprov_fmode_from_mode(RTFMODE *fMode, mode_t mode)
391{
392 RTFMODE m = 0;
393
394#define mode_set(r) ((mode & (S_##r)) ? RTFS_UNIX_##r : 0)
395 m = mode_set (ISUID);
396 m |= mode_set (ISGID);
397 m |= (mode & S_ISVTX) ? RTFS_UNIX_ISTXT : 0;
398 m |= mode_set (IRUSR);
399 m |= mode_set (IWUSR);
400 m |= mode_set (IXUSR);
401 m |= mode_set (IRGRP);
402 m |= mode_set (IWGRP);
403 m |= mode_set (IXGRP);
404 m |= mode_set (IROTH);
405 m |= mode_set (IWOTH);
406 m |= mode_set (IXOTH);
407
408 if (S_ISDIR(mode))
409 m |= RTFS_TYPE_DIRECTORY;
410 else if (S_ISREG(mode))
411 m |= RTFS_TYPE_FILE;
412 else if (S_ISFIFO(mode))
413 m |= RTFS_TYPE_FIFO;
414 else if (S_ISCHR(mode))
415 m |= RTFS_TYPE_DEV_CHAR;
416 else if (S_ISBLK(mode))
417 m |= RTFS_TYPE_DEV_BLOCK;
418 else if (S_ISLNK(mode))
419 m |= RTFS_TYPE_SYMLINK;
420 else if (S_ISSOCK(mode))
421 m |= RTFS_TYPE_SOCKET;
422 else
423 m |= RTFS_TYPE_FILE;
424
425 *fMode = m;
426}
427
428static void
429sfprov_mode_from_fmode(mode_t *mode, RTFMODE fMode)
430{
431 mode_t m = 0;
432
433 if (RTFS_IS_DIRECTORY(fMode))
434 m |= S_IFDIR;
435 else if (RTFS_IS_FILE(fMode))
436 m |= S_IFREG;
437 else if (RTFS_IS_FIFO(fMode))
438 m |= S_IFIFO;
439 else if (RTFS_IS_DEV_CHAR(fMode))
440 m |= S_IFCHR;
441 else if (RTFS_IS_DEV_BLOCK(fMode))
442 m |= S_IFBLK;
443 else if (RTFS_IS_SYMLINK(fMode))
444 m |= S_IFLNK;
445 else if (RTFS_IS_SOCKET(fMode))
446 m |= S_IFSOCK;
447
448 if (fMode & RTFS_UNIX_IRUSR)
449 m |= S_IRUSR;
450 if (fMode & RTFS_UNIX_IWUSR)
451 m |= S_IWUSR;
452 if (fMode & RTFS_UNIX_IXUSR)
453 m |= S_IXUSR;
454 if (fMode & RTFS_UNIX_IRGRP)
455 m |= S_IRGRP;
456 if (fMode & RTFS_UNIX_IWGRP)
457 m |= S_IWGRP;
458 if (fMode & RTFS_UNIX_IXGRP)
459 m |= S_IXGRP;
460 if (fMode & RTFS_UNIX_IROTH)
461 m |= S_IROTH;
462 if (fMode & RTFS_UNIX_IWOTH)
463 m |= S_IWOTH;
464 if (fMode & RTFS_UNIX_IXOTH)
465 m |= S_IXOTH;
466 if (fMode & RTFS_UNIX_ISUID)
467 m |= S_ISUID;
468 if (fMode & RTFS_UNIX_ISGID)
469 m |= S_ISGID;
470 if (fMode & RTFS_UNIX_ISTXT)
471 m |= S_ISVTX;
472 *mode = m;
473}
474
475/*
476 * get information about a file (or directory)
477 */
478int
479sfprov_get_mode(sfp_mount_t *mnt, char *path, mode_t *mode)
480{
481 int rc;
482 SHFLFSOBJINFO info;
483
484 rc = sfprov_getinfo(mnt, path, &info);
485 if (rc)
486 return (rc);
487 sfprov_mode_from_fmode(mode, info.Attr.fMode);
488 return (0);
489}
490
491int
492sfprov_get_size(sfp_mount_t *mnt, char *path, uint64_t *size)
493{
494 int rc;
495 SHFLFSOBJINFO info;
496
497 rc = sfprov_getinfo(mnt, path, &info);
498 if (rc)
499 return (rc);
500 *size = info.cbObject;
501 return (0);
502}
503
504static void
505sfprov_ftime_from_timespec(timestruc_t *time, RTTIMESPEC *ts)
506{
507 uint64_t nanosec = RTTimeSpecGetNano(ts);
508 time->tv_sec = nanosec / UINT64_C(1000000000);
509 time->tv_nsec = nanosec % UINT64_C(1000000000);
510}
511
512static void
513sfprov_stat_from_info(sffs_stat_t *stat, SHFLFSOBJINFO *info)
514{
515 sfprov_mode_from_fmode(&stat->sf_mode, info->Attr.fMode);
516 stat->sf_size = info->cbObject;
517 stat->sf_alloc = info->cbAllocated;
518 sfprov_ftime_from_timespec(&stat->sf_atime, &info->AccessTime);
519 sfprov_ftime_from_timespec(&stat->sf_mtime, &info->ModificationTime);
520 sfprov_ftime_from_timespec(&stat->sf_ctime, &info->ChangeTime);
521}
522
523int
524sfprov_get_atime(sfp_mount_t *mnt, char *path, timestruc_t *time)
525{
526 int rc;
527 SHFLFSOBJINFO info;
528
529 rc = sfprov_getinfo(mnt, path, &info);
530 if (rc)
531 return (rc);
532 sfprov_ftime_from_timespec(time, &info.AccessTime);
533 return (0);
534}
535
536int
537sfprov_get_mtime(sfp_mount_t *mnt, char *path, timestruc_t *time)
538{
539 int rc;
540 SHFLFSOBJINFO info;
541
542 rc = sfprov_getinfo(mnt, path, &info);
543 if (rc)
544 return (rc);
545 sfprov_ftime_from_timespec(time, &info.ModificationTime);
546 return (0);
547}
548
549int
550sfprov_get_ctime(sfp_mount_t *mnt, char *path, timestruc_t *time)
551{
552 int rc;
553 SHFLFSOBJINFO info;
554
555 rc = sfprov_getinfo(mnt, path, &info);
556 if (rc)
557 return (rc);
558 sfprov_ftime_from_timespec(time, &info.ChangeTime);
559 return (0);
560}
561
562int
563sfprov_get_attr(sfp_mount_t *mnt, char *path, sffs_stat_t *attr)
564{
565 int rc;
566 SHFLFSOBJINFO info;
567
568 rc = sfprov_getinfo(mnt, path, &info);
569 if (rc)
570 return (rc);
571 sfprov_stat_from_info(attr, &info);
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 SHFLFSOBJINFO 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\n",
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 sfprov_fmode_from_mode(&info.Attr.fMode, mode);
622 if (mask & AT_ATIME)
623 sfprov_timespec_from_ftime(&info.AccessTime, atime);
624 if (mask & AT_MTIME)
625 sfprov_timespec_from_ftime(&info.ModificationTime, mtime);
626 if (mask & AT_CTIME)
627 sfprov_timespec_from_ftime(&info.ChangeTime, ctime);
628
629 bytes = sizeof(info);
630 rc = vboxCallFSInfo(&vbox_client, &mnt->map, parms.Handle,
631 (SHFL_INFO_SET | SHFL_INFO_FILE), &bytes, (SHFLDIRINFO *)&info);
632 if (RT_FAILURE(rc)) {
633 if (rc != VERR_ACCESS_DENIED && rc != VERR_WRITE_PROTECT)
634 {
635 cmn_err(CE_WARN, "sfprov_set_attr: vboxCallFSInfo(%s, FILE) failed rc=%d\n",
636 path, rc);
637 }
638 err = sfprov_vbox2errno(rc);
639 goto fail1;
640 }
641
642 err = 0;
643
644fail1:
645 rc = vboxCallClose(&vbox_client, &mnt->map, parms.Handle);
646 if (RT_FAILURE(rc)) {
647 cmn_err(CE_WARN, "sfprov_set_attr: vboxCallClose(%s) failed rc=%d\n",
648 path, rc);
649 }
650fail2:
651 kmem_free(str, str_size);
652 return err;
653}
654
655int
656sfprov_set_size(sfp_mount_t *mnt, char *path, uint64_t size)
657{
658 int rc, err;
659 SHFLCREATEPARMS parms;
660 SHFLSTRING *str;
661 SHFLFSOBJINFO info;
662 uint32_t bytes;
663 int str_size;
664
665 str = sfprov_string(path, &str_size);
666 parms.Handle = 0;
667 parms.Info.cbObject = 0;
668 parms.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS
669 | SHFL_CF_ACT_FAIL_IF_NEW
670 | SHFL_CF_ACCESS_WRITE;
671
672 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
673
674 if (RT_FAILURE(rc)) {
675 cmn_err(CE_WARN, "sfprov_set_size: vboxCallCreate(%s) failed rc=%d\n",
676 path, rc);
677 err = EINVAL;
678 goto fail2;
679 }
680 if (parms.Result != SHFL_FILE_EXISTS) {
681 err = ENOENT;
682 goto fail1;
683 }
684
685 RT_ZERO(info);
686 info.cbObject = size;
687 bytes = sizeof(info);
688 rc = vboxCallFSInfo(&vbox_client, &mnt->map, parms.Handle,
689 (SHFL_INFO_SET | SHFL_INFO_SIZE), &bytes, (SHFLDIRINFO *)&info);
690 if (RT_FAILURE(rc)) {
691 cmn_err(CE_WARN, "sfprov_set_size: vboxCallFSInfo(%s, SIZE) failed rc=%d\n",
692 path, rc);
693 err = sfprov_vbox2errno(rc);
694 goto fail1;
695 }
696
697 err = 0;
698
699fail1:
700 rc = vboxCallClose(&vbox_client, &mnt->map, parms.Handle);
701 if (RT_FAILURE(rc)) {
702 cmn_err(CE_WARN, "sfprov_set_size: vboxCallClose(%s) failed rc=%d\n",
703 path, rc);
704 }
705fail2:
706 kmem_free(str, str_size);
707 return err;
708}
709
710/*
711 * Directory operations
712 */
713int
714sfprov_mkdir(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
715{
716 int rc;
717 SHFLCREATEPARMS parms;
718 SHFLSTRING *str;
719 int size;
720 sfp_file_t *newfp;
721
722 str = sfprov_string(path, &size);
723 parms.Handle = 0;
724 parms.Info.cbObject = 0;
725 parms.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW |
726 SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READ;
727 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
728 kmem_free(str, size);
729
730 if (RT_FAILURE(rc))
731 return (sfprov_vbox2errno(rc));
732 if (parms.Handle == SHFL_HANDLE_NIL) {
733 if (parms.Result == SHFL_FILE_EXISTS)
734 return (EEXIST);
735 return (ENOENT);
736 }
737 newfp = kmem_alloc(sizeof(sfp_file_t), KM_SLEEP);
738 newfp->handle = parms.Handle;
739 newfp->map = mnt->map;
740 *fp = newfp;
741 return (0);
742}
743
744int
745sfprov_set_show_symlinks(void)
746{
747 int rc;
748
749 rc = vboxCallSetSymlinks(&vbox_client);
750 if (RT_FAILURE(rc))
751 return (sfprov_vbox2errno(rc));
752
753 return (0);
754}
755
756int
757sfprov_remove(sfp_mount_t *mnt, char *path, uint_t is_link)
758{
759 int rc;
760 SHFLSTRING *str;
761 int size;
762
763 str = sfprov_string(path, &size);
764 rc = vboxCallRemove(&vbox_client, &mnt->map, str,
765 SHFL_REMOVE_FILE | (is_link ? SHFL_REMOVE_SYMLINK : 0));
766 kmem_free(str, size);
767 if (RT_FAILURE(rc))
768 return (sfprov_vbox2errno(rc));
769 return (0);
770}
771
772int
773sfprov_readlink(
774 sfp_mount_t *mnt,
775 char *path,
776 char *target,
777 size_t tgt_size)
778{
779 int rc;
780 SHFLSTRING *str;
781 int size;
782
783 str = sfprov_string(path, &size);
784
785 rc = vboxReadLink(&vbox_client, &mnt->map, str, (uint32_t) tgt_size,
786 target);
787 if (RT_FAILURE(rc))
788 rc = sfprov_vbox2errno(rc);
789
790 kmem_free(str, size);
791 return (rc);
792}
793
794int
795sfprov_symlink(
796 sfp_mount_t *mnt,
797 char *linkname,
798 char *target,
799 sffs_stat_t *stat)
800{
801 int rc;
802 SHFLSTRING *lnk, *tgt;
803 int lnk_size, tgt_size;
804 SHFLFSOBJINFO info;
805
806 lnk = sfprov_string(linkname, &lnk_size);
807 tgt = sfprov_string(target, &tgt_size);
808
809 rc = vboxCallSymlink(&vbox_client, &mnt->map, lnk, tgt, &info);
810 if (RT_FAILURE(rc)) {
811 rc = sfprov_vbox2errno(rc);
812 goto done;
813 }
814
815 if (stat != NULL)
816 sfprov_stat_from_info(stat, &info);
817
818done:
819 kmem_free(lnk, lnk_size);
820 kmem_free(tgt, tgt_size);
821
822 return (rc);
823}
824
825int
826sfprov_rmdir(sfp_mount_t *mnt, char *path)
827{
828 int rc;
829 SHFLSTRING *str;
830 int size;
831
832 str = sfprov_string(path, &size);
833 rc = vboxCallRemove(&vbox_client, &mnt->map, str, SHFL_REMOVE_DIR);
834 kmem_free(str, size);
835 if (RT_FAILURE(rc))
836 return (sfprov_vbox2errno(rc));
837 return (0);
838}
839
840int
841sfprov_rename(sfp_mount_t *mnt, char *from, char *to, uint_t is_dir)
842{
843 int rc;
844 SHFLSTRING *old, *new;
845 int old_size, new_size;
846
847 old = sfprov_string(from, &old_size);
848 new = sfprov_string(to, &new_size);
849 rc = vboxCallRename(&vbox_client, &mnt->map, old, new,
850 (is_dir ? SHFL_RENAME_DIR : SHFL_RENAME_FILE) |
851 SHFL_RENAME_REPLACE_IF_EXISTS);
852 kmem_free(old, old_size);
853 kmem_free(new, new_size);
854 if (RT_FAILURE(rc))
855 return (sfprov_vbox2errno(rc));
856 return (0);
857}
858
859
860/*
861 * Read all filenames in a directory.
862 *
863 * - success - all entries read and returned
864 * - ENOENT - Couldn't open the directory for reading
865 * - EINVAL - Internal error of some kind
866 *
867 * On successful return, *dirents points to a list of sffs_dirents_t;
868 * for each dirent, all fields except the d_ino will be set appropriately.
869 * The caller is responsible for freeing the dirents buffer.
870 */
871int
872sfprov_readdir(
873 sfp_mount_t *mnt,
874 char *path,
875 sffs_dirents_t **dirents)
876{
877 int error;
878 char *cp;
879 int len;
880 SHFLSTRING *mask_str = NULL; /* must be path with "/*" appended */
881 int mask_size;
882 sfp_file_t *fp;
883 uint32_t infobuff_alloc = 16384;
884 SHFLDIRINFO *infobuff = NULL, *info;
885 uint32_t numbytes;
886 uint32_t nents;
887 uint32_t size;
888 off_t offset;
889 sffs_dirents_t *cur_buf;
890 struct sffs_dirent *dirent;
891 unsigned short reclen;
892 unsigned short entlen;
893
894 *dirents = NULL;
895
896 error = sfprov_open(mnt, path, &fp);
897 if (error != 0)
898 return (ENOENT);
899
900 /*
901 * Allocate the first dirents buffers.
902 */
903 *dirents = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP);
904 if (*dirents == NULL) {
905 error = (ENOSPC);
906 goto done;
907 }
908 cur_buf = *dirents;
909 cur_buf->sf_next = NULL;
910 cur_buf->sf_len = 0;
911
912 /*
913 * Create mask that VBox expects. This needs to be the directory path,
914 * plus a "*" wildcard to get all files.
915 */
916 len = strlen(path) + 3;
917 cp = kmem_alloc(len, KM_SLEEP);
918 if (cp == NULL) {
919 error = (ENOSPC);
920 goto done;
921 }
922 strcpy(cp, path);
923 strcat(cp, "/*");
924 mask_str = sfprov_string(cp, &mask_size);
925 kmem_free(cp, len);
926
927 /*
928 * Now loop using vboxCallDirInfo
929 */
930 infobuff = kmem_alloc(infobuff_alloc, KM_SLEEP);
931 if (infobuff == NULL) {
932 error = (ENOSPC);
933 goto done;
934 }
935
936 offset = 0;
937 for (;;) {
938 numbytes = infobuff_alloc;
939 error = vboxCallDirInfo(&vbox_client, &fp->map, fp->handle,
940 mask_str, 0, 0, &numbytes, infobuff, &nents);
941 switch (error) {
942
943 case VINF_SUCCESS:
944 /* fallthrough */
945 case VERR_NO_MORE_FILES:
946 break;
947
948 case VERR_NO_TRANSLATION:
949 /* XXX ??? */
950 break;
951
952 default:
953 error = sfprov_vbox2errno(error);
954 goto done;
955 }
956
957 /*
958 * Create the dirent_t's and save the stats for each name
959 */
960 for (info = infobuff; (char *) info < (char *) infobuff + numbytes; nents--) {
961 /* expand buffers if we need more space */
962 reclen = DIRENT64_RECLEN(strlen(info->name.String.utf8));
963 entlen = sizeof(sffs_stat_t) + reclen;
964 if (SFFS_DIRENTS_OFF + cur_buf->sf_len + entlen > SFFS_DIRENTS_SIZE) {
965 cur_buf->sf_next = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP);
966 if (cur_buf->sf_next == NULL) {
967 error = ENOSPC;
968 goto done;
969 }
970 cur_buf = cur_buf->sf_next;
971 cur_buf->sf_next = NULL;
972 cur_buf->sf_len = 0;
973 }
974
975 /* create the dirent with the name, offset, and len */
976 dirent = (struct sffs_dirent *)
977 (((char *) &cur_buf->sf_entries[0]) + cur_buf->sf_len);
978 strncpy(&dirent->sf_entry.d_name[0], info->name.String.utf8, DIRENT64_NAMELEN(reclen));
979 dirent->sf_entry.d_reclen = reclen;
980 offset += entlen;
981 dirent->sf_entry.d_off = offset;
982
983 /* save the stats */
984 sfprov_stat_from_info(&dirent->sf_stat, &info->Info);
985
986 /* next info */
987 cur_buf->sf_len += entlen;
988 size = offsetof (SHFLDIRINFO, name.String) + info->name.u16Size;
989 info = (SHFLDIRINFO *) ((uintptr_t) info + size);
990 }
991 ASSERT(nents == 0);
992 ASSERT((char *) info == (char *) infobuff + numbytes);
993
994 if (error == VERR_NO_MORE_FILES)
995 break;
996 }
997 error = 0;
998
999done:
1000 if (error != 0) {
1001 while (*dirents) {
1002 cur_buf = (*dirents)->sf_next;
1003 kmem_free(*dirents, SFFS_DIRENTS_SIZE);
1004 *dirents = cur_buf;
1005 }
1006 }
1007 if (infobuff != NULL)
1008 kmem_free(infobuff, infobuff_alloc);
1009 if (mask_str != NULL)
1010 kmem_free(mask_str, mask_size);
1011 sfprov_close(fp);
1012 return (error);
1013}
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