VirtualBox

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

Last change on this file since 104448 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

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