VirtualBox

source: vbox/trunk/src/VBox/Additions/haiku/SharedFolders/vboxsf.c@ 101702

Last change on this file since 101702 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.3 KB
Line 
1/* $Id: vboxsf.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * Shared folders - Haiku Guest Additions, implementation.
4 */
5
6/*
7 * Copyright (C) 2012-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/*
29 * This code is based on:
30 *
31 * VirtualBox Guest Additions for Haiku.
32 * Copyright (c) 2011 Mike Smith <[email protected]>
33 *
34 * Permission is hereby granted, free of charge, to any person
35 * obtaining a copy of this software and associated documentation
36 * files (the "Software"), to deal in the Software without
37 * restriction, including without limitation the rights to use,
38 * copy, modify, merge, publish, distribute, sublicense, and/or sell
39 * copies of the Software, and to permit persons to whom the
40 * Software is furnished to do so, subject to the following
41 * conditions:
42 *
43 * The above copyright notice and this permission notice shall be
44 * included in all copies or substantial portions of the Software.
45 *
46 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
47 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
48 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
49 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
50 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
51 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
52 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
53 * OTHER DEALINGS IN THE SOFTWARE.
54 */
55
56#include "vboxsf.h"
57
58#define MODULE_NAME "file_systems/vboxsf"
59#define FS_NAME "vboxsf"
60#define FS_PRETTY_NAME "VirtualBox Shared Folders"
61
62VBGLSFCLIENT g_clientHandle;
63static fs_volume_ops vboxsf_volume_ops;
64static fs_vnode_ops vboxsf_vnode_ops;
65
66status_t init_module(void)
67{
68#if 0
69 /** @todo enable this soon */
70 int rc = get_module(VBOXGUEST_MODULE_NAME, (module_info **)&g_VBoxGuest);
71 if (RT_LIKELY(rc == B_OK)
72 {
73 rc = VbglR0SfInit();
74 if (RT_SUCCESS(rc))
75 {
76 rc = VbglR0SfConnect(&g_clientHandle);
77 if (RT_SUCCESS(rc))
78 {
79 rc = VbglR0SfSetUtf8(&g_clientHandle);
80 if (RT_SUCCESS(rc))
81 {
82 rc = VbglR0SfSetSymlinks(&g_clientHandle);
83 if (RT_FAILURE(rc))
84 LogRel((FS_NAME ": Warning! VbglR0SfSetSymlinks failed (rc=%d) - symlink will appear as copies.\n", rc));
85
86 mutex_init(&g_vnodeCacheLock, "vboxsf vnode cache lock");
87 Log((FS_NAME ": init_module succeeded.\n");
88 return B_OK;
89 }
90 else
91 LogRel((FS_NAME ": VbglR0SfSetUtf8 failed. rc=%d\n", rc));
92 }
93 else
94 LogRel((FS_NAME ": VbglR0SfConnect failed. rc=%d\n", rc));
95 }
96 else
97 LogRel((FS_NAME ": VbglR0SfInit failed. rc=%d\n", rc));
98 }
99 else
100 LogRel((FS_NAME ": get_module failed for '%s'. rc=%d\n", VBOXGUEST_MODULE_NAME, rc));
101
102 return B_ERROR;
103#endif
104
105 if (get_module(VBOXGUEST_MODULE_NAME, (module_info **)&g_VBoxGuest) != B_OK)
106 {
107 dprintf("get_module(%s) failed\n", VBOXGUEST_MODULE_NAME);
108 return B_ERROR;
109 }
110
111 if (RT_FAILURE(VbglR0SfInit()))
112 {
113 dprintf("VbglR0SfInit failed\n");
114 return B_ERROR;
115 }
116
117 if (RT_FAILURE(VbglR0SfConnect(&g_clientHandle)))
118 {
119 dprintf("VbglR0SfConnect failed\n");
120 return B_ERROR;
121 }
122
123 if (RT_FAILURE(VbglR0SfSetUtf8(&g_clientHandle)))
124 {
125 dprintf("VbglR0SfSetUtf8 failed\n");
126 return B_ERROR;
127 }
128
129 if (RT_FAILURE(VbglR0SfSetSymlinks(&g_clientHandle)))
130 {
131 dprintf("warning: VbglR0SfSetSymlinks failed (old vbox?) - symlinks will appear as copies\n");
132 }
133
134 mutex_init(&g_vnodeCacheLock, "vboxsf vnode cache lock");
135
136 dprintf(FS_NAME ": inited successfully\n");
137 return B_OK;
138}
139
140void uninit_module(void)
141{
142 mutex_destroy(&g_vnodeCacheLock);
143 put_module(VBOXGUEST_MODULE_NAME);
144}
145
146
147PSHFLSTRING make_shflstring(const char* const s)
148{
149 int len = strlen(s);
150 if (len > 0xFFFE)
151 {
152 dprintf(FS_NAME ": make_shflstring: string too long\n");
153 return NULL;
154 }
155
156 PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + len);
157 if (!rv)
158 return NULL;
159
160 rv->u16Length = len;
161 rv->u16Size = len + 1;
162 strcpy(rv->String.utf8, s);
163 return rv;
164}
165
166
167PSHFLSTRING clone_shflstring(PSHFLSTRING s)
168{
169 PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s->u16Length);
170 if (rv)
171 memcpy(rv, s, sizeof(SHFLSTRING) + s->u16Length);
172 return rv;
173}
174
175PSHFLSTRING concat_shflstring_cstr(PSHFLSTRING s1, const char* const s2)
176{
177 size_t s2len = strlen(s2);
178 PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s1->u16Length + s2len);
179 if (rv)
180 {
181 memcpy(rv, s1, sizeof(SHFLSTRING) + s1->u16Length);
182 strcat(rv->String.utf8, s2);
183 rv->u16Length += s2len;
184 rv->u16Size += s2len;
185 }
186 return rv;
187}
188
189
190PSHFLSTRING concat_cstr_shflstring(const char* const s1, PSHFLSTRING s2)
191{
192 size_t s1len = strlen(s1);
193 PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s1len + s2->u16Length);
194 if (rv)
195 {
196 strcpy(rv->String.utf8, s1);
197 strcat(rv->String.utf8, s2->String.utf8);
198 rv->u16Length = s1len + s2->u16Length;
199 rv->u16Size = rv->u16Length + 1;
200 }
201 return rv;
202}
203
204
205PSHFLSTRING build_path(vboxsf_vnode* dir, const char* const name)
206{
207 dprintf("*** build_path(%p, %p)\n", dir, name);
208 if (!dir || !name)
209 return NULL;
210
211 size_t len = dir->path->u16Length + strlen(name) + 1;
212 PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + len);
213 if (rv)
214 {
215 strcpy(rv->String.utf8, dir->path->String.utf8);
216 strcat(rv->String.utf8, "/");
217 strcat(rv->String.utf8, name);
218 rv->u16Length = len;
219 rv->u16Size = rv->u16Length + 1;
220 }
221 return rv;
222}
223
224
225status_t mount(fs_volume *volume, const char *device, uint32 flags, const char *args, ino_t *_rootVnodeID)
226{
227 if (device)
228 {
229 dprintf(FS_NAME ": trying to mount a real device as a vbox share is silly\n");
230 return B_BAD_TYPE;
231 }
232
233 dprintf(FS_NAME ": mount(%s)\n", args);
234
235 PSHFLSTRING sharename = make_shflstring(args);
236
237 vboxsf_volume* vbsfvolume = malloc(sizeof(vboxsf_volume));
238 volume->private_volume = vbsfvolume;
239 int rv = VbglR0SfMapFolder(&g_clientHandle, sharename, &(vbsfvolume->map));
240 free(sharename);
241
242 if (rv == 0)
243 {
244 vboxsf_vnode* root_vnode;
245
246 PSHFLSTRING name = make_shflstring("");
247 if (!name)
248 {
249 dprintf(FS_NAME ": make_shflstring() failed\n");
250 return B_NO_MEMORY;
251 }
252
253 status_t rs = vboxsf_new_vnode(&vbsfvolume->map, name, name, &root_vnode);
254 dprintf(FS_NAME ": allocated %p (path=%p name=%p)\n", root_vnode, root_vnode->path, root_vnode->name);
255
256 if (rs != B_OK)
257 {
258 dprintf(FS_NAME ": vboxsf_new_vnode() failed (%d)\n", (int)rs);
259 return rs;
260 }
261
262 rs = publish_vnode(volume, root_vnode->vnode, root_vnode, &vboxsf_vnode_ops, S_IFDIR, 0);
263 dprintf(FS_NAME ": publish_vnode(): %d\n", (int)rs);
264 *_rootVnodeID = root_vnode->vnode;
265 volume->ops = &vboxsf_volume_ops;
266 return B_OK;
267 }
268 else
269 {
270 dprintf(FS_NAME ": VbglR0SfMapFolder failed (%d)\n", rv);
271 free(volume->private_volume);
272 return vbox_err_to_haiku_err(rv);
273 }
274}
275
276
277status_t unmount(fs_volume *volume)
278{
279 dprintf(FS_NAME ": unmount\n");
280 VbglR0SfUnmapFolder(&g_clientHandle, volume->private_volume);
281 return B_OK;
282}
283
284
285status_t vboxsf_read_stat(fs_volume* _volume, fs_vnode* _vnode, struct stat* st)
286{
287 vboxsf_vnode* vnode = _vnode->private_node;
288 vboxsf_volume* volume = _volume->private_volume;
289 SHFLCREATEPARMS params;
290 int rc;
291
292 dprintf("vboxsf_read_stat (_vnode=%p, vnode=%p, path=%p (%s))\n", _vnode, vnode, vnode->path->String.utf8, vnode->path->String.utf8);
293
294 params.Handle = SHFL_HANDLE_NIL;
295 params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
296 dprintf("sf_stat: calling VbglR0SfCreate, file %s, flags %x\n", vnode->path->String.utf8, params.CreateFlags);
297 rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, &params);
298 if (rc == VERR_INVALID_NAME)
299 {
300 /* this can happen for names like 'foo*' on a Windows host */
301 return B_ENTRY_NOT_FOUND;
302 }
303 if (RT_FAILURE(rc))
304 {
305 dprintf("VbglR0SfCreate: %d\n", params.Result);
306 return vbox_err_to_haiku_err(params.Result);
307 }
308 if (params.Result != SHFL_FILE_EXISTS)
309 {
310 dprintf("VbglR0SfCreate: %d\n", params.Result);
311 return B_ENTRY_NOT_FOUND;
312 }
313
314 st->st_dev = 0;
315 st->st_ino = vnode->vnode;
316 st->st_mode = mode_from_fmode(params.Info.Attr.fMode);
317 st->st_nlink = 1;
318 st->st_uid = 0;
319 st->st_gid = 0;
320 st->st_rdev = 0;
321 st->st_size = params.Info.cbObject;
322 st->st_blksize = 1;
323 st->st_blocks = params.Info.cbAllocated;
324 st->st_atime = RTTimeSpecGetSeconds(&params.Info.AccessTime);
325 st->st_mtime = RTTimeSpecGetSeconds(&params.Info.ModificationTime);
326 st->st_ctime = RTTimeSpecGetSeconds(&params.Info.BirthTime);
327 return B_OK;
328}
329
330
331status_t vboxsf_open_dir(fs_volume* _volume, fs_vnode* _vnode, void** _cookie)
332{
333 vboxsf_volume* volume = _volume->private_volume;
334 vboxsf_vnode* vnode = _vnode->private_node;
335 SHFLCREATEPARMS params;
336
337 RT_ZERO(params);
338 params.Handle = SHFL_HANDLE_NIL;
339 params.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ;
340
341 int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, &params);
342 if (RT_SUCCESS(rc))
343 {
344 if (params.Result == SHFL_FILE_EXISTS && params.Handle != SHFL_HANDLE_NIL)
345 {
346 vboxsf_dir_cookie* cookie = malloc(sizeof(vboxsf_dir_cookie));
347 *_cookie = cookie;
348 cookie->index = 0;
349 cookie->path = build_path(vnode, "*");
350 cookie->handle = params.Handle;
351 cookie->has_more_files = true;
352 cookie->buffer_start = cookie->buffer = NULL;
353 cookie->buffer_length = cookie->num_files = 0;
354 return B_OK;
355 }
356 else
357 return B_ENTRY_NOT_FOUND;
358 }
359 else
360 {
361 dprintf(FS_NAME ": VbglR0SfCreate: %d\n", rc);
362 return vbox_err_to_haiku_err(rc);
363 }
364}
365
366
367/** read a single entry from a dir */
368status_t vboxsf_read_dir_1(vboxsf_volume* volume, vboxsf_vnode* vnode, vboxsf_dir_cookie* cookie,
369 struct dirent* buffer, size_t bufferSize)
370{
371 dprintf("%p, %d, %p\n", cookie, cookie->has_more_files, cookie->buffer);
372 if (!cookie->has_more_files)
373 return B_ENTRY_NOT_FOUND;
374
375 if (!cookie->buffer)
376 {
377 cookie->buffer_length = 16384;
378 cookie->buffer_start = cookie->buffer = malloc(cookie->buffer_length);
379
380 int rc = VbglR0SfDirInfo(&g_clientHandle, &volume->map, cookie->handle, cookie->path, 0, cookie->index,
381 &cookie->buffer_length, cookie->buffer, &cookie->num_files);
382
383 if (rc != 0 && rc != VERR_NO_MORE_FILES)
384 {
385 dprintf(FS_NAME ": VbglR0SfDirInfo failed: %d\n", rc);
386 free(cookie->buffer_start);
387 cookie->buffer_start = NULL;
388 return vbox_err_to_haiku_err(rc);
389 }
390
391 if (rc == VERR_NO_MORE_FILES)
392 {
393 free(cookie->buffer_start);
394 cookie->buffer_start = NULL;
395 cookie->has_more_files = false;
396 return B_ENTRY_NOT_FOUND;
397 }
398 }
399
400 if (bufferSize <= sizeof(struct dirent) + cookie->buffer->name.u16Length)
401 {
402 dprintf("hit end of buffer\n");
403 return B_BUFFER_OVERFLOW;
404 }
405
406 PSHFLSTRING name1 = clone_shflstring(&cookie->buffer->name);
407 if (!name1)
408 {
409 dprintf(FS_NAME ": make_shflstring() failed\n");
410 return B_NO_MEMORY;
411 }
412
413 vboxsf_vnode* new_vnode;
414 int rv = vboxsf_new_vnode(&volume->map, build_path(vnode, name1->String.utf8), name1, &new_vnode);
415 if (rv != B_OK)
416 {
417 dprintf(FS_NAME ": vboxsf_new_vnode() failed\n");
418 return rv;
419 }
420
421 buffer->d_dev = 0;
422 buffer->d_pdev = 0;
423 buffer->d_ino = new_vnode->vnode;
424 buffer->d_pino = vnode->vnode;
425 buffer->d_reclen = sizeof(struct dirent) + cookie->buffer->name.u16Length;
426 strncpy(buffer->d_name, cookie->buffer->name.String.utf8, NAME_MAX);
427
428 size_t size = offsetof(SHFLDIRINFO, name.String) + cookie->buffer->name.u16Size;
429 cookie->buffer = ((void*)cookie->buffer + size);
430 cookie->index++;
431
432 if (cookie->index >= cookie->num_files)
433 {
434 // hit end of this buffer, next call will reallocate a new one
435 free(cookie->buffer_start);
436 cookie->buffer_start = cookie->buffer = NULL;
437 }
438 return B_OK;
439}
440
441
442status_t vboxsf_read_dir(fs_volume* _volume, fs_vnode* _vnode, void* _cookie,
443 struct dirent* buffer, size_t bufferSize, uint32* _num)
444{
445 vboxsf_dir_cookie* cookie = _cookie;
446 vboxsf_volume* volume = _volume->private_volume;
447 vboxsf_vnode* vnode = _vnode->private_node;
448 uint32 num_read = 0;
449 status_t rv = B_OK;
450
451 for (num_read = 0; num_read < *_num && cookie->has_more_files; num_read++)
452 {
453 rv = vboxsf_read_dir_1(volume, vnode, cookie, buffer, bufferSize);
454 if (rv == B_BUFFER_OVERFLOW || rv == B_ENTRY_NOT_FOUND)
455 {
456 // hit end of at least one of the buffers - not really an error
457 rv = B_OK;
458 break;
459 }
460 bufferSize -= buffer->d_reclen;
461 buffer = ((void*)(buffer)) + buffer->d_reclen;
462 }
463
464 *_num = num_read;
465 return rv;
466}
467
468
469status_t vboxsf_free_dir_cookie(fs_volume* _volume, fs_vnode* vnode, void* _cookie)
470{
471 vboxsf_volume* volume = _volume->private_volume;
472 vboxsf_dir_cookie* cookie = _cookie;
473
474 VbglR0SfClose(&g_clientHandle, &volume->map, cookie->handle);
475 free(cookie->path);
476 free(cookie);
477
478 return B_OK;
479}
480
481
482status_t vboxsf_read_fs_info(fs_volume* _volume, struct fs_info* info)
483{
484 vboxsf_volume* volume = _volume->private_volume;
485
486 SHFLVOLINFO volume_info;
487 uint32_t bytes = sizeof(SHFLVOLINFO);
488
489 int rc = VbglR0SfFsInfo(&g_clientHandle, &volume->map, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME,
490 &bytes, (PSHFLDIRINFO)&volume_info);
491 if (RT_FAILURE(rc))
492 {
493 dprintf(FS_NAME ": VbglR0SfFsInfo failed (%d)\n", rc);
494 return vbox_err_to_haiku_err(rc);
495 }
496
497 info->flags = B_FS_IS_PERSISTENT;
498 if (volume_info.fsProperties.fReadOnly)
499 info->flags |= B_FS_IS_READONLY;
500
501 info->dev = 0;
502 info->root = 1;
503 info->block_size = volume_info.ulBytesPerAllocationUnit;
504 info->io_size = volume_info.ulBytesPerAllocationUnit;
505 info->total_blocks = volume_info.ullTotalAllocationBytes / info->block_size;
506 info->free_blocks = volume_info.ullAvailableAllocationBytes / info->block_size;
507 info->total_nodes = LONGLONG_MAX;
508 info->free_nodes = LONGLONG_MAX;
509 strcpy(info->volume_name, "VBox share");
510 return B_OK;
511}
512
513
514status_t vboxsf_lookup(fs_volume* _volume, fs_vnode* dir, const char* name, ino_t* _id)
515{
516 dprintf(FS_NAME ": lookup %s\n", name);
517 vboxsf_volume* volume = _volume->private_volume;
518 SHFLCREATEPARMS params;
519
520 RT_ZERO(params);
521 params.Handle = SHFL_HANDLE_NIL;
522 params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
523
524 PSHFLSTRING path = build_path(dir->private_node, name);
525 if (!path)
526 {
527 dprintf(FS_NAME ": make_shflstring() failed\n");
528 return B_NO_MEMORY;
529 }
530
531 int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, &params);
532 if (RT_SUCCESS(rc))
533 {
534 if (params.Result == SHFL_FILE_EXISTS)
535 {
536 vboxsf_vnode* vn;
537 status_t rv = vboxsf_new_vnode(&volume->map, path, path, &vn);
538 if (rv == B_OK)
539 {
540 *_id = vn->vnode;
541 rv = publish_vnode(_volume, vn->vnode, vn, &vboxsf_vnode_ops, mode_from_fmode(params.Info.Attr.fMode), 0);
542 }
543 return rv;
544 }
545 else
546 {
547 free(path);
548 return B_ENTRY_NOT_FOUND;
549 }
550 }
551 else
552 {
553 free(path);
554 dprintf(FS_NAME ": VbglR0SfCreate: %d\n", rc);
555 return vbox_err_to_haiku_err(rc);
556 }
557}
558
559
560mode_t mode_from_fmode(RTFMODE fMode)
561{
562 mode_t m = 0;
563
564 if (RTFS_IS_DIRECTORY(fMode))
565 m |= S_IFDIR;
566 else if (RTFS_IS_FILE(fMode))
567 m |= S_IFREG;
568 else if (RTFS_IS_FIFO(fMode))
569 m |= S_IFIFO;
570 else if (RTFS_IS_DEV_CHAR(fMode))
571 m |= S_IFCHR;
572 else if (RTFS_IS_DEV_BLOCK(fMode))
573 m |= S_IFBLK;
574 else if (RTFS_IS_SYMLINK(fMode))
575 m |= S_IFLNK;
576 else if (RTFS_IS_SOCKET(fMode))
577 m |= S_IFSOCK;
578
579 if (fMode & RTFS_UNIX_IRUSR)
580 m |= S_IRUSR;
581 if (fMode & RTFS_UNIX_IWUSR)
582 m |= S_IWUSR;
583 if (fMode & RTFS_UNIX_IXUSR)
584 m |= S_IXUSR;
585 if (fMode & RTFS_UNIX_IRGRP)
586 m |= S_IRGRP;
587 if (fMode & RTFS_UNIX_IWGRP)
588 m |= S_IWGRP;
589 if (fMode & RTFS_UNIX_IXGRP)
590 m |= S_IXGRP;
591 if (fMode & RTFS_UNIX_IROTH)
592 m |= S_IROTH;
593 if (fMode & RTFS_UNIX_IWOTH)
594 m |= S_IWOTH;
595 if (fMode & RTFS_UNIX_IXOTH)
596 m |= S_IXOTH;
597 if (fMode & RTFS_UNIX_ISUID)
598 m |= S_ISUID;
599 if (fMode & RTFS_UNIX_ISGID)
600 m |= S_ISGID;
601 if (fMode & RTFS_UNIX_ISTXT)
602 m |= S_ISVTX;
603
604 return m;
605}
606
607
608status_t vboxsf_open(fs_volume* _volume, fs_vnode* _vnode, int openMode, void** _cookie)
609{
610 vboxsf_volume* volume = _volume->private_volume;
611 vboxsf_vnode* vnode = _vnode->private_node;
612
613 dprintf(FS_NAME ": open %s (mode=%x)\n", vnode->path->String.utf8, openMode);
614
615 SHFLCREATEPARMS params;
616
617 RT_ZERO(params);
618 params.Handle = SHFL_HANDLE_NIL;
619
620 if (openMode & O_RDWR)
621 params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
622 else if (openMode & O_RDONLY)
623 params.CreateFlags |= SHFL_CF_ACCESS_READ;
624 else if (openMode & O_WRONLY)
625 params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
626
627 if (openMode & O_APPEND)
628 params.CreateFlags |= SHFL_CF_ACCESS_APPEND;
629
630 if (openMode & O_CREAT)
631 {
632 params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW;
633 if (openMode & O_EXCL)
634 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS;
635 else if (openMode & O_TRUNC)
636 params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
637 else
638 params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
639 }
640 else
641 {
642 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
643 if (openMode & O_TRUNC)
644 params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
645 else
646 params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
647 }
648
649 int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, &params);
650 if (!RT_SUCCESS(rc))
651 {
652 dprintf("VbglR0SfCreate returned %d\n", rc);
653 return vbox_err_to_haiku_err(rc);
654 }
655
656 vboxsf_file_cookie* cookie = malloc(sizeof(vboxsf_file_cookie));
657 if (!cookie)
658 {
659 dprintf("couldn't allocate file cookie\n");
660 return B_NO_MEMORY;
661 }
662
663 cookie->handle = params.Handle;
664 cookie->path = vnode->path;
665
666 *_cookie = cookie;
667
668 return B_OK;
669}
670
671
672status_t vboxsf_create(fs_volume* _volume, fs_vnode* _dir, const char *name, int openMode, int perms, void **_cookie, ino_t *_newVnodeID)
673{
674 vboxsf_volume* volume = _volume->private_volume;
675
676 SHFLCREATEPARMS params;
677
678 RT_ZERO(params);
679 params.Handle = SHFL_HANDLE_NIL;
680
681 if (openMode & O_RDWR)
682 params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
683 else if (openMode & O_RDONLY)
684 params.CreateFlags |= SHFL_CF_ACCESS_READ;
685 else if (openMode & O_WRONLY)
686 params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
687
688 if (openMode & O_APPEND)
689 params.CreateFlags |= SHFL_CF_ACCESS_APPEND;
690
691 if (openMode & O_CREAT)
692 {
693 params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW;
694 if (openMode & O_EXCL)
695 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS;
696 else if (openMode & O_TRUNC)
697 params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
698 else
699 params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
700 }
701 else
702 {
703 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
704 if (openMode & O_TRUNC)
705 params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
706 else
707 params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
708 }
709
710 PSHFLSTRING path = build_path(_dir->private_node, name);
711 int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, &params);
712
713 if (!RT_SUCCESS(rc))
714 {
715 dprintf("VbglR0SfCreate returned %d\n", rc);
716 free(path);
717 return vbox_err_to_haiku_err(rc);
718 }
719
720 vboxsf_file_cookie* cookie = malloc(sizeof(vboxsf_file_cookie));
721 if (!cookie)
722 {
723 dprintf("couldn't allocate file cookie\n");
724 free(path);
725 return B_NO_MEMORY;
726 }
727
728 cookie->handle = params.Handle;
729 cookie->path = path;
730
731 *_cookie = cookie;
732 return vboxsf_lookup(_volume, _dir, name, _newVnodeID);
733}
734
735
736status_t vboxsf_close(fs_volume* _volume, fs_vnode* _vnode, void* _cookie)
737{
738 vboxsf_volume* volume = _volume->private_volume;
739 vboxsf_file_cookie* cookie = _cookie;
740
741 int rc = VbglR0SfClose(&g_clientHandle, &volume->map, cookie->handle);
742 dprintf("VbglR0SfClose returned %d\n", rc);
743 return vbox_err_to_haiku_err(rc);
744}
745
746
747status_t vboxsf_rewind_dir(fs_volume* _volume, fs_vnode* _vnode, void* _cookie)
748{
749 vboxsf_dir_cookie* cookie = _cookie;
750 cookie->index = 0;
751 return B_OK;
752}
753
754
755status_t vboxsf_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
756{
757 return B_OK;
758}
759
760
761status_t vboxsf_free_cookie(fs_volume *volume, fs_vnode *vnode, void *_cookie)
762{
763 vboxsf_dir_cookie* cookie = _cookie;
764 free(cookie);
765 return B_OK;
766}
767
768status_t vboxsf_read(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, void *buffer, size_t *length)
769{
770 vboxsf_volume* volume = _volume->private_volume;
771 vboxsf_vnode* vnode = _vnode->private_node;
772 vboxsf_file_cookie* cookie = _cookie;
773
774 if (*length > 0xFFFFFFFF)
775 *length = 0xFFFFFFFF;
776
777 uint32_t l = *length;
778 void* other_buffer = malloc(l); /** @todo map the user memory into kernel space here for efficiency */
779 int rc = VbglR0SfRead(&g_clientHandle, &volume->map, cookie->handle, pos, &l, other_buffer, false /*fLocked*/);
780 memcpy(buffer, other_buffer, l);
781 free(other_buffer);
782
783 dprintf("VbglR0SfRead returned %d\n", rc);
784 *length = l;
785 return vbox_err_to_haiku_err(rc);
786}
787
788
789status_t vboxsf_write(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, const void *buffer, size_t *length)
790{
791 vboxsf_volume* volume = _volume->private_volume;
792 vboxsf_vnode* vnode = _vnode->private_node;
793 vboxsf_file_cookie* cookie = _cookie;
794
795 if (*length > 0xFFFFFFFF)
796 *length = 0xFFFFFFFF;
797
798 uint32_t l = *length;
799 void* other_buffer = malloc(l); /** @todo map the user memory into kernel space here for efficiency */
800 memcpy(other_buffer, buffer, l);
801 int rc = VbglR0SfWrite(&g_clientHandle, &volume->map, cookie->handle, pos, &l, other_buffer, false /*fLocked*/);
802 free(other_buffer);
803
804 *length = l;
805 return vbox_err_to_haiku_err(rc);
806}
807
808
809status_t vboxsf_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, uint32 statMask)
810{
811 /* The host handles updating the stat info - in the guest, this is a no-op */
812 return B_OK;
813}
814
815
816status_t vboxsf_create_dir(fs_volume *_volume, fs_vnode *parent, const char *name, int perms)
817{
818 vboxsf_volume* volume = _volume->private_volume;
819
820 SHFLCREATEPARMS params;
821 params.Handle = 0;
822 params.Info.cbObject = 0;
823 params.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW |
824 SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READ;
825
826 PSHFLSTRING path = build_path(parent->private_node, name);
827 int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, &params);
828 free(path);
829 /** @todo r=ramshankar: we should perhaps also check rc here and change
830 * Handle initialization from 0 to SHFL_HANDLE_NIL. */
831 if (params.Handle == SHFL_HANDLE_NIL)
832 return vbox_err_to_haiku_err(rc);
833 VbglR0SfClose(&g_clientHandle, &volume->map, params.Handle);
834 return B_OK;
835}
836
837
838status_t vboxsf_remove_dir(fs_volume *_volume, fs_vnode *parent, const char *name)
839{
840 vboxsf_volume* volume = _volume->private_volume;
841
842 PSHFLSTRING path = build_path(parent->private_node, name);
843 int rc = VbglR0SfRemove(&g_clientHandle, &volume->map, path, SHFL_REMOVE_DIR);
844 free(path);
845
846 return vbox_err_to_haiku_err(rc);
847}
848
849
850status_t vboxsf_unlink(fs_volume *_volume, fs_vnode *parent, const char *name)
851{
852 vboxsf_volume* volume = _volume->private_volume;
853
854 PSHFLSTRING path = build_path(parent->private_node, name);
855 int rc = VbglR0SfRemove(&g_clientHandle, &volume->map, path, SHFL_REMOVE_FILE);
856 free(path);
857
858 return vbox_err_to_haiku_err(rc);
859}
860
861status_t vboxsf_link(fs_volume *volume, fs_vnode *dir, const char *name, fs_vnode *vnode)
862{
863 return B_UNSUPPORTED;
864}
865
866
867status_t vboxsf_rename(fs_volume* _volume, fs_vnode* fromDir, const char* fromName, fs_vnode* toDir, const char* toName)
868{
869 vboxsf_volume* volume = _volume->private_volume;
870
871 PSHFLSTRING oldpath = build_path(fromDir->private_node, fromName);
872 PSHFLSTRING newpath = build_path(toDir->private_node, toName);
873 int rc = VbglR0SfRename(&g_clientHandle, &volume->map, oldpath, newpath, SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS);
874 free(oldpath);
875 free(newpath);
876
877 return vbox_err_to_haiku_err(rc);
878}
879
880
881status_t vboxsf_create_symlink(fs_volume* _volume, fs_vnode* dir, const char* name, const char* path, int mode)
882{
883 vboxsf_volume* volume = _volume->private_volume;
884
885 PSHFLSTRING target = make_shflstring(path);
886 PSHFLSTRING linkpath = build_path(dir->private_node, name);
887 SHFLFSOBJINFO stuff;
888 RT_ZERO(stuff);
889
890 int rc = VbglR0SfSymlink(&g_clientHandle, &volume->map, linkpath, target, &stuff);
891
892 free(target);
893 free(linkpath);
894
895 return vbox_err_to_haiku_err(rc);
896}
897
898
899status_t vboxsf_read_symlink(fs_volume* _volume, fs_vnode* link, char* buffer, size_t* _bufferSize)
900{
901 vboxsf_volume* volume = _volume->private_volume;
902 vboxsf_vnode* vnode = link->private_node;
903
904 int rc = VbglR0SfReadLink(&g_clientHandle, &volume->map, vnode->path, *_bufferSize, buffer);
905 *_bufferSize = strlen(buffer);
906
907 return vbox_err_to_haiku_err(rc);
908}
909
910
911/** @todo move this into the runtime */
912status_t vbox_err_to_haiku_err(int rc)
913{
914 switch (rc)
915 {
916 case VINF_SUCCESS: return B_OK;
917 case VERR_INVALID_POINTER: return B_BAD_ADDRESS;
918 case VERR_INVALID_PARAMETER: return B_BAD_VALUE;
919 case VERR_PERMISSION_DENIED: return B_PERMISSION_DENIED;
920 case VERR_NOT_IMPLEMENTED: return B_UNSUPPORTED;
921 case VERR_FILE_NOT_FOUND: return B_ENTRY_NOT_FOUND;
922
923 case SHFL_PATH_NOT_FOUND:
924 case SHFL_FILE_NOT_FOUND: return B_ENTRY_NOT_FOUND;
925 case SHFL_FILE_EXISTS: return B_FILE_EXISTS;
926
927 default:
928 return B_ERROR;
929 }
930}
931
932
933static status_t std_ops(int32 op, ...)
934{
935 switch(op)
936 {
937 case B_MODULE_INIT:
938 dprintf(MODULE_NAME ": B_MODULE_INIT\n");
939 return init_module();
940 case B_MODULE_UNINIT:
941 dprintf(MODULE_NAME ": B_MODULE_UNINIT\n");
942 uninit_module();
943 return B_OK;
944 default:
945 return B_ERROR;
946 }
947}
948
949
950static fs_volume_ops vboxsf_volume_ops =
951{
952 unmount,
953 vboxsf_read_fs_info,
954 NULL, /* write_fs_info */
955 NULL, /* sync */
956 vboxsf_get_vnode,
957 NULL, /* open_index_dir */
958 NULL, /* close_index_dir */
959 NULL, /* free_index_dir_cookie */
960 NULL, /* read_index_dir */
961 NULL, /* rewind_index_dir */
962 NULL, /* create_index */
963 NULL, /* remove_index */
964 NULL, /* read_index_stat */
965 NULL, /* open_query */
966 NULL, /* close_query */
967 NULL, /* free_query_cookie */
968 NULL, /* read_query */
969 NULL, /* rewind_query */
970 NULL, /* all_layers_mounted */
971 NULL, /* create_sub_vnode */
972 NULL, /* delete_sub_vnode */
973};
974
975static fs_vnode_ops vboxsf_vnode_ops =
976{
977 vboxsf_lookup,
978 NULL, /* get_vnode_name */
979 vboxsf_put_vnode,
980 NULL, /* remove_vnode */
981 NULL, /* can_page */
982 NULL, /* read_pages */
983 NULL, /* write_pages */
984 NULL, /* io */
985 NULL, /* cancel_io */
986 NULL, /* get_file_map */
987 NULL, /* ioctl */
988 NULL, /* set_flags */
989 NULL, /* select */
990 NULL, /* deselect */
991 NULL, /* fsync */
992 vboxsf_read_symlink,
993 vboxsf_create_symlink,
994 vboxsf_link,
995 vboxsf_unlink,
996 vboxsf_rename,
997 NULL, /* access */
998 vboxsf_read_stat,
999 vboxsf_write_stat,
1000 NULL, /* preallocate */
1001 vboxsf_create,
1002 vboxsf_open,
1003 vboxsf_close,
1004 vboxsf_free_cookie,
1005 vboxsf_read,
1006 vboxsf_write,
1007 vboxsf_create_dir,
1008 vboxsf_remove_dir,
1009 vboxsf_open_dir,
1010 vboxsf_close_dir,
1011 vboxsf_free_dir_cookie,
1012 vboxsf_read_dir,
1013 vboxsf_rewind_dir,
1014 NULL, /* open_attr_dir */
1015 NULL, /* close_attr_dir */
1016 NULL, /* free_attr_dir_cookie */
1017 NULL, /* read_attr_dir */
1018 NULL, /* rewind_attr_dir */
1019 NULL, /* create_attr */
1020 NULL, /* open_attr */
1021 NULL, /* close_attr */
1022 NULL, /* free_attr_cookie */
1023 NULL, /* read_attr */
1024 NULL, /* write_attr */
1025 NULL, /* read_attr_stat */
1026 NULL, /* write_attr_stat */
1027 NULL, /* rename_attr */
1028 NULL, /* remove_attr */
1029 NULL, /* create_special_node */
1030 NULL, /* get_super_vnode */
1031};
1032
1033static file_system_module_info sVBoxSharedFileSystem =
1034{
1035 {
1036 MODULE_NAME B_CURRENT_FS_API_VERSION,
1037 0,
1038 std_ops,
1039 },
1040 FS_NAME,
1041 FS_PRETTY_NAME,
1042 0, /* DDM flags */
1043 NULL, /* identify_partition */
1044 NULL, /* scan_partition */
1045 NULL, /* free_identify_partition_cookie */
1046 NULL, /* free_partition_content_cookie */
1047 mount,
1048};
1049
1050module_info *modules[] =
1051{
1052 (module_info *)&sVBoxSharedFileSystem,
1053 NULL,
1054};
1055
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