VirtualBox

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

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

Haiku Additions: cleanup.

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