VirtualBox

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

Last change on this file since 107250 was 107250, checked in by vboxsync, 6 weeks ago

Add,HostDrivers: More parfait/solaris kludges.

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