VirtualBox

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

最後變更 在這個檔案從43363是 43363,由 vboxsync 提交於 13 年 前

Haiku Additions.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette