VirtualBox

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

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

Additions/haiku: build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.9 KB
Line 
1/* $Id: vboxsf.c 43415 2012-09-24 12:18:16Z 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#define FS_PRETTY_NAME "VirtualBox Shared Folders"
51
52VBSFCLIENT 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 = vboxInit();
64 if (RT_SUCCESS(rc))
65 {
66 rc = vboxConnect(&g_clientHandle);
67 if (RT_SUCCESS(rc))
68 {
69 rc = vboxCallSetUtf8(&g_clientHandle);
70 if (RT_SUCCESS(rc))
71 {
72 rc = vboxCallSetSymlinks(&g_clientHandle);
73 if (RT_FAILURE(rc))
74 LogRel((FS_NAME ":Warning! vboxCallSetSymlinks 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 ":vboxCallSetUtf8 failed. rc=%d\n", rc));
82 }
83 else
84 LogRel((FS_NAME ":vboxConnect failed. rc=%d\n", rc));
85 }
86 else
87 LogRel((FS_NAME ":vboxInit 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(vboxInit()))
102 {
103 dprintf("vboxInit failed\n");
104 return B_ERROR;
105 }
106
107 if (RT_FAILURE(vboxConnect(&g_clientHandle)))
108 {
109 dprintf("vboxConnect failed\n");
110 return B_ERROR;
111 }
112
113 if (RT_FAILURE(vboxCallSetUtf8(&g_clientHandle)))
114 {
115 dprintf("vboxCallSetUtf8 failed\n");
116 return B_ERROR;
117 }
118
119 if (RT_FAILURE(vboxCallSetSymlinks(&g_clientHandle)))
120 {
121 dprintf("warning: vboxCallSetSymlinks 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 = vboxCallMapFolder(&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 ": vboxCallMapFolder 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 vboxCallUnmapFolder(&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 vboxCallCreate, file %s, flags %x\n", vnode->path->String.utf8, params.CreateFlags);
287 rc = vboxCallCreate(&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("vboxCallCreate: %d\n", params.Result);
296 return vbox_err_to_haiku_err(params.Result);
297 }
298 if (params.Result != SHFL_FILE_EXISTS)
299 {
300 dprintf("vboxCallCreate: %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 = vboxCallCreate(&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 ": vboxCallCreate: %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 = vboxCallDirInfo(&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 ": vboxCallDirInfo 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 vboxCallClose(&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 = vboxCallFSInfo(&g_clientHandle, &volume->map, 0,
480 (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (PSHFLDIRINFO)&volume_info);
481
482 if (RT_FAILURE(rc))
483 {
484 dprintf(FS_NAME ": vboxCallFSInfo failed (%d)\n", rc);
485 return vbox_err_to_haiku_err(rc);
486 }
487
488 info->flags = B_FS_IS_PERSISTENT;
489 if (volume_info.fsProperties.fReadOnly)
490 info->flags |= B_FS_IS_READONLY;
491
492 info->dev = 0;
493 info->root = 1;
494 info->block_size = volume_info.ulBytesPerAllocationUnit;
495 info->io_size = volume_info.ulBytesPerAllocationUnit;
496 info->total_blocks = volume_info.ullTotalAllocationBytes / info->block_size;
497 info->free_blocks = volume_info.ullAvailableAllocationBytes / info->block_size;
498 info->total_nodes = LONGLONG_MAX;
499 info->free_nodes = LONGLONG_MAX;
500 strcpy(info->volume_name, "VBox share");
501 return B_OK;
502}
503
504
505status_t vboxsf_lookup(fs_volume* _volume, fs_vnode* dir, const char* name, ino_t* _id)
506{
507 dprintf(FS_NAME ": lookup %s\n", name);
508 vboxsf_volume* volume = _volume->private_volume;
509 SHFLCREATEPARMS params;
510
511 RT_ZERO(params);
512 params.Handle = SHFL_HANDLE_NIL;
513 params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
514
515 PSHFLSTRING path = build_path(dir->private_node, name);
516 if (!path)
517 {
518 dprintf(FS_NAME ": make_shflstring() failed\n");
519 return B_NO_MEMORY;
520 }
521
522 int rc = vboxCallCreate(&g_clientHandle, &volume->map, path, &params);
523 if (RT_SUCCESS(rc))
524 {
525 if (params.Result == SHFL_FILE_EXISTS)
526 {
527 vboxsf_vnode* vn;
528 status_t rv = vboxsf_new_vnode(&volume->map, path, path, &vn);
529 if (rv == B_OK)
530 {
531 *_id = vn->vnode;
532 rv = publish_vnode(_volume, vn->vnode, vn, &vboxsf_vnode_ops, mode_from_fmode(params.Info.Attr.fMode), 0);
533 }
534 return rv;
535 }
536 else
537 {
538 free(path);
539 return B_ENTRY_NOT_FOUND;
540 }
541 }
542 else
543 {
544 free(path);
545 dprintf(FS_NAME ": vboxCallCreate: %d\n", rc);
546 return vbox_err_to_haiku_err(rc);
547 }
548}
549
550
551mode_t mode_from_fmode(RTFMODE fMode)
552{
553 mode_t m = 0;
554
555 if (RTFS_IS_DIRECTORY(fMode))
556 m |= S_IFDIR;
557 else if (RTFS_IS_FILE(fMode))
558 m |= S_IFREG;
559 else if (RTFS_IS_FIFO(fMode))
560 m |= S_IFIFO;
561 else if (RTFS_IS_DEV_CHAR(fMode))
562 m |= S_IFCHR;
563 else if (RTFS_IS_DEV_BLOCK(fMode))
564 m |= S_IFBLK;
565 else if (RTFS_IS_SYMLINK(fMode))
566 m |= S_IFLNK;
567 else if (RTFS_IS_SOCKET(fMode))
568 m |= S_IFSOCK;
569
570 if (fMode & RTFS_UNIX_IRUSR)
571 m |= S_IRUSR;
572 if (fMode & RTFS_UNIX_IWUSR)
573 m |= S_IWUSR;
574 if (fMode & RTFS_UNIX_IXUSR)
575 m |= S_IXUSR;
576 if (fMode & RTFS_UNIX_IRGRP)
577 m |= S_IRGRP;
578 if (fMode & RTFS_UNIX_IWGRP)
579 m |= S_IWGRP;
580 if (fMode & RTFS_UNIX_IXGRP)
581 m |= S_IXGRP;
582 if (fMode & RTFS_UNIX_IROTH)
583 m |= S_IROTH;
584 if (fMode & RTFS_UNIX_IWOTH)
585 m |= S_IWOTH;
586 if (fMode & RTFS_UNIX_IXOTH)
587 m |= S_IXOTH;
588 if (fMode & RTFS_UNIX_ISUID)
589 m |= S_ISUID;
590 if (fMode & RTFS_UNIX_ISGID)
591 m |= S_ISGID;
592 if (fMode & RTFS_UNIX_ISTXT)
593 m |= S_ISVTX;
594
595 return m;
596}
597
598
599status_t vboxsf_open(fs_volume* _volume, fs_vnode* _vnode, int openMode, void** _cookie)
600{
601 vboxsf_volume* volume = _volume->private_volume;
602 vboxsf_vnode* vnode = _vnode->private_node;
603
604 dprintf(FS_NAME ": open %s (mode=%x)\n", vnode->path->String.utf8, openMode);
605
606 SHFLCREATEPARMS params;
607
608 RT_ZERO(params);
609 params.Handle = SHFL_HANDLE_NIL;
610
611 if (openMode & O_RDWR)
612 params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
613 else if (openMode & O_RDONLY)
614 params.CreateFlags |= SHFL_CF_ACCESS_READ;
615 else if (openMode & O_WRONLY)
616 params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
617
618 if (openMode & O_APPEND)
619 params.CreateFlags |= SHFL_CF_ACCESS_APPEND;
620
621 if (openMode & O_CREAT)
622 {
623 params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW;
624 if (openMode & O_EXCL)
625 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS;
626 else if (openMode & O_TRUNC)
627 params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
628 else
629 params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
630 }
631 else
632 {
633 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
634 if (openMode & O_TRUNC)
635 params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
636 else
637 params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
638 }
639
640 int rc = vboxCallCreate(&g_clientHandle, &volume->map, vnode->path, &params);
641 if (!RT_SUCCESS(rc))
642 {
643 dprintf("vboxCallCreate returned %d\n", rc);
644 return vbox_err_to_haiku_err(rc);
645 }
646
647 vboxsf_file_cookie* cookie = malloc(sizeof(vboxsf_file_cookie));
648 if (!cookie)
649 {
650 dprintf("couldn't allocate file cookie\n");
651 return B_NO_MEMORY;
652 }
653
654 cookie->handle = params.Handle;
655 cookie->path = vnode->path;
656
657 *_cookie = cookie;
658
659 return B_OK;
660}
661
662
663status_t vboxsf_create(fs_volume* _volume, fs_vnode* _dir, const char *name, int openMode, int perms, void **_cookie, ino_t *_newVnodeID)
664{
665 vboxsf_volume* volume = _volume->private_volume;
666
667 SHFLCREATEPARMS params;
668
669 RT_ZERO(params);
670 params.Handle = SHFL_HANDLE_NIL;
671
672 if (openMode & O_RDWR)
673 params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
674 else if (openMode & O_RDONLY)
675 params.CreateFlags |= SHFL_CF_ACCESS_READ;
676 else if (openMode & O_WRONLY)
677 params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
678
679 if (openMode & O_APPEND)
680 params.CreateFlags |= SHFL_CF_ACCESS_APPEND;
681
682 if (openMode & O_CREAT)
683 {
684 params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW;
685 if (openMode & O_EXCL)
686 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS;
687 else if (openMode & O_TRUNC)
688 params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
689 else
690 params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
691 }
692 else
693 {
694 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
695 if (openMode & O_TRUNC)
696 params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
697 else
698 params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
699 }
700
701 PSHFLSTRING path = build_path(_dir->private_node, name);
702 int rc = vboxCallCreate(&g_clientHandle, &volume->map, path, &params);
703
704 if (!RT_SUCCESS(rc))
705 {
706 dprintf("vboxCallCreate returned %d\n", rc);
707 free(path);
708 return vbox_err_to_haiku_err(rc);
709 }
710
711 vboxsf_file_cookie* cookie = malloc(sizeof(vboxsf_file_cookie));
712 if (!cookie)
713 {
714 dprintf("couldn't allocate file cookie\n");
715 free(path);
716 return B_NO_MEMORY;
717 }
718
719 cookie->handle = params.Handle;
720 cookie->path = path;
721
722 *_cookie = cookie;
723 return vboxsf_lookup(_volume, _dir, name, _newVnodeID);
724}
725
726
727status_t vboxsf_close(fs_volume* _volume, fs_vnode* _vnode, void* _cookie)
728{
729 vboxsf_volume* volume = _volume->private_volume;
730 vboxsf_file_cookie* cookie = _cookie;
731
732 int rc = vboxCallClose(&g_clientHandle, &volume->map, cookie->handle);
733 dprintf("vboxCallClose returned %d\n", rc);
734 return vbox_err_to_haiku_err(rc);
735}
736
737
738status_t vboxsf_rewind_dir(fs_volume* _volume, fs_vnode* _vnode, void* _cookie)
739{
740 vboxsf_dir_cookie* cookie = _cookie;
741 cookie->index = 0;
742 return B_OK;
743}
744
745
746status_t vboxsf_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
747{
748 return B_OK;
749}
750
751
752status_t vboxsf_free_cookie(fs_volume *volume, fs_vnode *vnode, void *_cookie)
753{
754 vboxsf_dir_cookie* cookie = _cookie;
755 free(cookie);
756 return B_OK;
757}
758
759status_t vboxsf_read(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, void *buffer, size_t *length)
760{
761 vboxsf_volume* volume = _volume->private_volume;
762 vboxsf_vnode* vnode = _vnode->private_node;
763 vboxsf_file_cookie* cookie = _cookie;
764
765 if (*length > 0xFFFFFFFF)
766 *length = 0xFFFFFFFF;
767
768 uint32_t l = *length;
769 void* other_buffer = malloc(l); /* @todo map the user memory into kernel space here for efficiency */
770 int rc = vboxCallRead(&g_clientHandle, &volume->map, cookie->handle, pos, &l, other_buffer, false);
771 memcpy(buffer, other_buffer, l);
772 free(other_buffer);
773
774 dprintf("vboxCallRead returned %d\n", rc);
775 *length = l;
776 return vbox_err_to_haiku_err(rc);
777}
778
779
780status_t vboxsf_write(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, const void *buffer, size_t *length)
781{
782 vboxsf_volume* volume = _volume->private_volume;
783 vboxsf_vnode* vnode = _vnode->private_node;
784 vboxsf_file_cookie* cookie = _cookie;
785
786 if (*length > 0xFFFFFFFF)
787 *length = 0xFFFFFFFF;
788
789 uint32_t l = *length;
790 void* other_buffer = malloc(l); /* @todo map the user memory into kernel space here for efficiency */
791 memcpy(other_buffer, buffer, l);
792 int rc = vboxCallWrite(&g_clientHandle, &volume->map, cookie->handle, pos, &l, other_buffer, false);
793 free(other_buffer);
794
795 *length = l;
796 return vbox_err_to_haiku_err(rc);
797}
798
799
800status_t vboxsf_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, uint32 statMask)
801{
802 /* The host handles updating the stat info - in the guest, this is a no-op */
803 return B_OK;
804}
805
806
807status_t vboxsf_create_dir(fs_volume *_volume, fs_vnode *parent, const char *name, int perms)
808{
809 vboxsf_volume* volume = _volume->private_volume;
810
811 SHFLCREATEPARMS params;
812 params.Handle = 0;
813 params.Info.cbObject = 0;
814 params.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW |
815 SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READ;
816
817 PSHFLSTRING path = build_path(parent->private_node, name);
818 int rc = vboxCallCreate(&g_clientHandle, &volume->map, path, &params);
819 free(path);
820 /** @todo r=ramshankar: we should perhaps also check rc here and change
821 * Handle initialization from 0 to SHFL_HANDLE_NIL. */
822 if (params.Handle == SHFL_HANDLE_NIL)
823 return vbox_err_to_haiku_err(rc);
824 else
825 {
826 vboxCallClose(&g_clientHandle, &volume->map, params.Handle);
827 return B_OK;
828 }
829}
830
831
832status_t vboxsf_remove_dir(fs_volume *_volume, fs_vnode *parent, const char *name)
833{
834 vboxsf_volume* volume = _volume->private_volume;
835
836 PSHFLSTRING path = build_path(parent->private_node, name);
837 int rc = vboxCallRemove(&g_clientHandle, &volume->map, path, SHFL_REMOVE_DIR);
838 free(path);
839
840 return vbox_err_to_haiku_err(rc);
841}
842
843
844status_t vboxsf_unlink(fs_volume *_volume, fs_vnode *parent, const char *name)
845{
846 vboxsf_volume* volume = _volume->private_volume;
847
848 PSHFLSTRING path = build_path(parent->private_node, name);
849 int rc = vboxCallRemove(&g_clientHandle, &volume->map, path, SHFL_REMOVE_FILE);
850 free(path);
851
852 return vbox_err_to_haiku_err(rc);
853}
854
855status_t vboxsf_link(fs_volume *volume, fs_vnode *dir, const char *name, fs_vnode *vnode)
856{
857 return B_UNSUPPORTED;
858}
859
860
861status_t vboxsf_rename(fs_volume* _volume, fs_vnode* fromDir, const char* fromName, fs_vnode* toDir, const char* toName)
862{
863 vboxsf_volume* volume = _volume->private_volume;
864
865 PSHFLSTRING oldpath = build_path(fromDir->private_node, fromName);
866 PSHFLSTRING newpath = build_path(toDir->private_node, toName);
867 int rc = vboxCallRename(&g_clientHandle, &volume->map, oldpath, newpath, SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS);
868 free(oldpath);
869 free(newpath);
870
871 return vbox_err_to_haiku_err(rc);
872}
873
874
875status_t vboxsf_create_symlink(fs_volume* _volume, fs_vnode* dir, const char* name, const char* path, int mode)
876{
877 vboxsf_volume* volume = _volume->private_volume;
878
879 PSHFLSTRING target = make_shflstring(path);
880 PSHFLSTRING linkpath = build_path(dir->private_node, name);
881 SHFLFSOBJINFO stuff;
882 RT_ZERO(stuff);
883
884 int rc = vboxCallSymlink(&g_clientHandle, &volume->map, linkpath, target, &stuff);
885
886 free(target);
887 free(linkpath);
888
889 return vbox_err_to_haiku_err(rc);
890}
891
892
893status_t vboxsf_read_symlink(fs_volume* _volume, fs_vnode* link, char* buffer, size_t* _bufferSize)
894{
895 vboxsf_volume* volume = _volume->private_volume;
896 vboxsf_vnode* vnode = link->private_node;
897
898 int rc = vboxReadLink(&g_clientHandle, &volume->map, vnode->path, *_bufferSize, buffer);
899 *_bufferSize = strlen(buffer);
900
901 return vbox_err_to_haiku_err(rc);
902}
903
904
905/* @todo move this into the runtime */
906status_t vbox_err_to_haiku_err(int rc)
907{
908 switch (rc)
909 {
910 case VINF_SUCCESS: return B_OK;
911 case VERR_INVALID_POINTER: return B_BAD_ADDRESS;
912 case VERR_INVALID_PARAMETER: return B_BAD_VALUE;
913 case VERR_PERMISSION_DENIED: return B_PERMISSION_DENIED;
914 case VERR_NOT_IMPLEMENTED: return B_UNSUPPORTED;
915 case VERR_FILE_NOT_FOUND: return B_ENTRY_NOT_FOUND;
916
917 case SHFL_PATH_NOT_FOUND:
918 case SHFL_FILE_NOT_FOUND: return B_ENTRY_NOT_FOUND;
919 case SHFL_FILE_EXISTS: return B_FILE_EXISTS;
920
921 default:
922 return B_ERROR;
923 }
924}
925
926
927static status_t std_ops(int32 op, ...)
928{
929 switch(op)
930 {
931 case B_MODULE_INIT:
932 dprintf(MODULE_NAME ": B_MODULE_INIT\n");
933 return init_module();
934 case B_MODULE_UNINIT:
935 dprintf(MODULE_NAME ": B_MODULE_UNINIT\n");
936 uninit_module();
937 return B_OK;
938 default:
939 return B_ERROR;
940 }
941}
942
943
944static fs_volume_ops vboxsf_volume_ops =
945{
946 unmount,
947 vboxsf_read_fs_info,
948 NULL, /* write_fs_info */
949 NULL, /* sync */
950 vboxsf_get_vnode,
951 NULL, /* open_index_dir */
952 NULL, /* close_index_dir */
953 NULL, /* free_index_dir_cookie */
954 NULL, /* read_index_dir */
955 NULL, /* rewind_index_dir */
956 NULL, /* create_index */
957 NULL, /* remove_index */
958 NULL, /* read_index_stat */
959 NULL, /* open_query */
960 NULL, /* close_query */
961 NULL, /* free_query_cookie */
962 NULL, /* read_query */
963 NULL, /* rewind_query */
964 NULL, /* all_layers_mounted */
965 NULL, /* create_sub_vnode */
966 NULL, /* delete_sub_vnode */
967};
968
969static fs_vnode_ops vboxsf_vnode_ops =
970{
971 vboxsf_lookup,
972 NULL, /* get_vnode_name */
973 vboxsf_put_vnode,
974 NULL, /* remove_vnode */
975 NULL, /* can_page */
976 NULL, /* read_pages */
977 NULL, /* write_pages */
978 NULL, /* io */
979 NULL, /* cancel_io */
980 NULL, /* get_file_map */
981 NULL, /* ioctl */
982 NULL, /* set_flags */
983 NULL, /* select */
984 NULL, /* deselect */
985 NULL, /* fsync */
986 vboxsf_read_symlink,
987 vboxsf_create_symlink,
988 vboxsf_link,
989 vboxsf_unlink,
990 vboxsf_rename,
991 NULL, /* access */
992 vboxsf_read_stat,
993 vboxsf_write_stat,
994 NULL, /* preallocate */
995 vboxsf_create,
996 vboxsf_open,
997 vboxsf_close,
998 vboxsf_free_cookie,
999 vboxsf_read,
1000 vboxsf_write,
1001 vboxsf_create_dir,
1002 vboxsf_remove_dir,
1003 vboxsf_open_dir,
1004 vboxsf_close_dir,
1005 vboxsf_free_dir_cookie,
1006 vboxsf_read_dir,
1007 vboxsf_rewind_dir,
1008 NULL, /* open_attr_dir */
1009 NULL, /* close_attr_dir */
1010 NULL, /* free_attr_dir_cookie */
1011 NULL, /* read_attr_dir */
1012 NULL, /* rewind_attr_dir */
1013 NULL, /* create_attr */
1014 NULL, /* open_attr */
1015 NULL, /* close_attr */
1016 NULL, /* free_attr_cookie */
1017 NULL, /* read_attr */
1018 NULL, /* write_attr */
1019 NULL, /* read_attr_stat */
1020 NULL, /* write_attr_stat */
1021 NULL, /* rename_attr */
1022 NULL, /* remove_attr */
1023 NULL, /* create_special_node */
1024 NULL, /* get_super_vnode */
1025};
1026
1027static file_system_module_info sVBoxSharedFileSystem =
1028{
1029 {
1030 MODULE_NAME B_CURRENT_FS_API_VERSION,
1031 0,
1032 std_ops,
1033 },
1034 FS_NAME,
1035 FS_PRETTY_NAME,
1036 0, /* DDM flags */
1037 NULL, /* identify_partition */
1038 NULL, /* scan_partition */
1039 NULL, /* free_identify_partition_cookie */
1040 NULL, /* free_partition_content_cookie */
1041 mount,
1042};
1043
1044module_info *modules[] =
1045{
1046 (module_info *)&sVBoxSharedFileSystem,
1047 NULL,
1048};
1049
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