VirtualBox

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

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

Additions/solaris/SharedFolders: Consolidate volinfo calls into one fsinfo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.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.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 * get information about a file (or directory)
388 */
389static void
390sfprov_mode_from_fmode(mode_t *mode, RTFMODE fMode)
391{
392 mode_t m = 0;
393
394 if (RTFS_IS_DIRECTORY(fMode))
395 m |= S_IFDIR;
396 else if (RTFS_IS_FILE(fMode))
397 m |= S_IFREG;
398 else if (RTFS_IS_FIFO(fMode))
399 m |= S_IFIFO;
400 else if (RTFS_IS_DEV_CHAR(fMode))
401 m |= S_IFCHR;
402 else if (RTFS_IS_DEV_BLOCK(fMode))
403 m |= S_IFBLK;
404 else if (RTFS_IS_SYMLINK(fMode))
405 m |= S_IFLNK;
406 else if (RTFS_IS_SOCKET(fMode))
407 m |= S_IFSOCK;
408
409 if (fMode & RTFS_UNIX_IRUSR)
410 m |= S_IRUSR;
411 if (fMode & RTFS_UNIX_IWUSR)
412 m |= S_IWUSR;
413 if (fMode & RTFS_UNIX_IXUSR)
414 m |= S_IXUSR;
415 if (fMode & RTFS_UNIX_IRGRP)
416 m |= S_IRGRP;
417 if (fMode & RTFS_UNIX_IWGRP)
418 m |= S_IWGRP;
419 if (fMode & RTFS_UNIX_IXGRP)
420 m |= S_IXGRP;
421 if (fMode & RTFS_UNIX_IROTH)
422 m |= S_IROTH;
423 if (fMode & RTFS_UNIX_IWOTH)
424 m |= S_IWOTH;
425 if (fMode & RTFS_UNIX_IXOTH)
426 m |= S_IXOTH;
427 if (fMode & RTFS_UNIX_ISUID)
428 m |= S_ISUID;
429 if (fMode & RTFS_UNIX_ISGID)
430 m |= S_ISGID;
431 if (fMode & RTFS_UNIX_ISTXT)
432 m |= S_ISVTX;
433 *mode = m;
434}
435
436/*
437 * get information about a file (or directory)
438 */
439int
440sfprov_get_mode(sfp_mount_t *mnt, char *path, mode_t *mode)
441{
442 int rc;
443 SHFLFSOBJINFO info;
444
445 rc = sfprov_getinfo(mnt, path, &info);
446 if (rc)
447 return (rc);
448 sfprov_mode_from_fmode(mode, info.Attr.fMode);
449 return (0);
450}
451
452int
453sfprov_get_size(sfp_mount_t *mnt, char *path, uint64_t *size)
454{
455 int rc;
456 SHFLFSOBJINFO info;
457
458 rc = sfprov_getinfo(mnt, path, &info);
459 if (rc)
460 return (rc);
461 *size = info.cbObject;
462 return (0);
463}
464
465static void
466sfprov_ftime_from_timespec(timestruc_t *time, RTTIMESPEC *ts)
467{
468 uint64_t nanosec = RTTimeSpecGetNano(ts);
469 time->tv_sec = nanosec / UINT64_C(1000000000);
470 time->tv_nsec = nanosec % UINT64_C(1000000000);
471}
472
473static void
474sfprov_stat_from_info(sffs_stat_t *stat, SHFLFSOBJINFO *info)
475{
476 sfprov_mode_from_fmode(&stat->sf_mode, info->Attr.fMode);
477 stat->sf_size = info->cbObject;
478 stat->sf_alloc = info->cbAllocated;
479 sfprov_ftime_from_timespec(&stat->sf_atime, &info->AccessTime);
480 sfprov_ftime_from_timespec(&stat->sf_mtime, &info->ModificationTime);
481 sfprov_ftime_from_timespec(&stat->sf_ctime, &info->ChangeTime);
482}
483
484int
485sfprov_get_atime(sfp_mount_t *mnt, char *path, timestruc_t *time)
486{
487 int rc;
488 SHFLFSOBJINFO info;
489
490 rc = sfprov_getinfo(mnt, path, &info);
491 if (rc)
492 return (rc);
493 sfprov_ftime_from_timespec(time, &info.AccessTime);
494 return (0);
495}
496
497int
498sfprov_get_mtime(sfp_mount_t *mnt, char *path, timestruc_t *time)
499{
500 int rc;
501 SHFLFSOBJINFO info;
502
503 rc = sfprov_getinfo(mnt, path, &info);
504 if (rc)
505 return (rc);
506 sfprov_ftime_from_timespec(time, &info.ModificationTime);
507 return (0);
508}
509
510int
511sfprov_get_ctime(sfp_mount_t *mnt, char *path, timestruc_t *time)
512{
513 int rc;
514 SHFLFSOBJINFO info;
515
516 rc = sfprov_getinfo(mnt, path, &info);
517 if (rc)
518 return (rc);
519 sfprov_ftime_from_timespec(time, &info.ChangeTime);
520 return (0);
521}
522
523int
524sfprov_get_attr(sfp_mount_t *mnt, char *path, sffs_stat_t *attr)
525{
526 int rc;
527 SHFLFSOBJINFO info;
528
529 rc = sfprov_getinfo(mnt, path, &info);
530 if (rc)
531 return (rc);
532 sfprov_stat_from_info(attr, &info);
533 return (0);
534}
535
536static void
537sfprov_timespec_from_ftime(RTTIMESPEC *ts, timestruc_t time)
538{
539 uint64_t nanosec = UINT64_C(1000000000) * time.tv_sec + time.tv_nsec;
540 RTTimeSpecSetNano(ts, nanosec);
541}
542
543int
544sfprov_set_attr(
545 sfp_mount_t *mnt,
546 char *path,
547 uint_t mask,
548 mode_t mode,
549 timestruc_t atime,
550 timestruc_t mtime,
551 timestruc_t ctime)
552{
553 int rc, err;
554 SHFLCREATEPARMS parms;
555 SHFLSTRING *str;
556 SHFLFSOBJINFO info;
557 uint32_t bytes;
558 int str_size;
559
560 str = sfprov_string(path, &str_size);
561 parms.Handle = 0;
562 parms.Info.cbObject = 0;
563 parms.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS
564 | SHFL_CF_ACT_FAIL_IF_NEW
565 | SHFL_CF_ACCESS_ATTR_WRITE;
566
567 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
568
569 if (RT_FAILURE(rc)) {
570 cmn_err(CE_WARN, "sfprov_set_attr: vboxCallCreate(%s) failed rc=%d\n",
571 path, rc);
572 err = EINVAL;
573 goto fail2;
574 }
575 if (parms.Result != SHFL_FILE_EXISTS) {
576 err = ENOENT;
577 goto fail1;
578 }
579
580 RT_ZERO(info);
581 if (mask & AT_MODE) {
582#define mode_set(r) ((mode & (S_##r)) ? RTFS_UNIX_##r : 0)
583
584 info.Attr.fMode = mode_set (ISUID);
585 info.Attr.fMode |= mode_set (ISGID);
586 info.Attr.fMode |= (mode & S_ISVTX) ? RTFS_UNIX_ISTXT : 0;
587 info.Attr.fMode |= mode_set (IRUSR);
588 info.Attr.fMode |= mode_set (IWUSR);
589 info.Attr.fMode |= mode_set (IXUSR);
590 info.Attr.fMode |= mode_set (IRGRP);
591 info.Attr.fMode |= mode_set (IWGRP);
592 info.Attr.fMode |= mode_set (IXGRP);
593 info.Attr.fMode |= mode_set (IROTH);
594 info.Attr.fMode |= mode_set (IWOTH);
595 info.Attr.fMode |= mode_set (IXOTH);
596
597 if (S_ISDIR(mode))
598 info.Attr.fMode |= RTFS_TYPE_DIRECTORY;
599 else if (S_ISREG(mode))
600 info.Attr.fMode |= RTFS_TYPE_FILE;
601 else if (S_ISFIFO(mode))
602 info.Attr.fMode |= RTFS_TYPE_FIFO;
603 else if (S_ISCHR(mode))
604 info.Attr.fMode |= RTFS_TYPE_DEV_CHAR;
605 else if (S_ISBLK(mode))
606 info.Attr.fMode |= RTFS_TYPE_DEV_BLOCK;
607 else if (S_ISLNK(mode))
608 info.Attr.fMode |= RTFS_TYPE_SYMLINK;
609 else if (S_ISSOCK(mode))
610 info.Attr.fMode |= RTFS_TYPE_SOCKET;
611 else
612 info.Attr.fMode |= RTFS_TYPE_FILE;
613 }
614
615 if (mask & AT_ATIME)
616 sfprov_timespec_from_ftime(&info.AccessTime, atime);
617 if (mask & AT_MTIME)
618 sfprov_timespec_from_ftime(&info.ModificationTime, mtime);
619 if (mask & AT_CTIME)
620 sfprov_timespec_from_ftime(&info.ChangeTime, ctime);
621
622 bytes = sizeof(info);
623 rc = vboxCallFSInfo(&vbox_client, &mnt->map, parms.Handle,
624 (SHFL_INFO_SET | SHFL_INFO_FILE), &bytes, (SHFLDIRINFO *)&info);
625 if (RT_FAILURE(rc)) {
626 if (rc != VERR_ACCESS_DENIED && rc != VERR_WRITE_PROTECT)
627 {
628 cmn_err(CE_WARN, "sfprov_set_attr: vboxCallFSInfo(%s, FILE) failed rc=%d\n",
629 path, rc);
630 }
631 err = sfprov_vbox2errno(rc);
632 goto fail1;
633 }
634
635 err = 0;
636
637fail1:
638 rc = vboxCallClose(&vbox_client, &mnt->map, parms.Handle);
639 if (RT_FAILURE(rc)) {
640 cmn_err(CE_WARN, "sfprov_set_attr: vboxCallClose(%s) failed rc=%d\n",
641 path, rc);
642 }
643fail2:
644 kmem_free(str, str_size);
645 return err;
646}
647
648int
649sfprov_set_size(sfp_mount_t *mnt, char *path, uint64_t size)
650{
651 int rc, err;
652 SHFLCREATEPARMS parms;
653 SHFLSTRING *str;
654 SHFLFSOBJINFO info;
655 uint32_t bytes;
656 int str_size;
657
658 str = sfprov_string(path, &str_size);
659 parms.Handle = 0;
660 parms.Info.cbObject = 0;
661 parms.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS
662 | SHFL_CF_ACT_FAIL_IF_NEW
663 | SHFL_CF_ACCESS_WRITE;
664
665 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
666
667 if (RT_FAILURE(rc)) {
668 cmn_err(CE_WARN, "sfprov_set_size: vboxCallCreate(%s) failed rc=%d\n",
669 path, rc);
670 err = EINVAL;
671 goto fail2;
672 }
673 if (parms.Result != SHFL_FILE_EXISTS) {
674 err = ENOENT;
675 goto fail1;
676 }
677
678 RT_ZERO(info);
679 info.cbObject = size;
680 bytes = sizeof(info);
681 rc = vboxCallFSInfo(&vbox_client, &mnt->map, parms.Handle,
682 (SHFL_INFO_SET | SHFL_INFO_SIZE), &bytes, (SHFLDIRINFO *)&info);
683 if (RT_FAILURE(rc)) {
684 cmn_err(CE_WARN, "sfprov_set_size: vboxCallFSInfo(%s, SIZE) failed rc=%d\n",
685 path, rc);
686 err = sfprov_vbox2errno(rc);
687 goto fail1;
688 }
689
690 err = 0;
691
692fail1:
693 rc = vboxCallClose(&vbox_client, &mnt->map, parms.Handle);
694 if (RT_FAILURE(rc)) {
695 cmn_err(CE_WARN, "sfprov_set_size: vboxCallClose(%s) failed rc=%d\n",
696 path, rc);
697 }
698fail2:
699 kmem_free(str, str_size);
700 return err;
701}
702
703/*
704 * Directory operations
705 */
706int
707sfprov_mkdir(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
708{
709 int rc;
710 SHFLCREATEPARMS parms;
711 SHFLSTRING *str;
712 int size;
713 sfp_file_t *newfp;
714
715 str = sfprov_string(path, &size);
716 parms.Handle = 0;
717 parms.Info.cbObject = 0;
718 parms.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW |
719 SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READ;
720 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
721 kmem_free(str, size);
722
723 if (RT_FAILURE(rc))
724 return (sfprov_vbox2errno(rc));
725 if (parms.Handle == SHFL_HANDLE_NIL) {
726 if (parms.Result == SHFL_FILE_EXISTS)
727 return (EEXIST);
728 return (ENOENT);
729 }
730 newfp = kmem_alloc(sizeof(sfp_file_t), KM_SLEEP);
731 newfp->handle = parms.Handle;
732 newfp->map = mnt->map;
733 *fp = newfp;
734 return (0);
735}
736
737int
738sfprov_set_show_symlinks(void)
739{
740 int rc;
741
742 rc = vboxCallSetSymlinks(&vbox_client);
743 if (RT_FAILURE(rc))
744 return (sfprov_vbox2errno(rc));
745
746 return (0);
747}
748
749int
750sfprov_remove(sfp_mount_t *mnt, char *path, uint_t is_link)
751{
752 int rc;
753 SHFLSTRING *str;
754 int size;
755
756 str = sfprov_string(path, &size);
757 rc = vboxCallRemove(&vbox_client, &mnt->map, str,
758 SHFL_REMOVE_FILE | (is_link ? SHFL_REMOVE_SYMLINK : 0));
759 kmem_free(str, size);
760 if (RT_FAILURE(rc))
761 return (sfprov_vbox2errno(rc));
762 return (0);
763}
764
765int
766sfprov_readlink(
767 sfp_mount_t *mnt,
768 char *path,
769 char *target,
770 size_t tgt_size)
771{
772 int rc;
773 SHFLSTRING *str;
774 int size;
775
776 str = sfprov_string(path, &size);
777
778 rc = vboxReadLink(&vbox_client, &mnt->map, str, (uint32_t) tgt_size,
779 target);
780 if (RT_FAILURE(rc))
781 rc = sfprov_vbox2errno(rc);
782
783 kmem_free(str, size);
784 return (rc);
785}
786
787int
788sfprov_symlink(
789 sfp_mount_t *mnt,
790 char *linkname,
791 char *target,
792 sffs_stat_t *stat)
793{
794 int rc;
795 SHFLSTRING *lnk, *tgt;
796 int lnk_size, tgt_size;
797 SHFLFSOBJINFO info;
798
799 lnk = sfprov_string(linkname, &lnk_size);
800 tgt = sfprov_string(target, &tgt_size);
801
802 rc = vboxCallSymlink(&vbox_client, &mnt->map, lnk, tgt, &info);
803 if (RT_FAILURE(rc)) {
804 rc = sfprov_vbox2errno(rc);
805 goto done;
806 }
807
808 if (stat != NULL)
809 sfprov_stat_from_info(stat, &info);
810
811done:
812 kmem_free(lnk, lnk_size);
813 kmem_free(tgt, tgt_size);
814
815 return (rc);
816}
817
818int
819sfprov_rmdir(sfp_mount_t *mnt, char *path)
820{
821 int rc;
822 SHFLSTRING *str;
823 int size;
824
825 str = sfprov_string(path, &size);
826 rc = vboxCallRemove(&vbox_client, &mnt->map, str, SHFL_REMOVE_DIR);
827 kmem_free(str, size);
828 if (RT_FAILURE(rc))
829 return (sfprov_vbox2errno(rc));
830 return (0);
831}
832
833int
834sfprov_rename(sfp_mount_t *mnt, char *from, char *to, uint_t is_dir)
835{
836 int rc;
837 SHFLSTRING *old, *new;
838 int old_size, new_size;
839
840 old = sfprov_string(from, &old_size);
841 new = sfprov_string(to, &new_size);
842 rc = vboxCallRename(&vbox_client, &mnt->map, old, new,
843 (is_dir ? SHFL_RENAME_DIR : SHFL_RENAME_FILE) |
844 SHFL_RENAME_REPLACE_IF_EXISTS);
845 kmem_free(old, old_size);
846 kmem_free(new, new_size);
847 if (RT_FAILURE(rc))
848 return (sfprov_vbox2errno(rc));
849 return (0);
850}
851
852
853/*
854 * Read all filenames in a directory.
855 *
856 * - success - all entries read and returned
857 * - ENOENT - Couldn't open the directory for reading
858 * - EINVAL - Internal error of some kind
859 *
860 * On successful return, *dirents points to a list of sffs_dirents_t;
861 * for each dirent, all fields except the d_ino will be set appropriately.
862 * The caller is responsible for freeing the dirents buffer.
863 */
864int
865sfprov_readdir(
866 sfp_mount_t *mnt,
867 char *path,
868 sffs_dirents_t **dirents)
869{
870 int error;
871 char *cp;
872 int len;
873 SHFLSTRING *mask_str = NULL; /* must be path with "/*" appended */
874 int mask_size;
875 sfp_file_t *fp;
876 uint32_t infobuff_alloc = 16384;
877 SHFLDIRINFO *infobuff = NULL, *info;
878 uint32_t numbytes;
879 uint32_t nents;
880 uint32_t size;
881 off_t offset;
882 sffs_dirents_t *cur_buf;
883 struct sffs_dirent *dirent;
884 unsigned short reclen;
885 unsigned short entlen;
886
887 *dirents = NULL;
888
889 error = sfprov_open(mnt, path, &fp);
890 if (error != 0)
891 return (ENOENT);
892
893 /*
894 * Allocate the first dirents buffers.
895 */
896 *dirents = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP);
897 if (*dirents == NULL) {
898 error = (ENOSPC);
899 goto done;
900 }
901 cur_buf = *dirents;
902 cur_buf->sf_next = NULL;
903 cur_buf->sf_len = 0;
904
905 /*
906 * Create mask that VBox expects. This needs to be the directory path,
907 * plus a "*" wildcard to get all files.
908 */
909 len = strlen(path) + 3;
910 cp = kmem_alloc(len, KM_SLEEP);
911 if (cp == NULL) {
912 error = (ENOSPC);
913 goto done;
914 }
915 strcpy(cp, path);
916 strcat(cp, "/*");
917 mask_str = sfprov_string(cp, &mask_size);
918 kmem_free(cp, len);
919
920 /*
921 * Now loop using vboxCallDirInfo
922 */
923 infobuff = kmem_alloc(infobuff_alloc, KM_SLEEP);
924 if (infobuff == NULL) {
925 error = (ENOSPC);
926 goto done;
927 }
928
929 offset = 0;
930 for (;;) {
931 numbytes = infobuff_alloc;
932 error = vboxCallDirInfo(&vbox_client, &fp->map, fp->handle,
933 mask_str, 0, 0, &numbytes, infobuff, &nents);
934 switch (error) {
935
936 case VINF_SUCCESS:
937 /* fallthrough */
938 case VERR_NO_MORE_FILES:
939 break;
940
941 case VERR_NO_TRANSLATION:
942 /* XXX ??? */
943 break;
944
945 default:
946 error = sfprov_vbox2errno(error);
947 goto done;
948 }
949
950 /*
951 * Create the dirent_t's and save the stats for each name
952 */
953 for (info = infobuff; (char *) info < (char *) infobuff + numbytes; nents--) {
954 /* expand buffers if we need more space */
955 reclen = DIRENT64_RECLEN(strlen(info->name.String.utf8));
956 entlen = sizeof(sffs_stat_t) + reclen;
957 if (SFFS_DIRENTS_OFF + cur_buf->sf_len + entlen > SFFS_DIRENTS_SIZE) {
958 cur_buf->sf_next = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP);
959 if (cur_buf->sf_next == NULL) {
960 error = ENOSPC;
961 goto done;
962 }
963 cur_buf = cur_buf->sf_next;
964 cur_buf->sf_next = NULL;
965 cur_buf->sf_len = 0;
966 }
967
968 /* create the dirent with the name, offset, and len */
969 dirent = (struct sffs_dirent *)
970 (((char *) &cur_buf->sf_entries[0]) + cur_buf->sf_len);
971 strncpy(&dirent->sf_entry.d_name[0], info->name.String.utf8, DIRENT64_NAMELEN(reclen));
972 dirent->sf_entry.d_reclen = reclen;
973 offset += entlen;
974 dirent->sf_entry.d_off = offset;
975
976 /* save the stats */
977 sfprov_stat_from_info(&dirent->sf_stat, &info->Info);
978
979 /* next info */
980 cur_buf->sf_len += entlen;
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 }
1000 if (infobuff != NULL)
1001 kmem_free(infobuff, infobuff_alloc);
1002 if (mask_str != NULL)
1003 kmem_free(mask_str, mask_size);
1004 sfprov_close(fp);
1005 return (error);
1006}
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