From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../Additions/haiku/SharedFolders/Makefile.kmk | 89 ++ .../Additions/haiku/SharedFolders/OpenHashTable.h | 515 ++++++++++ .../Additions/haiku/SharedFolders/kernel_cpp.h | 122 +++ src/VBox/Additions/haiku/SharedFolders/lock.h | 315 ++++++ src/VBox/Additions/haiku/SharedFolders/vboxsf.c | 1055 ++++++++++++++++++++ src/VBox/Additions/haiku/SharedFolders/vboxsf.h | 120 +++ .../Additions/haiku/SharedFolders/vnode_cache.cpp | 144 +++ 7 files changed, 2360 insertions(+) create mode 100644 src/VBox/Additions/haiku/SharedFolders/Makefile.kmk create mode 100644 src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h create mode 100644 src/VBox/Additions/haiku/SharedFolders/kernel_cpp.h create mode 100644 src/VBox/Additions/haiku/SharedFolders/lock.h create mode 100644 src/VBox/Additions/haiku/SharedFolders/vboxsf.c create mode 100644 src/VBox/Additions/haiku/SharedFolders/vboxsf.h create mode 100644 src/VBox/Additions/haiku/SharedFolders/vnode_cache.cpp (limited to 'src/VBox/Additions/haiku/SharedFolders') diff --git a/src/VBox/Additions/haiku/SharedFolders/Makefile.kmk b/src/VBox/Additions/haiku/SharedFolders/Makefile.kmk new file mode 100644 index 00000000..daa5d002 --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/Makefile.kmk @@ -0,0 +1,89 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for shared folders, Haiku Guest Additions. +# + +# +# Copyright (C) 2012-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# SPDX-License-Identifier: GPL-3.0-only +# + +# +# This code is based on: +# +# VirtualBox Guest Additions for Haiku. +# Copyright (c) 2011 Mike Smith +# François Revol +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +ifdef VBOX_WITH_ADDITION_DRIVERS + SYSMODS += vboxsf +endif + +# +# Populate FILES_VBOXSF_NOBIN +# +#include $(PATH_SUB_CURRENT)/files_vboxsf + +# +# The module (for syntax checking). +# The DEBUG_HASH* stuff is for CONFIG_DYNAMIC_DEBUG-enabled kernels +# +vboxsf_TEMPLATE = VBoxGuestR0Drv +vboxsf_DEFS = \ + MODULE IN_RT_R0 VBOXGUEST VBOX_WITH_HGCM \ + KBUILD_MODNAME=KBUILD_STR\(vboxsf\) \ + KBUILD_BASENAME=KBUILD_STR\(vboxsf\) +vboxsf_INCS = \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest \ + $(PATH_ROOT)/src/VBox/Runtime/r0drv/haiku +vboxsf_SOURCES = \ + vboxsf.c \ + vnode_cache.cpp \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku-stubs.c +vboxsf_LIBS = \ + $(VBOX_LIB_VBGL_R0) + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h b/src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h new file mode 100644 index 00000000..ac01704d --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h @@ -0,0 +1,515 @@ +/* $Id: OpenHashTable.h $ */ +/** @file + * OpenHashTable, Haiku Guest Additions. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * + * Copyright 2007, Hugo Santos. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + +#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_OpenHashTable_h +#define GA_INCLUDED_SRC_haiku_SharedFolders_OpenHashTable_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include +#include +#include + +#ifdef _KERNEL_MODE +# include +# include "kernel_cpp.h" +#endif + +/*! + The Definition template must have four methods: `HashKey', `Hash', + `Compare' and `GetLink;. It must also define several types as shown in the + following example: + + struct Foo { + int bar; + + Foo* fNext; + }; + + struct HashTableDefinition { + typedef int KeyType; + typedef Foo ValueType; + + size_t HashKey(int key) const + { + return key >> 1; + } + + size_t Hash(Foo* value) const + { + return HashKey(value->bar); + } + + bool Compare(int key, Foo* value) const + { + return value->bar == key; + } + + Foo*& GetLink(Foo* value) const + { + return value->fNext; + } + }; +*/ + + +struct MallocAllocator +{ + void* Allocate(size_t size) const + { + return malloc(size); + } + + void Free(void* memory) const + { + free(memory); + } +}; + + +template +class BOpenHashTable +{ +public: + typedef BOpenHashTable HashTable; + typedef typename Definition::KeyType KeyType; + typedef typename Definition::ValueType ValueType; + + static const size_t kMinimumSize = 8; + + // All allocations are of power of 2 lengths. + + // regrowth factor: 200 / 256 = 78.125% + // 50 / 256 = 19.53125% + + BOpenHashTable() + : + fTableSize(0), + fItemCount(0), + fTable(NULL) + { + } + + BOpenHashTable(const Definition& definition) + : + fDefinition(definition), + fTableSize(0), + fItemCount(0), + fTable(NULL) + { + } + + BOpenHashTable(const Definition& definition, const Allocator& allocator) + : + fDefinition(definition), + fAllocator(allocator), + fTableSize(0), + fItemCount(0), + fTable(NULL) + { + } + + ~BOpenHashTable() + { + fAllocator.Free(fTable); + } + + status_t Init(size_t initialSize = kMinimumSize) + { + if (initialSize > 0 && !_Resize(initialSize)) + return B_NO_MEMORY; + return B_OK; + } + + size_t TableSize() const + { + return fTableSize; + } + + size_t CountElements() const + { + return fItemCount; + } + + ValueType* Lookup(const KeyType& key) const + { + if (fTableSize == 0) + return NULL; + + size_t index = fDefinition.HashKey(key) & (fTableSize - 1); + ValueType* slot = fTable[index]; + + while (slot) + { + if (fDefinition.Compare(key, slot)) + break; + slot = _Link(slot); + } + + return slot; + } + + status_t Insert(ValueType* value) + { + if (fTableSize == 0) + { + if (!_Resize(kMinimumSize)) + return B_NO_MEMORY; + } + else if (AutoExpand && fItemCount >= (fTableSize * 200 / 256)) + _Resize(fTableSize * 2); + + InsertUnchecked(value); + return B_OK; + } + + void InsertUnchecked(ValueType* value) + { + if (CheckDuplicates && _ExhaustiveSearch(value)) + { +#ifdef _KERNEL_MODE + panic("Hash Table: value already in table."); +#else + debugger("Hash Table: value already in table."); +#endif + } + + _Insert(fTable, fTableSize, value); + fItemCount++; + } + + // TODO: a ValueType* Remove(const KeyType& key) method is missing + + bool Remove(ValueType* value) + { + if (!RemoveUnchecked(value)) + return false; + + if (AutoExpand && fTableSize > kMinimumSize + && fItemCount < (fTableSize * 50 / 256)) + _Resize(fTableSize / 2); + + return true; + } + + bool RemoveUnchecked(ValueType* value) + { + size_t index = fDefinition.Hash(value) & (fTableSize - 1); + ValueType* previous = NULL; + ValueType* slot = fTable[index]; + + while (slot) + { + ValueType* next = _Link(slot); + + if (value == slot) + { + if (previous) + _Link(previous) = next; + else + fTable[index] = next; + break; + } + + previous = slot; + slot = next; + } + + if (slot == NULL) + return false; + + if (CheckDuplicates && _ExhaustiveSearch(value)) + { +#ifdef _KERNEL_MODE + panic("Hash Table: duplicate detected."); +#else + debugger("Hash Table: duplicate detected."); +#endif + } + + fItemCount--; + return true; + } + + /*! Removes all elements from the hash table. No resizing happens. The + elements are not deleted. If \a returnElements is \c true, the method + returns all elements chained via their hash table link. + */ + ValueType* Clear(bool returnElements = false) + { + if (this->fItemCount == 0) + return NULL; + + ValueType* result = NULL; + + if (returnElements) + { + ValueType** nextPointer = &result; + + // iterate through all buckets + for (size_t i = 0; i < fTableSize; i++) + { + ValueType* element = fTable[i]; + if (element != NULL) + { + // add the bucket to the list + *nextPointer = element; + + // update nextPointer to point to the fNext of the last + // element in the bucket + while (element != NULL) + { + nextPointer = &_Link(element); + element = *nextPointer; + } + } + } + } + + memset(this->fTable, 0, sizeof(ValueType*) * this->fTableSize); + + return result; + } + + /*! If the table needs resizing, the number of bytes for the required + allocation is returned. If no resizing is needed, 0 is returned. + */ + size_t ResizeNeeded() const + { + size_t size = fTableSize; + if (size == 0 || fItemCount >= (size * 200 / 256)) + { + // grow table + if (size == 0) + size = kMinimumSize; + while (fItemCount >= size * 200 / 256) + size <<= 1; + } + else if (size > kMinimumSize && fItemCount < size * 50 / 256) + { + // shrink table + while (fItemCount < size * 50 / 256) + size >>= 1; + if (size < kMinimumSize) + size = kMinimumSize; + } + + if (size == fTableSize) + return 0; + + return size * sizeof(ValueType*); + } + + /*! Resizes the table using the given allocation. The allocation must not + be \c NULL. It must be of size \a size, which must a value returned + earlier by ResizeNeeded(). If the size requirements have changed in the + meantime, the method free()s the given allocation and returns \c false, + unless \a force is \c true, in which case the supplied allocation is + used in any event. + Otherwise \c true is returned. + If \a oldTable is non-null and resizing is successful, the old table + will not be freed, but will be returned via this parameter instead. + */ + bool Resize(void* allocation, size_t size, bool force = false, + void** oldTable = NULL) + { + if (!force && size != ResizeNeeded()) + { + fAllocator.Free(allocation); + return false; + } + + _Resize((ValueType**)allocation, size / sizeof(ValueType*), oldTable); + return true; + } + + class Iterator + { + public: + Iterator(const HashTable* table) + : fTable(table) + { + Rewind(); + } + + Iterator(const HashTable* table, size_t index, ValueType* value) + : fTable(table), fIndex(index), fNext(value) {} + + bool HasNext() const { return fNext != NULL; } + + ValueType* Next() + { + ValueType* current = fNext; + _GetNext(); + return current; + } + + void Rewind() + { + // get the first one + fIndex = 0; + fNext = NULL; + _GetNext(); + } + + protected: + Iterator() {} + + void _GetNext() + { + if (fNext) + fNext = fTable->_Link(fNext); + + while (fNext == NULL && fIndex < fTable->fTableSize) + fNext = fTable->fTable[fIndex++]; + } + + const HashTable* fTable; + size_t fIndex; + ValueType* fNext; + }; + + Iterator GetIterator() const + { + return Iterator(this); + } + + Iterator GetIterator(const KeyType& key) const + { + if (fTableSize == 0) + return Iterator(this, fTableSize, NULL); + + size_t index = fDefinition.HashKey(key) & (fTableSize - 1); + ValueType* slot = fTable[index]; + + while (slot) + { + if (fDefinition.Compare(key, slot)) + break; + slot = _Link(slot); + } + + if (slot == NULL) + return Iterator(this, fTableSize, NULL); + + return Iterator(this, index + 1, slot); + } + +protected: + // for g++ 2.95 + friend class Iterator; + + void _Insert(ValueType** table, size_t tableSize, ValueType* value) + { + size_t index = fDefinition.Hash(value) & (tableSize - 1); + + _Link(value) = table[index]; + table[index] = value; + } + + bool _Resize(size_t newSize) + { + ValueType** newTable + = (ValueType**)fAllocator.Allocate(sizeof(ValueType*) * newSize); + if (newTable == NULL) + return false; + + _Resize(newTable, newSize); + return true; + } + + void _Resize(ValueType** newTable, size_t newSize, void** _oldTable = NULL) + { + for (size_t i = 0; i < newSize; i++) + newTable[i] = NULL; + + if (fTable) + { + for (size_t i = 0; i < fTableSize; i++) + { + ValueType* bucket = fTable[i]; + while (bucket) + { + ValueType* next = _Link(bucket); + _Insert(newTable, newSize, bucket); + bucket = next; + } + } + + if (_oldTable != NULL) + *_oldTable = fTable; + else + fAllocator.Free(fTable); + } + else if (_oldTable != NULL) + *_oldTable = NULL; + + fTableSize = newSize; + fTable = newTable; + } + + ValueType*& _Link(ValueType* bucket) const + { + return fDefinition.GetLink(bucket); + } + + bool _ExhaustiveSearch(ValueType* value) const + { + for (size_t i = 0; i < fTableSize; i++) + { + ValueType* bucket = fTable[i]; + while (bucket) { + if (bucket == value) + return true; + bucket = _Link(bucket); + } + } + + return false; + } + + Definition fDefinition; + Allocator fAllocator; + size_t fTableSize; + size_t fItemCount; + ValueType** fTable; +}; + +#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_OpenHashTable_h */ + diff --git a/src/VBox/Additions/haiku/SharedFolders/kernel_cpp.h b/src/VBox/Additions/haiku/SharedFolders/kernel_cpp.h new file mode 100644 index 00000000..7cc3093f --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/kernel_cpp.h @@ -0,0 +1,122 @@ +/* $Id: kernel_cpp.h $ */ +/** @file + * Kernel C++, Haiku private. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. C++ in the kernel. + * + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + +#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_kernel_cpp_h +#define GA_INCLUDED_SRC_haiku_SharedFolders_kernel_cpp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef __cplusplus + +#include +#include + +#if _KERNEL_MODE || _LOADER_MODE + +using namespace std; +extern const nothrow_t std::nothrow; + +// We need new() versions we can use when also linking against libgcc. +// std::nothrow can't be used since it's defined in both libgcc and +// kernel_cpp.cpp. +typedef struct {} mynothrow_t; +extern const mynothrow_t mynothrow; + + +inline void * +operator new(size_t size) throw (std::bad_alloc) +{ + // we don't actually throw any exceptions, but we have to + // keep the prototype as specified in , or else GCC 3 + // won't like us + return malloc(size); +} + + +inline void * +operator new[](size_t size) throw (std::bad_alloc) +{ + return malloc(size); +} + + +inline void * +operator new(size_t size, const std::nothrow_t &) throw () +{ + return malloc(size); +} + + +inline void * +operator new[](size_t size, const std::nothrow_t &) throw () +{ + return malloc(size); +} + + +inline void * +operator new(size_t size, const mynothrow_t &) throw () +{ + return malloc(size); +} + + +inline void * +operator new[](size_t size, const mynothrow_t &) throw () +{ + return malloc(size); +} + + +inline void +operator delete(void *ptr) throw () +{ + free(ptr); +} + + +inline void +operator delete[](void *ptr) throw () +{ + free(ptr); +} + +#endif // #if _KERNEL_MODE + +#endif // __cplusplus + +#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_kernel_cpp_h */ diff --git a/src/VBox/Additions/haiku/SharedFolders/lock.h b/src/VBox/Additions/haiku/SharedFolders/lock.h new file mode 100644 index 00000000..4bca6a3f --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/lock.h @@ -0,0 +1,315 @@ +/* $Id: lock.h $ */ +/** @file + * Lock.h - Haiku, private locking internals. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * + * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_lock_h +#define GA_INCLUDED_SRC_haiku_SharedFolders_lock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +struct mutex_waiter; + +typedef struct mutex { + const char* name; + struct mutex_waiter* waiters; +#if KDEBUG + thread_id holder; +#else + int32 count; + uint16 ignore_unlock_count; +#endif + uint8 flags; +} mutex; + +#define MUTEX_FLAG_CLONE_NAME 0x1 + + +typedef struct recursive_lock { + mutex lock; +#if !KDEBUG + thread_id holder; +#endif + int recursion; +} recursive_lock; + + +struct rw_lock_waiter; + +typedef struct rw_lock { + const char* name; + struct rw_lock_waiter* waiters; + thread_id holder; + vint32 count; + int32 owner_count; + int16 active_readers; + // Only > 0 while a writer is waiting: number + // of active readers when the first waiting + // writer started waiting. + int16 pending_readers; + // Number of readers that have already + // incremented "count", but have not yet started + // to wait at the time the last writer unlocked. + uint32 flags; +} rw_lock; + +#define RW_LOCK_WRITER_COUNT_BASE 0x10000 + +#define RW_LOCK_FLAG_CLONE_NAME 0x1 + + +#if KDEBUG +# define KDEBUG_RW_LOCK_DEBUG 0 + // Define to 1 if you want to use ASSERT_READ_LOCKED_RW_LOCK(). + // The rw_lock will just behave like a recursive locker then. +# define ASSERT_LOCKED_RECURSIVE(r) \ + { ASSERT(find_thread(NULL) == (r)->lock.holder); } +# define ASSERT_LOCKED_MUTEX(m) { ASSERT(find_thread(NULL) == (m)->holder); } +# define ASSERT_WRITE_LOCKED_RW_LOCK(l) \ + { ASSERT(find_thread(NULL) == (l)->holder); } +# if KDEBUG_RW_LOCK_DEBUG +# define ASSERT_READ_LOCKED_RW_LOCK(l) \ + { ASSERT(find_thread(NULL) == (l)->holder); } +# else +# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false) +# endif +#else +# define ASSERT_LOCKED_RECURSIVE(r) do {} while (false) +# define ASSERT_LOCKED_MUTEX(m) do {} while (false) +# define ASSERT_WRITE_LOCKED_RW_LOCK(m) do {} while (false) +# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false) +#endif + + +// static initializers +#if KDEBUG +# define MUTEX_INITIALIZER(name) { name, NULL, -1, 0 } +# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), 0 } +#else +# define MUTEX_INITIALIZER(name) { name, NULL, 0, 0, 0 } +# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), -1, 0 } +#endif + +#define RW_LOCK_INITIALIZER(name) { name, NULL, -1, 0, 0, 0 } + + +#if KDEBUG +# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->lock.holder) +#else +# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->holder) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +extern void recursive_lock_init(recursive_lock *lock, const char *name); + // name is *not* cloned nor freed in recursive_lock_destroy() +extern void recursive_lock_init_etc(recursive_lock *lock, const char *name, + uint32 flags); +extern void recursive_lock_destroy(recursive_lock *lock); +extern status_t recursive_lock_lock(recursive_lock *lock); +extern status_t recursive_lock_trylock(recursive_lock *lock); +extern void recursive_lock_unlock(recursive_lock *lock); +extern int32 recursive_lock_get_recursion(recursive_lock *lock); + +extern void rw_lock_init(rw_lock* lock, const char* name); + // name is *not* cloned nor freed in rw_lock_destroy() +extern void rw_lock_init_etc(rw_lock* lock, const char* name, uint32 flags); +extern void rw_lock_destroy(rw_lock* lock); +extern status_t rw_lock_write_lock(rw_lock* lock); + +extern void mutex_init(mutex* lock, const char* name); + // name is *not* cloned nor freed in mutex_destroy() +extern void mutex_init_etc(mutex* lock, const char* name, uint32 flags); +extern void mutex_destroy(mutex* lock); +extern status_t mutex_switch_lock(mutex* from, mutex* to); + // Unlocks "from" and locks "to" such that unlocking and starting to wait + // for the lock is atomically. I.e. if "from" guards the object "to" belongs + // to, the operation is safe as long as "from" is held while destroying + // "to". +extern status_t mutex_switch_from_read_lock(rw_lock* from, mutex* to); + // Like mutex_switch_lock(), just for a switching from a read-locked + // rw_lock. + + +// implementation private: + +extern status_t _rw_lock_read_lock(rw_lock* lock); +extern status_t _rw_lock_read_lock_with_timeout(rw_lock* lock, + uint32 timeoutFlags, bigtime_t timeout); +extern void _rw_lock_read_unlock(rw_lock* lock, bool threadsLocked); +extern void _rw_lock_write_unlock(rw_lock* lock, bool threadsLocked); + +extern status_t _mutex_lock(mutex* lock, bool threadsLocked); +extern void _mutex_unlock(mutex* lock, bool threadsLocked); +extern status_t _mutex_trylock(mutex* lock); +extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, + bigtime_t timeout); + + +static inline status_t +rw_lock_read_lock(rw_lock* lock) +{ +#if KDEBUG_RW_LOCK_DEBUG + return rw_lock_write_lock(lock); +#else + int32 oldCount = atomic_add(&lock->count, 1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + return _rw_lock_read_lock(lock); + return B_OK; +#endif +} + + +static inline status_t +rw_lock_read_lock_with_timeout(rw_lock* lock, uint32 timeoutFlags, + bigtime_t timeout) +{ +#if KDEBUG_RW_LOCK_DEBUG + return mutex_lock_with_timeout(lock, timeoutFlags, timeout); +#else + int32 oldCount = atomic_add(&lock->count, 1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + return _rw_lock_read_lock_with_timeout(lock, timeoutFlags, timeout); + return B_OK; +#endif +} + + +static inline void +rw_lock_read_unlock(rw_lock* lock) +{ +#if KDEBUG_RW_LOCK_DEBUG + rw_lock_write_unlock(lock); +#else + int32 oldCount = atomic_add(&lock->count, -1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + _rw_lock_read_unlock(lock, false); +#endif +} + + +static inline void +rw_lock_write_unlock(rw_lock* lock) +{ + _rw_lock_write_unlock(lock, false); +} + + +static inline status_t +mutex_lock(mutex* lock) +{ +#if KDEBUG + return _mutex_lock(lock, false); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock(lock, false); + return B_OK; +#endif +} + + +static inline status_t +mutex_lock_threads_locked(mutex* lock) +{ +#if KDEBUG + return _mutex_lock(lock, true); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock(lock, true); + return B_OK; +#endif +} + + +static inline status_t +mutex_trylock(mutex* lock) +{ +#if KDEBUG + return _mutex_trylock(lock); +#else + if (atomic_test_and_set(&lock->count, -1, 0) != 0) + return B_WOULD_BLOCK; + return B_OK; +#endif +} + + +static inline status_t +mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout) +{ +#if KDEBUG + return _mutex_lock_with_timeout(lock, timeoutFlags, timeout); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock_with_timeout(lock, timeoutFlags, timeout); + return B_OK; +#endif +} + + +static inline void +mutex_unlock(mutex* lock) +{ +#if !KDEBUG + if (atomic_add(&lock->count, 1) < -1) +#endif + _mutex_unlock(lock, false); +} + + +static inline void +mutex_transfer_lock(mutex* lock, thread_id thread) +{ +#if KDEBUG + lock->holder = thread; +#endif +} + + +extern void lock_debug_init(); + +#ifdef __cplusplus +} +#endif + +#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_lock_h */ diff --git a/src/VBox/Additions/haiku/SharedFolders/vboxsf.c b/src/VBox/Additions/haiku/SharedFolders/vboxsf.c new file mode 100644 index 00000000..26182d42 --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/vboxsf.c @@ -0,0 +1,1055 @@ +/* $Id: vboxsf.c $ */ +/** @file + * Shared folders - Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "vboxsf.h" + +#define MODULE_NAME "file_systems/vboxsf" +#define FS_NAME "vboxsf" +#define FS_PRETTY_NAME "VirtualBox Shared Folders" + +VBGLSFCLIENT g_clientHandle; +static fs_volume_ops vboxsf_volume_ops; +static fs_vnode_ops vboxsf_vnode_ops; + +status_t init_module(void) +{ +#if 0 + /** @todo enable this soon */ + int rc = get_module(VBOXGUEST_MODULE_NAME, (module_info **)&g_VBoxGuest); + if (RT_LIKELY(rc == B_OK) + { + rc = VbglR0SfInit(); + if (RT_SUCCESS(rc)) + { + rc = VbglR0SfConnect(&g_clientHandle); + if (RT_SUCCESS(rc)) + { + rc = VbglR0SfSetUtf8(&g_clientHandle); + if (RT_SUCCESS(rc)) + { + rc = VbglR0SfSetSymlinks(&g_clientHandle); + if (RT_FAILURE(rc)) + LogRel((FS_NAME ": Warning! VbglR0SfSetSymlinks failed (rc=%d) - symlink will appear as copies.\n", rc)); + + mutex_init(&g_vnodeCacheLock, "vboxsf vnode cache lock"); + Log((FS_NAME ": init_module succeeded.\n"); + return B_OK; + } + else + LogRel((FS_NAME ": VbglR0SfSetUtf8 failed. rc=%d\n", rc)); + } + else + LogRel((FS_NAME ": VbglR0SfConnect failed. rc=%d\n", rc)); + } + else + LogRel((FS_NAME ": VbglR0SfInit failed. rc=%d\n", rc)); + } + else + LogRel((FS_NAME ": get_module failed for '%s'. rc=%d\n", VBOXGUEST_MODULE_NAME, rc)); + + return B_ERROR; +#endif + + if (get_module(VBOXGUEST_MODULE_NAME, (module_info **)&g_VBoxGuest) != B_OK) + { + dprintf("get_module(%s) failed\n", VBOXGUEST_MODULE_NAME); + return B_ERROR; + } + + if (RT_FAILURE(VbglR0SfInit())) + { + dprintf("VbglR0SfInit failed\n"); + return B_ERROR; + } + + if (RT_FAILURE(VbglR0SfConnect(&g_clientHandle))) + { + dprintf("VbglR0SfConnect failed\n"); + return B_ERROR; + } + + if (RT_FAILURE(VbglR0SfSetUtf8(&g_clientHandle))) + { + dprintf("VbglR0SfSetUtf8 failed\n"); + return B_ERROR; + } + + if (RT_FAILURE(VbglR0SfSetSymlinks(&g_clientHandle))) + { + dprintf("warning: VbglR0SfSetSymlinks failed (old vbox?) - symlinks will appear as copies\n"); + } + + mutex_init(&g_vnodeCacheLock, "vboxsf vnode cache lock"); + + dprintf(FS_NAME ": inited successfully\n"); + return B_OK; +} + +void uninit_module(void) +{ + mutex_destroy(&g_vnodeCacheLock); + put_module(VBOXGUEST_MODULE_NAME); +} + + +PSHFLSTRING make_shflstring(const char* const s) +{ + int len = strlen(s); + if (len > 0xFFFE) + { + dprintf(FS_NAME ": make_shflstring: string too long\n"); + return NULL; + } + + PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + len); + if (!rv) + return NULL; + + rv->u16Length = len; + rv->u16Size = len + 1; + strcpy(rv->String.utf8, s); + return rv; +} + + +PSHFLSTRING clone_shflstring(PSHFLSTRING s) +{ + PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s->u16Length); + if (rv) + memcpy(rv, s, sizeof(SHFLSTRING) + s->u16Length); + return rv; +} + +PSHFLSTRING concat_shflstring_cstr(PSHFLSTRING s1, const char* const s2) +{ + size_t s2len = strlen(s2); + PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s1->u16Length + s2len); + if (rv) + { + memcpy(rv, s1, sizeof(SHFLSTRING) + s1->u16Length); + strcat(rv->String.utf8, s2); + rv->u16Length += s2len; + rv->u16Size += s2len; + } + return rv; +} + + +PSHFLSTRING concat_cstr_shflstring(const char* const s1, PSHFLSTRING s2) +{ + size_t s1len = strlen(s1); + PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s1len + s2->u16Length); + if (rv) + { + strcpy(rv->String.utf8, s1); + strcat(rv->String.utf8, s2->String.utf8); + rv->u16Length = s1len + s2->u16Length; + rv->u16Size = rv->u16Length + 1; + } + return rv; +} + + +PSHFLSTRING build_path(vboxsf_vnode* dir, const char* const name) +{ + dprintf("*** build_path(%p, %p)\n", dir, name); + if (!dir || !name) + return NULL; + + size_t len = dir->path->u16Length + strlen(name) + 1; + PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + len); + if (rv) + { + strcpy(rv->String.utf8, dir->path->String.utf8); + strcat(rv->String.utf8, "/"); + strcat(rv->String.utf8, name); + rv->u16Length = len; + rv->u16Size = rv->u16Length + 1; + } + return rv; +} + + +status_t mount(fs_volume *volume, const char *device, uint32 flags, const char *args, ino_t *_rootVnodeID) +{ + if (device) + { + dprintf(FS_NAME ": trying to mount a real device as a vbox share is silly\n"); + return B_BAD_TYPE; + } + + dprintf(FS_NAME ": mount(%s)\n", args); + + PSHFLSTRING sharename = make_shflstring(args); + + vboxsf_volume* vbsfvolume = malloc(sizeof(vboxsf_volume)); + volume->private_volume = vbsfvolume; + int rv = VbglR0SfMapFolder(&g_clientHandle, sharename, &(vbsfvolume->map)); + free(sharename); + + if (rv == 0) + { + vboxsf_vnode* root_vnode; + + PSHFLSTRING name = make_shflstring(""); + if (!name) + { + dprintf(FS_NAME ": make_shflstring() failed\n"); + return B_NO_MEMORY; + } + + status_t rs = vboxsf_new_vnode(&vbsfvolume->map, name, name, &root_vnode); + dprintf(FS_NAME ": allocated %p (path=%p name=%p)\n", root_vnode, root_vnode->path, root_vnode->name); + + if (rs != B_OK) + { + dprintf(FS_NAME ": vboxsf_new_vnode() failed (%d)\n", (int)rs); + return rs; + } + + rs = publish_vnode(volume, root_vnode->vnode, root_vnode, &vboxsf_vnode_ops, S_IFDIR, 0); + dprintf(FS_NAME ": publish_vnode(): %d\n", (int)rs); + *_rootVnodeID = root_vnode->vnode; + volume->ops = &vboxsf_volume_ops; + return B_OK; + } + else + { + dprintf(FS_NAME ": VbglR0SfMapFolder failed (%d)\n", rv); + free(volume->private_volume); + return vbox_err_to_haiku_err(rv); + } +} + + +status_t unmount(fs_volume *volume) +{ + dprintf(FS_NAME ": unmount\n"); + VbglR0SfUnmapFolder(&g_clientHandle, volume->private_volume); + return B_OK; +} + + +status_t vboxsf_read_stat(fs_volume* _volume, fs_vnode* _vnode, struct stat* st) +{ + vboxsf_vnode* vnode = _vnode->private_node; + vboxsf_volume* volume = _volume->private_volume; + SHFLCREATEPARMS params; + int rc; + + dprintf("vboxsf_read_stat (_vnode=%p, vnode=%p, path=%p (%s))\n", _vnode, vnode, vnode->path->String.utf8, vnode->path->String.utf8); + + params.Handle = SHFL_HANDLE_NIL; + params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW; + dprintf("sf_stat: calling VbglR0SfCreate, file %s, flags %x\n", vnode->path->String.utf8, params.CreateFlags); + rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, ¶ms); + if (rc == VERR_INVALID_NAME) + { + /* this can happen for names like 'foo*' on a Windows host */ + return B_ENTRY_NOT_FOUND; + } + if (RT_FAILURE(rc)) + { + dprintf("VbglR0SfCreate: %d\n", params.Result); + return vbox_err_to_haiku_err(params.Result); + } + if (params.Result != SHFL_FILE_EXISTS) + { + dprintf("VbglR0SfCreate: %d\n", params.Result); + return B_ENTRY_NOT_FOUND; + } + + st->st_dev = 0; + st->st_ino = vnode->vnode; + st->st_mode = mode_from_fmode(params.Info.Attr.fMode); + st->st_nlink = 1; + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + st->st_size = params.Info.cbObject; + st->st_blksize = 1; + st->st_blocks = params.Info.cbAllocated; + st->st_atime = RTTimeSpecGetSeconds(¶ms.Info.AccessTime); + st->st_mtime = RTTimeSpecGetSeconds(¶ms.Info.ModificationTime); + st->st_ctime = RTTimeSpecGetSeconds(¶ms.Info.BirthTime); + return B_OK; +} + + +status_t vboxsf_open_dir(fs_volume* _volume, fs_vnode* _vnode, void** _cookie) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = _vnode->private_node; + SHFLCREATEPARMS params; + + RT_ZERO(params); + params.Handle = SHFL_HANDLE_NIL; + params.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ; + + int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, ¶ms); + if (RT_SUCCESS(rc)) + { + if (params.Result == SHFL_FILE_EXISTS && params.Handle != SHFL_HANDLE_NIL) + { + vboxsf_dir_cookie* cookie = malloc(sizeof(vboxsf_dir_cookie)); + *_cookie = cookie; + cookie->index = 0; + cookie->path = build_path(vnode, "*"); + cookie->handle = params.Handle; + cookie->has_more_files = true; + cookie->buffer_start = cookie->buffer = NULL; + cookie->buffer_length = cookie->num_files = 0; + return B_OK; + } + else + return B_ENTRY_NOT_FOUND; + } + else + { + dprintf(FS_NAME ": VbglR0SfCreate: %d\n", rc); + return vbox_err_to_haiku_err(rc); + } +} + + +/** read a single entry from a dir */ +status_t vboxsf_read_dir_1(vboxsf_volume* volume, vboxsf_vnode* vnode, vboxsf_dir_cookie* cookie, + struct dirent* buffer, size_t bufferSize) +{ + dprintf("%p, %d, %p\n", cookie, cookie->has_more_files, cookie->buffer); + if (!cookie->has_more_files) + return B_ENTRY_NOT_FOUND; + + if (!cookie->buffer) + { + cookie->buffer_length = 16384; + cookie->buffer_start = cookie->buffer = malloc(cookie->buffer_length); + + int rc = VbglR0SfDirInfo(&g_clientHandle, &volume->map, cookie->handle, cookie->path, 0, cookie->index, + &cookie->buffer_length, cookie->buffer, &cookie->num_files); + + if (rc != 0 && rc != VERR_NO_MORE_FILES) + { + dprintf(FS_NAME ": VbglR0SfDirInfo failed: %d\n", rc); + free(cookie->buffer_start); + cookie->buffer_start = NULL; + return vbox_err_to_haiku_err(rc); + } + + if (rc == VERR_NO_MORE_FILES) + { + free(cookie->buffer_start); + cookie->buffer_start = NULL; + cookie->has_more_files = false; + return B_ENTRY_NOT_FOUND; + } + } + + if (bufferSize <= sizeof(struct dirent) + cookie->buffer->name.u16Length) + { + dprintf("hit end of buffer\n"); + return B_BUFFER_OVERFLOW; + } + + PSHFLSTRING name1 = clone_shflstring(&cookie->buffer->name); + if (!name1) + { + dprintf(FS_NAME ": make_shflstring() failed\n"); + return B_NO_MEMORY; + } + + vboxsf_vnode* new_vnode; + int rv = vboxsf_new_vnode(&volume->map, build_path(vnode, name1->String.utf8), name1, &new_vnode); + if (rv != B_OK) + { + dprintf(FS_NAME ": vboxsf_new_vnode() failed\n"); + return rv; + } + + buffer->d_dev = 0; + buffer->d_pdev = 0; + buffer->d_ino = new_vnode->vnode; + buffer->d_pino = vnode->vnode; + buffer->d_reclen = sizeof(struct dirent) + cookie->buffer->name.u16Length; + strncpy(buffer->d_name, cookie->buffer->name.String.utf8, NAME_MAX); + + size_t size = offsetof(SHFLDIRINFO, name.String) + cookie->buffer->name.u16Size; + cookie->buffer = ((void*)cookie->buffer + size); + cookie->index++; + + if (cookie->index >= cookie->num_files) + { + // hit end of this buffer, next call will reallocate a new one + free(cookie->buffer_start); + cookie->buffer_start = cookie->buffer = NULL; + } + return B_OK; +} + + +status_t vboxsf_read_dir(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, + struct dirent* buffer, size_t bufferSize, uint32* _num) +{ + vboxsf_dir_cookie* cookie = _cookie; + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = _vnode->private_node; + uint32 num_read = 0; + status_t rv = B_OK; + + for (num_read = 0; num_read < *_num && cookie->has_more_files; num_read++) + { + rv = vboxsf_read_dir_1(volume, vnode, cookie, buffer, bufferSize); + if (rv == B_BUFFER_OVERFLOW || rv == B_ENTRY_NOT_FOUND) + { + // hit end of at least one of the buffers - not really an error + rv = B_OK; + break; + } + bufferSize -= buffer->d_reclen; + buffer = ((void*)(buffer)) + buffer->d_reclen; + } + + *_num = num_read; + return rv; +} + + +status_t vboxsf_free_dir_cookie(fs_volume* _volume, fs_vnode* vnode, void* _cookie) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_dir_cookie* cookie = _cookie; + + VbglR0SfClose(&g_clientHandle, &volume->map, cookie->handle); + free(cookie->path); + free(cookie); + + return B_OK; +} + + +status_t vboxsf_read_fs_info(fs_volume* _volume, struct fs_info* info) +{ + vboxsf_volume* volume = _volume->private_volume; + + SHFLVOLINFO volume_info; + uint32_t bytes = sizeof(SHFLVOLINFO); + + int rc = VbglR0SfFsInfo(&g_clientHandle, &volume->map, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME, + &bytes, (PSHFLDIRINFO)&volume_info); + if (RT_FAILURE(rc)) + { + dprintf(FS_NAME ": VbglR0SfFsInfo failed (%d)\n", rc); + return vbox_err_to_haiku_err(rc); + } + + info->flags = B_FS_IS_PERSISTENT; + if (volume_info.fsProperties.fReadOnly) + info->flags |= B_FS_IS_READONLY; + + info->dev = 0; + info->root = 1; + info->block_size = volume_info.ulBytesPerAllocationUnit; + info->io_size = volume_info.ulBytesPerAllocationUnit; + info->total_blocks = volume_info.ullTotalAllocationBytes / info->block_size; + info->free_blocks = volume_info.ullAvailableAllocationBytes / info->block_size; + info->total_nodes = LONGLONG_MAX; + info->free_nodes = LONGLONG_MAX; + strcpy(info->volume_name, "VBox share"); + return B_OK; +} + + +status_t vboxsf_lookup(fs_volume* _volume, fs_vnode* dir, const char* name, ino_t* _id) +{ + dprintf(FS_NAME ": lookup %s\n", name); + vboxsf_volume* volume = _volume->private_volume; + SHFLCREATEPARMS params; + + RT_ZERO(params); + params.Handle = SHFL_HANDLE_NIL; + params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW; + + PSHFLSTRING path = build_path(dir->private_node, name); + if (!path) + { + dprintf(FS_NAME ": make_shflstring() failed\n"); + return B_NO_MEMORY; + } + + int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, ¶ms); + if (RT_SUCCESS(rc)) + { + if (params.Result == SHFL_FILE_EXISTS) + { + vboxsf_vnode* vn; + status_t rv = vboxsf_new_vnode(&volume->map, path, path, &vn); + if (rv == B_OK) + { + *_id = vn->vnode; + rv = publish_vnode(_volume, vn->vnode, vn, &vboxsf_vnode_ops, mode_from_fmode(params.Info.Attr.fMode), 0); + } + return rv; + } + else + { + free(path); + return B_ENTRY_NOT_FOUND; + } + } + else + { + free(path); + dprintf(FS_NAME ": VbglR0SfCreate: %d\n", rc); + return vbox_err_to_haiku_err(rc); + } +} + + +mode_t mode_from_fmode(RTFMODE fMode) +{ + mode_t m = 0; + + if (RTFS_IS_DIRECTORY(fMode)) + m |= S_IFDIR; + else if (RTFS_IS_FILE(fMode)) + m |= S_IFREG; + else if (RTFS_IS_FIFO(fMode)) + m |= S_IFIFO; + else if (RTFS_IS_DEV_CHAR(fMode)) + m |= S_IFCHR; + else if (RTFS_IS_DEV_BLOCK(fMode)) + m |= S_IFBLK; + else if (RTFS_IS_SYMLINK(fMode)) + m |= S_IFLNK; + else if (RTFS_IS_SOCKET(fMode)) + m |= S_IFSOCK; + + if (fMode & RTFS_UNIX_IRUSR) + m |= S_IRUSR; + if (fMode & RTFS_UNIX_IWUSR) + m |= S_IWUSR; + if (fMode & RTFS_UNIX_IXUSR) + m |= S_IXUSR; + if (fMode & RTFS_UNIX_IRGRP) + m |= S_IRGRP; + if (fMode & RTFS_UNIX_IWGRP) + m |= S_IWGRP; + if (fMode & RTFS_UNIX_IXGRP) + m |= S_IXGRP; + if (fMode & RTFS_UNIX_IROTH) + m |= S_IROTH; + if (fMode & RTFS_UNIX_IWOTH) + m |= S_IWOTH; + if (fMode & RTFS_UNIX_IXOTH) + m |= S_IXOTH; + if (fMode & RTFS_UNIX_ISUID) + m |= S_ISUID; + if (fMode & RTFS_UNIX_ISGID) + m |= S_ISGID; + if (fMode & RTFS_UNIX_ISTXT) + m |= S_ISVTX; + + return m; +} + + +status_t vboxsf_open(fs_volume* _volume, fs_vnode* _vnode, int openMode, void** _cookie) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = _vnode->private_node; + + dprintf(FS_NAME ": open %s (mode=%x)\n", vnode->path->String.utf8, openMode); + + SHFLCREATEPARMS params; + + RT_ZERO(params); + params.Handle = SHFL_HANDLE_NIL; + + if (openMode & O_RDWR) + params.CreateFlags |= SHFL_CF_ACCESS_READWRITE; + else if (openMode & O_RDONLY) + params.CreateFlags |= SHFL_CF_ACCESS_READ; + else if (openMode & O_WRONLY) + params.CreateFlags |= SHFL_CF_ACCESS_WRITE; + + if (openMode & O_APPEND) + params.CreateFlags |= SHFL_CF_ACCESS_APPEND; + + if (openMode & O_CREAT) + { + params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW; + if (openMode & O_EXCL) + params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS; + else if (openMode & O_TRUNC) + params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; + else + params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS; + } + else + { + params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW; + if (openMode & O_TRUNC) + params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; + else + params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS; + } + + int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, ¶ms); + if (!RT_SUCCESS(rc)) + { + dprintf("VbglR0SfCreate returned %d\n", rc); + return vbox_err_to_haiku_err(rc); + } + + vboxsf_file_cookie* cookie = malloc(sizeof(vboxsf_file_cookie)); + if (!cookie) + { + dprintf("couldn't allocate file cookie\n"); + return B_NO_MEMORY; + } + + cookie->handle = params.Handle; + cookie->path = vnode->path; + + *_cookie = cookie; + + return B_OK; +} + + +status_t vboxsf_create(fs_volume* _volume, fs_vnode* _dir, const char *name, int openMode, int perms, void **_cookie, ino_t *_newVnodeID) +{ + vboxsf_volume* volume = _volume->private_volume; + + SHFLCREATEPARMS params; + + RT_ZERO(params); + params.Handle = SHFL_HANDLE_NIL; + + if (openMode & O_RDWR) + params.CreateFlags |= SHFL_CF_ACCESS_READWRITE; + else if (openMode & O_RDONLY) + params.CreateFlags |= SHFL_CF_ACCESS_READ; + else if (openMode & O_WRONLY) + params.CreateFlags |= SHFL_CF_ACCESS_WRITE; + + if (openMode & O_APPEND) + params.CreateFlags |= SHFL_CF_ACCESS_APPEND; + + if (openMode & O_CREAT) + { + params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW; + if (openMode & O_EXCL) + params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS; + else if (openMode & O_TRUNC) + params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; + else + params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS; + } + else + { + params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW; + if (openMode & O_TRUNC) + params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; + else + params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS; + } + + PSHFLSTRING path = build_path(_dir->private_node, name); + int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, ¶ms); + + if (!RT_SUCCESS(rc)) + { + dprintf("VbglR0SfCreate returned %d\n", rc); + free(path); + return vbox_err_to_haiku_err(rc); + } + + vboxsf_file_cookie* cookie = malloc(sizeof(vboxsf_file_cookie)); + if (!cookie) + { + dprintf("couldn't allocate file cookie\n"); + free(path); + return B_NO_MEMORY; + } + + cookie->handle = params.Handle; + cookie->path = path; + + *_cookie = cookie; + return vboxsf_lookup(_volume, _dir, name, _newVnodeID); +} + + +status_t vboxsf_close(fs_volume* _volume, fs_vnode* _vnode, void* _cookie) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_file_cookie* cookie = _cookie; + + int rc = VbglR0SfClose(&g_clientHandle, &volume->map, cookie->handle); + dprintf("VbglR0SfClose returned %d\n", rc); + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_rewind_dir(fs_volume* _volume, fs_vnode* _vnode, void* _cookie) +{ + vboxsf_dir_cookie* cookie = _cookie; + cookie->index = 0; + return B_OK; +} + + +status_t vboxsf_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + return B_OK; +} + + +status_t vboxsf_free_cookie(fs_volume *volume, fs_vnode *vnode, void *_cookie) +{ + vboxsf_dir_cookie* cookie = _cookie; + free(cookie); + return B_OK; +} + +status_t vboxsf_read(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, void *buffer, size_t *length) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = _vnode->private_node; + vboxsf_file_cookie* cookie = _cookie; + + if (*length > 0xFFFFFFFF) + *length = 0xFFFFFFFF; + + uint32_t l = *length; + void* other_buffer = malloc(l); /** @todo map the user memory into kernel space here for efficiency */ + int rc = VbglR0SfRead(&g_clientHandle, &volume->map, cookie->handle, pos, &l, other_buffer, false /*fLocked*/); + memcpy(buffer, other_buffer, l); + free(other_buffer); + + dprintf("VbglR0SfRead returned %d\n", rc); + *length = l; + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_write(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, const void *buffer, size_t *length) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = _vnode->private_node; + vboxsf_file_cookie* cookie = _cookie; + + if (*length > 0xFFFFFFFF) + *length = 0xFFFFFFFF; + + uint32_t l = *length; + void* other_buffer = malloc(l); /** @todo map the user memory into kernel space here for efficiency */ + memcpy(other_buffer, buffer, l); + int rc = VbglR0SfWrite(&g_clientHandle, &volume->map, cookie->handle, pos, &l, other_buffer, false /*fLocked*/); + free(other_buffer); + + *length = l; + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, uint32 statMask) +{ + /* The host handles updating the stat info - in the guest, this is a no-op */ + return B_OK; +} + + +status_t vboxsf_create_dir(fs_volume *_volume, fs_vnode *parent, const char *name, int perms) +{ + vboxsf_volume* volume = _volume->private_volume; + + SHFLCREATEPARMS params; + params.Handle = 0; + params.Info.cbObject = 0; + params.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW | + SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READ; + + PSHFLSTRING path = build_path(parent->private_node, name); + int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, ¶ms); + free(path); + /** @todo r=ramshankar: we should perhaps also check rc here and change + * Handle initialization from 0 to SHFL_HANDLE_NIL. */ + if (params.Handle == SHFL_HANDLE_NIL) + return vbox_err_to_haiku_err(rc); + VbglR0SfClose(&g_clientHandle, &volume->map, params.Handle); + return B_OK; +} + + +status_t vboxsf_remove_dir(fs_volume *_volume, fs_vnode *parent, const char *name) +{ + vboxsf_volume* volume = _volume->private_volume; + + PSHFLSTRING path = build_path(parent->private_node, name); + int rc = VbglR0SfRemove(&g_clientHandle, &volume->map, path, SHFL_REMOVE_DIR); + free(path); + + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_unlink(fs_volume *_volume, fs_vnode *parent, const char *name) +{ + vboxsf_volume* volume = _volume->private_volume; + + PSHFLSTRING path = build_path(parent->private_node, name); + int rc = VbglR0SfRemove(&g_clientHandle, &volume->map, path, SHFL_REMOVE_FILE); + free(path); + + return vbox_err_to_haiku_err(rc); +} + +status_t vboxsf_link(fs_volume *volume, fs_vnode *dir, const char *name, fs_vnode *vnode) +{ + return B_UNSUPPORTED; +} + + +status_t vboxsf_rename(fs_volume* _volume, fs_vnode* fromDir, const char* fromName, fs_vnode* toDir, const char* toName) +{ + vboxsf_volume* volume = _volume->private_volume; + + PSHFLSTRING oldpath = build_path(fromDir->private_node, fromName); + PSHFLSTRING newpath = build_path(toDir->private_node, toName); + int rc = VbglR0SfRename(&g_clientHandle, &volume->map, oldpath, newpath, SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS); + free(oldpath); + free(newpath); + + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_create_symlink(fs_volume* _volume, fs_vnode* dir, const char* name, const char* path, int mode) +{ + vboxsf_volume* volume = _volume->private_volume; + + PSHFLSTRING target = make_shflstring(path); + PSHFLSTRING linkpath = build_path(dir->private_node, name); + SHFLFSOBJINFO stuff; + RT_ZERO(stuff); + + int rc = VbglR0SfSymlink(&g_clientHandle, &volume->map, linkpath, target, &stuff); + + free(target); + free(linkpath); + + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_read_symlink(fs_volume* _volume, fs_vnode* link, char* buffer, size_t* _bufferSize) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = link->private_node; + + int rc = VbglR0SfReadLink(&g_clientHandle, &volume->map, vnode->path, *_bufferSize, buffer); + *_bufferSize = strlen(buffer); + + return vbox_err_to_haiku_err(rc); +} + + +/** @todo move this into the runtime */ +status_t vbox_err_to_haiku_err(int rc) +{ + switch (rc) + { + case VINF_SUCCESS: return B_OK; + case VERR_INVALID_POINTER: return B_BAD_ADDRESS; + case VERR_INVALID_PARAMETER: return B_BAD_VALUE; + case VERR_PERMISSION_DENIED: return B_PERMISSION_DENIED; + case VERR_NOT_IMPLEMENTED: return B_UNSUPPORTED; + case VERR_FILE_NOT_FOUND: return B_ENTRY_NOT_FOUND; + + case SHFL_PATH_NOT_FOUND: + case SHFL_FILE_NOT_FOUND: return B_ENTRY_NOT_FOUND; + case SHFL_FILE_EXISTS: return B_FILE_EXISTS; + + default: + return B_ERROR; + } +} + + +static status_t std_ops(int32 op, ...) +{ + switch(op) + { + case B_MODULE_INIT: + dprintf(MODULE_NAME ": B_MODULE_INIT\n"); + return init_module(); + case B_MODULE_UNINIT: + dprintf(MODULE_NAME ": B_MODULE_UNINIT\n"); + uninit_module(); + return B_OK; + default: + return B_ERROR; + } +} + + +static fs_volume_ops vboxsf_volume_ops = +{ + unmount, + vboxsf_read_fs_info, + NULL, /* write_fs_info */ + NULL, /* sync */ + vboxsf_get_vnode, + NULL, /* open_index_dir */ + NULL, /* close_index_dir */ + NULL, /* free_index_dir_cookie */ + NULL, /* read_index_dir */ + NULL, /* rewind_index_dir */ + NULL, /* create_index */ + NULL, /* remove_index */ + NULL, /* read_index_stat */ + NULL, /* open_query */ + NULL, /* close_query */ + NULL, /* free_query_cookie */ + NULL, /* read_query */ + NULL, /* rewind_query */ + NULL, /* all_layers_mounted */ + NULL, /* create_sub_vnode */ + NULL, /* delete_sub_vnode */ +}; + +static fs_vnode_ops vboxsf_vnode_ops = +{ + vboxsf_lookup, + NULL, /* get_vnode_name */ + vboxsf_put_vnode, + NULL, /* remove_vnode */ + NULL, /* can_page */ + NULL, /* read_pages */ + NULL, /* write_pages */ + NULL, /* io */ + NULL, /* cancel_io */ + NULL, /* get_file_map */ + NULL, /* ioctl */ + NULL, /* set_flags */ + NULL, /* select */ + NULL, /* deselect */ + NULL, /* fsync */ + vboxsf_read_symlink, + vboxsf_create_symlink, + vboxsf_link, + vboxsf_unlink, + vboxsf_rename, + NULL, /* access */ + vboxsf_read_stat, + vboxsf_write_stat, + NULL, /* preallocate */ + vboxsf_create, + vboxsf_open, + vboxsf_close, + vboxsf_free_cookie, + vboxsf_read, + vboxsf_write, + vboxsf_create_dir, + vboxsf_remove_dir, + vboxsf_open_dir, + vboxsf_close_dir, + vboxsf_free_dir_cookie, + vboxsf_read_dir, + vboxsf_rewind_dir, + NULL, /* open_attr_dir */ + NULL, /* close_attr_dir */ + NULL, /* free_attr_dir_cookie */ + NULL, /* read_attr_dir */ + NULL, /* rewind_attr_dir */ + NULL, /* create_attr */ + NULL, /* open_attr */ + NULL, /* close_attr */ + NULL, /* free_attr_cookie */ + NULL, /* read_attr */ + NULL, /* write_attr */ + NULL, /* read_attr_stat */ + NULL, /* write_attr_stat */ + NULL, /* rename_attr */ + NULL, /* remove_attr */ + NULL, /* create_special_node */ + NULL, /* get_super_vnode */ +}; + +static file_system_module_info sVBoxSharedFileSystem = +{ + { + MODULE_NAME B_CURRENT_FS_API_VERSION, + 0, + std_ops, + }, + FS_NAME, + FS_PRETTY_NAME, + 0, /* DDM flags */ + NULL, /* identify_partition */ + NULL, /* scan_partition */ + NULL, /* free_identify_partition_cookie */ + NULL, /* free_partition_content_cookie */ + mount, +}; + +module_info *modules[] = +{ + (module_info *)&sVBoxSharedFileSystem, + NULL, +}; + diff --git a/src/VBox/Additions/haiku/SharedFolders/vboxsf.h b/src/VBox/Additions/haiku/SharedFolders/vboxsf.h new file mode 100644 index 00000000..d8449987 --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/vboxsf.h @@ -0,0 +1,120 @@ +/* $Id: vboxsf.h $ */ +/** @file + * Shared folders - Haiku Guest Additions, header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_vboxsf_h +#define GA_INCLUDED_SRC_haiku_SharedFolders_vboxsf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include "lock.h" + +typedef struct vboxsf_volume +{ + VBGLSFMAP map; + ino_t rootid; +} vboxsf_volume; + +typedef struct vboxsf_vnode +{ + PVBGLSFMAP map; + PSHFLSTRING name; + PSHFLSTRING path; + ino_t vnode; + struct vboxsf_vnode* next; +} vboxsf_vnode; + +typedef struct vboxsf_dir_cookie +{ + SHFLHANDLE handle; + PSHFLSTRING path; + uint32_t index; + bool has_more_files; + PSHFLDIRINFO buffer_start, buffer; + uint32_t buffer_length, num_files; +} vboxsf_dir_cookie; + +typedef struct vboxsf_file_cookie +{ + SHFLHANDLE handle; + PSHFLSTRING path; +} vboxsf_file_cookie; + +#ifdef __cplusplus +extern "C" { +#endif + +status_t vboxsf_new_vnode(PVBGLSFMAP map, PSHFLSTRING path, PSHFLSTRING name, vboxsf_vnode** p); +status_t vboxsf_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, uint32* _flags, bool reenter); +status_t vboxsf_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter); +PSHFLSTRING make_shflstring(const char* const s); +mode_t mode_from_fmode(RTFMODE fMode); +status_t vbox_err_to_haiku_err(int rc); +extern mutex g_vnodeCacheLock; + +#ifdef __cplusplus +} +#endif + +#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_vboxsf_h */ + diff --git a/src/VBox/Additions/haiku/SharedFolders/vnode_cache.cpp b/src/VBox/Additions/haiku/SharedFolders/vnode_cache.cpp new file mode 100644 index 00000000..05221606 --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/vnode_cache.cpp @@ -0,0 +1,144 @@ +/* $Id: vnode_cache.cpp $ */ +/** @file + * Shared folders - Haiku Guest Additions, vnode cache header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "vboxsf.h" +#include "OpenHashTable.h" + +struct HashTableDefinition +{ + typedef uint32 KeyType; + typedef vboxsf_vnode ValueType; + + size_t HashKey(uint32 key) const + { + return key; + } + + size_t Hash(vboxsf_vnode* value) const + { + return HashKey(value->vnode); + } + + bool Compare(uint32 key, vboxsf_vnode* value) const + { + return value->vnode == key; + } + + vboxsf_vnode*& GetLink(vboxsf_vnode* value) const + { + return value->next; + } +}; + +static BOpenHashTable g_cache; +static ino_t g_nextVnid = 1; +mutex g_vnodeCacheLock; + + +extern "C" status_t vboxsf_new_vnode(PVBSFMAP map, PSHFLSTRING path, PSHFLSTRING name, vboxsf_vnode** p) +{ + vboxsf_vnode* vn = (vboxsf_vnode*)malloc(sizeof(vboxsf_vnode)); + if (vn == NULL) + return B_NO_MEMORY; + + dprintf("creating new vnode at %p with path=%p (%s)\n", vn, path->String.utf8, path->String.utf8); + vn->map = map; + vn->path = path; + if (name) + vn->name = name; + else + { + const char* cname = strrchr((char*)path->String.utf8, '/'); + if (!cname) + vn->name = path; // no slash, assume this *is* the filename + else + vn->name = make_shflstring(cname); + } + + if (mutex_lock(&g_vnodeCacheLock) < B_OK) + { + free(vn); + return B_ERROR; + } + + vn->vnode = g_nextVnid++; + *p = vn; + dprintf("vboxsf: allocated %p (path=%p name=%p)\n", vn, vn->path, vn->name); + status_t rv = g_cache.Insert(vn); + + mutex_unlock(&g_vnodeCacheLock); + + return rv; +} + + +extern "C" status_t vboxsf_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, + int* _type, uint32* _flags, bool reenter) +{ + vboxsf_vnode* vn = g_cache.Lookup(id); + if (vn) + { + vnode->private_node = vn; + return B_OK; + } + return B_ERROR; +} + + +extern "C" status_t vboxsf_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) +{ + g_cache.Remove((vboxsf_vnode*)vnode->private_node); +} + -- cgit v1.2.3