VirtualBox

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

Last change on this file since 44528 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette