VirtualBox

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

Last change on this file since 76553 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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