From c41ac5b0e1433d84f8519d0c62f8d438f50a80a8 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Thu, 19 Feb 2009 23:01:42 +0000 Subject: [PATCH] * Remove the original overlay filesystem. * Add attribute_overlay and write_overlay to the image/floppy instead. * Mount a iso9660 boot volume with both write and attribute overlay for now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29261 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/jam/FloppyBootImage | 2 +- build/jam/HaikuImage | 3 +- .../kernel/file_systems/overlay/Jamfile | 7 - .../kernel/file_systems/overlay/overlay.cpp | 2291 ----------------- src/system/kernel/fs/vfs_boot.cpp | 2 +- 5 files changed, 4 insertions(+), 2301 deletions(-) delete mode 100644 src/add-ons/kernel/file_systems/overlay/Jamfile delete mode 100644 src/add-ons/kernel/file_systems/overlay/overlay.cpp diff --git a/build/jam/FloppyBootImage b/build/jam/FloppyBootImage index 34cf51113b..392e9b427d 100644 --- a/build/jam/FloppyBootImage +++ b/build/jam/FloppyBootImage @@ -33,7 +33,7 @@ BOOT_ADD_ONS_NET = BEOS_ADD_ONS_BUS_MANAGERS = pci $(X86_ONLY)isa ide scsi config_manager agp_gart usb ; -BEOS_ADD_ONS_FILE_SYSTEMS = bfs iso9660 overlay ; +BEOS_ADD_ONS_FILE_SYSTEMS = bfs iso9660 attribute_overlay write_overlay ; #cdda fat googlefs nfs ; diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index e17f14a098..6094129c17 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -138,7 +138,8 @@ BEOS_ADD_ONS_DRIVERS_NET = $(X86_ONLY)3com $(X86_ONLY)broadcom440x BEOS_ADD_ONS_BUS_MANAGERS = pci $(X86_ONLY)ps2 $(X86_ONLY)isa ide scsi config_manager agp_gart usb firewire $(X86_ONLY)acpi ; -BEOS_ADD_ONS_FILE_SYSTEMS = bfs cdda ext2 fat iso9660 nfs overlay $(GPL_ONLY)reiserfs ; +BEOS_ADD_ONS_FILE_SYSTEMS = bfs cdda ext2 fat iso9660 nfs attribute_overlay + write_overlay $(GPL_ONLY)reiserfs ; #googlefs $(GPL_ONLY)ntfs ; diff --git a/src/add-ons/kernel/file_systems/overlay/Jamfile b/src/add-ons/kernel/file_systems/overlay/Jamfile deleted file mode 100644 index 03d6eef089..0000000000 --- a/src/add-ons/kernel/file_systems/overlay/Jamfile +++ /dev/null @@ -1,7 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel file_systems overlay ; - -UsePrivateKernelHeaders ; - -KernelAddon overlay : - overlay.cpp - ; diff --git a/src/add-ons/kernel/file_systems/overlay/overlay.cpp b/src/add-ons/kernel/file_systems/overlay/overlay.cpp deleted file mode 100644 index cc7bdcc883..0000000000 --- a/src/add-ons/kernel/file_systems/overlay/overlay.cpp +++ /dev/null @@ -1,2291 +0,0 @@ -/* - * Copyright 2009, Haiku Inc. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Michael Lotz - */ - -#include -#include -#include - -#include - -#include - -#include -#include - -#include -#include -#include - - -//#define TRACE_OVERLAY -#ifdef TRACE_OVERLAY -#define TRACE(x...) dprintf("overlay: " x) -#define TRACE_VOLUME(x...) dprintf("overlay: " x) -#define TRACE_ALWAYS(x...) dprintf("overlay: " x) -#else -#define TRACE(x...) /* nothing */ -#define TRACE_VOLUME(x...) /* nothing */ -#define TRACE_ALWAYS(x...) dprintf("overlay: " x) -#endif - - -namespace overlay { - -class AttributeFile; -class AttributeEntry; - - -struct open_cookie { - int open_mode; - void * super_cookie; -}; - -struct write_buffer { - write_buffer * next; - off_t position; - size_t length; - uint8 buffer[1]; -}; - -struct attribute_dir_cookie { - AttributeFile * file; - uint32 index; -}; - - -class OverlayVolume { -public: - OverlayVolume(fs_volume *volume); - ~OverlayVolume(); - - status_t AllLayersMounted(); - - fs_volume * Volume() { return fVolume; } - fs_volume * SuperVolume() { return fVolume->super_volume; } - - bool WriteSupport() { return fWriteSupport; } - -private: - fs_volume * fVolume; - bool fWriteSupport; -}; - - -class OverlayInode { -public: - OverlayInode(OverlayVolume *volume, - fs_vnode *superVnode, ino_t inodeNumber); - ~OverlayInode(); - - status_t InitCheck(); - - fs_volume * Volume() { return fVolume->Volume(); } - fs_volume * SuperVolume() { return fVolume->SuperVolume(); } - fs_vnode * SuperVnode() { return &fSuperVnode; } - ino_t InodeNumber() { return fInodeNumber; } - - status_t GetAttributeFile(AttributeFile **attributeFile); - status_t WriteAttributeFile(); - - status_t ReadStat(struct stat *stat); - - status_t Open(int openMode, void **cookie); - status_t Close(void *cookie); - status_t FreeCookie(void *cookie); - status_t Read(void *cookie, off_t position, void *buffer, - size_t *length); - status_t Write(void *cookie, off_t position, - const void *buffer, size_t *length); - -private: - OverlayVolume * fVolume; - fs_vnode fSuperVnode; - ino_t fInodeNumber; - AttributeFile * fAttributeFile; - write_buffer * fWriteBuffers; - off_t fOriginalNodeLength; - off_t fCurrentNodeLength; - time_t fModificationTime; -}; - - -class AttributeFile { -public: - AttributeFile(fs_volume *overlay, fs_volume *volume, - fs_vnode *vnode); - ~AttributeFile(); - - status_t InitCheck() { return fStatus; } - - dev_t VolumeID() { return fVolumeID; } - ino_t FileInode() { return fFileInode; } - - status_t CreateEmpty(); - status_t WriteAttributeFile(fs_volume *overlay, - fs_volume *volume, fs_vnode *vnode); - - status_t ReadAttributeDir(struct dirent *dirent, - size_t bufferSize, uint32 *numEntries, - uint32 *index); - - uint32 CountAttributes(); - AttributeEntry * FindAttribute(const char *name, - uint32 *index = NULL); - - status_t CreateAttribute(const char *name, type_code type, - int openMode, AttributeEntry **entry); - status_t OpenAttribute(const char *name, int openMode, - AttributeEntry **entry); - status_t RemoveAttribute(const char *name, - AttributeEntry **entry); - status_t AddAttribute(AttributeEntry *entry); - -private: - #define ATTRIBUTE_OVERLAY_FILE_MAGIC 'attr' - #define ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME "_HAIKU" - - struct attribute_file { - uint32 magic; // 'attr' - uint32 entry_count; - uint8 entries[1]; - } _PACKED; - - status_t fStatus; - dev_t fVolumeID; - ino_t fFileInode; - ino_t fDirectoryInode; - ino_t fAttributeDirInode; - ino_t fAttributeFileInode; - attribute_file * fFile; - uint32 fAttributeDirIndex; - AttributeEntry ** fEntries; -}; - - -class AttributeEntry { -public: - AttributeEntry(AttributeFile *parent, - uint8 *buffer); - AttributeEntry(AttributeFile *parent, - const char *name, type_code type); - ~AttributeEntry(); - - status_t InitCheck() { return fStatus; } - - uint8 * Entry() { return (uint8 *)fEntry; } - size_t EntrySize(); - uint8 * Data() { return fData; } - size_t DataSize() { return fEntry->size; } - - status_t SetType(type_code type); - type_code Type() { return fEntry->type; } - - status_t SetSize(size_t size); - uint32 Size() { return fEntry->size; } - - status_t SetName(const char *name); - const char * Name() { return fEntry->name; } - uint8 NameLength() { return fEntry->name_length; } - - status_t FillDirent(struct dirent *dirent, - size_t bufferSize, uint32 *numEntries); - - status_t Read(off_t position, void *buffer, size_t *length); - status_t Write(off_t position, const void *buffer, - size_t *length); - - status_t ReadStat(struct stat *stat); - status_t WriteStat(const struct stat *stat, uint32 statMask); - -private: - struct attribute_entry { - type_code type; - uint32 size; - uint8 name_length; // including 0 byte - char name[1]; // 0 terminated, followed by data - } _PACKED; - - AttributeFile * fParent; - attribute_entry * fEntry; - uint8 * fData; - status_t fStatus; - bool fAllocatedEntry; - bool fAllocatedData; -}; - - -// #pragma mark OverlayVolume - - -OverlayVolume::OverlayVolume(fs_volume *volume) - : fVolume(volume), - fWriteSupport(false) -{ -} - - -OverlayVolume::~OverlayVolume() -{ -} - - -status_t -OverlayVolume::AllLayersMounted() -{ - fs_info info; - fs_volume *superVolume = fVolume->super_volume; - if (superVolume->ops->read_fs_info != NULL - && superVolume->ops->read_fs_info(superVolume, &info) == B_OK) - fWriteSupport = (info.flags & B_FS_IS_READONLY) != 0; - - return B_OK; -} - - -// #pragma mark OverlayInode - - -OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode, - ino_t inodeNumber) - : fVolume(volume), - fSuperVnode(*superVnode), - fInodeNumber(inodeNumber), - fAttributeFile(NULL), - fWriteBuffers(NULL), - fOriginalNodeLength(-1), - fCurrentNodeLength(-1) -{ - TRACE("inode created\n"); -} - - -OverlayInode::~OverlayInode() -{ - TRACE("inode destroyed\n"); - delete fAttributeFile; - - write_buffer *element = fWriteBuffers; - while (element) { - write_buffer *next = element->next; - free(element); - element = next; - } -} - - -status_t -OverlayInode::InitCheck() -{ - return B_OK; -} - - -status_t -OverlayInode::GetAttributeFile(AttributeFile **attributeFile) -{ - if (fAttributeFile == NULL) { - fAttributeFile = new(std::nothrow) AttributeFile(Volume(), - SuperVolume(), &fSuperVnode); - if (fAttributeFile == NULL) { - TRACE_ALWAYS("no memory to allocate attribute file\n"); - return B_NO_MEMORY; - } - } - - status_t result = fAttributeFile->InitCheck(); - if (result != B_OK) { - if (result == B_ENTRY_NOT_FOUND) { - // TODO: need to check if we're able to create the file - // but at least allow virtual attributes for now - } - - result = fAttributeFile->CreateEmpty(); - if (result != B_OK) - return result; - } - - *attributeFile = fAttributeFile; - return B_OK; -} - - -status_t -OverlayInode::WriteAttributeFile() -{ - if (fAttributeFile == NULL) - return B_NO_INIT; - - status_t result = fAttributeFile->InitCheck(); - if (result != B_OK) - return result; - - return fAttributeFile->WriteAttributeFile(Volume(), SuperVolume(), - &fSuperVnode); -} - - -status_t -OverlayInode::ReadStat(struct stat *stat) -{ - if (fSuperVnode.ops->read_stat == NULL) - return B_UNSUPPORTED; - - status_t result = fSuperVnode.ops->read_stat(SuperVolume(), &fSuperVnode, - stat); - if (result != B_OK) - return result; - - if (fVolume->WriteSupport() && fCurrentNodeLength >= 0) { - stat->st_size = fCurrentNodeLength; - stat->st_blocks = (stat->st_size + stat->st_blksize - 1) - / stat->st_blksize; - stat->st_mtime = fModificationTime; - } - - return B_OK; -} - - -status_t -OverlayInode::Open(int openMode, void **_cookie) -{ - if (fSuperVnode.ops->open == NULL) - return B_UNSUPPORTED; - - if (fVolume->WriteSupport()) { - open_cookie *cookie = (open_cookie *)malloc(sizeof(open_cookie)); - if (cookie == NULL) - return B_NO_MEMORY; - - if (fOriginalNodeLength < 0) { - struct stat stat; - status_t result = fSuperVnode.ops->read_stat(SuperVolume(), - &fSuperVnode, &stat); - if (result != B_OK) - return result; - - fOriginalNodeLength = stat.st_size; - fCurrentNodeLength = stat.st_size; - fModificationTime = stat.st_mtime; - } - - cookie->open_mode = openMode; - *_cookie = cookie; - - if (openMode & O_TRUNC) - fCurrentNodeLength = 0; - - openMode &= ~(O_RDWR | O_WRONLY | O_TRUNC | O_CREAT); - return fSuperVnode.ops->open(SuperVolume(), &fSuperVnode, openMode, - &cookie->super_cookie); - } - - return fSuperVnode.ops->open(SuperVolume(), &fSuperVnode, openMode, - _cookie); -} - - -status_t -OverlayInode::Close(void *_cookie) -{ - if (fVolume->WriteSupport()) { - open_cookie *cookie = (open_cookie *)_cookie; - return fSuperVnode.ops->close(SuperVolume(), &fSuperVnode, - cookie->super_cookie); - } - - return fSuperVnode.ops->close(SuperVolume(), &fSuperVnode, _cookie); -} - - -status_t -OverlayInode::FreeCookie(void *_cookie) -{ - if (fVolume->WriteSupport()) { - open_cookie *cookie = (open_cookie *)_cookie; - status_t result = fSuperVnode.ops->free_cookie(SuperVolume(), - &fSuperVnode, cookie->super_cookie); - free(cookie); - return result; - } - - return fSuperVnode.ops->free_cookie(SuperVolume(), &fSuperVnode, _cookie); -} - - -status_t -OverlayInode::Read(void *_cookie, off_t position, void *buffer, size_t *length) -{ - if (fVolume->WriteSupport()) { - if (position >= fCurrentNodeLength) { - *length = 0; - return B_OK; - } - - if (position < fOriginalNodeLength) { - open_cookie *cookie = (open_cookie *)_cookie; - size_t readLength = MIN(fOriginalNodeLength - position, *length); - status_t result = fSuperVnode.ops->read(SuperVolume(), &fSuperVnode, - cookie->super_cookie, position, buffer, &readLength); - if (result != B_OK) - return result; - } - - // overlay the read with whatever chunks we have written - write_buffer *element = fWriteBuffers; - *length = MIN(fCurrentNodeLength - position, *length); - off_t end = position + *length; - while (element) { - if (element->position > end) - break; - - off_t elementEnd = element->position + element->length; - if (elementEnd > position) { - off_t copyPosition = MAX(position, element->position); - size_t copyLength = MIN(elementEnd - position, *length); - memcpy((uint8 *)buffer + (copyPosition - position), - element->buffer + (copyPosition - element->position), - copyLength); - } - - element = element->next; - } - - return B_OK; - } - - return fSuperVnode.ops->read(SuperVolume(), &fSuperVnode, _cookie, - position, buffer, length); -} - - -status_t -OverlayInode::Write(void *_cookie, off_t position, const void *buffer, - size_t *length) -{ - if (fVolume->WriteSupport()) { - // find insertion point - write_buffer **link = &fWriteBuffers; - write_buffer *other = fWriteBuffers; - write_buffer *swallow = NULL; - off_t newPosition = position; - size_t newLength = *length; - uint32 swallowCount = 0; - - while (other) { - off_t newEnd = newPosition + newLength; - off_t otherEnd = other->position + other->length; - if (otherEnd < newPosition) { - // other is completely before us - link = &other->next; - other = other->next; - continue; - } - - if (other->position > newEnd) { - // other is completely past us - break; - } - - swallowCount++; - if (swallow == NULL) - swallow = other; - - if (other->position <= newPosition) { - if (swallowCount == 1 && otherEnd >= newEnd) { - // other chunk completely covers us, just copy - memcpy(other->buffer + (newPosition - other->position), - buffer, *length); - - fModificationTime = time(NULL); - notify_stat_changed(SuperVolume()->id, fInodeNumber, - B_STAT_MODIFICATION_TIME); - return B_OK; - } - - newLength += newPosition - other->position; - newPosition = other->position; - } - - if (otherEnd > newEnd) - newLength += otherEnd - newEnd; - - other = other->next; - } - - write_buffer *element = (write_buffer *)malloc(sizeof(write_buffer) - 1 - + newLength); - if (element == NULL) - return B_NO_MEMORY; - - element->next = *link; - element->position = newPosition; - element->length = newLength; - *link = element; - - bool sizeChanged = false; - off_t newEnd = newPosition + newLength; - if (newEnd > fCurrentNodeLength) { - fCurrentNodeLength = newEnd; - sizeChanged = true; - } - - // populate the buffer with the existing chunks - if (swallowCount > 0) { - while (swallowCount-- > 0) { - memcpy(element->buffer + (swallow->position - newPosition), - swallow->buffer, swallow->length); - - element->next = swallow->next; - free(swallow); - swallow = element->next; - } - } - - memcpy(element->buffer + (position - newPosition), buffer, *length); - - fModificationTime = time(NULL); - notify_stat_changed(SuperVolume()->id, fInodeNumber, - B_STAT_MODIFICATION_TIME | (sizeChanged ? B_STAT_SIZE : 0)); - - return B_OK; - } - - return fSuperVnode.ops->write(SuperVolume(), &fSuperVnode, _cookie, - position, buffer, length); -} - - -// #pragma mark AttributeFile - - -AttributeFile::AttributeFile(fs_volume *overlay, fs_volume *volume, - fs_vnode *vnode) - : fStatus(B_NO_INIT), - fVolumeID(volume->id), - fFileInode(0), - fDirectoryInode(0), - fAttributeDirInode(0), - fAttributeFileInode(0), - fFile(NULL), - fAttributeDirIndex(0), - fEntries(NULL) -{ - if (vnode->ops->get_vnode_name == NULL) { - TRACE_ALWAYS("cannot get vnode name, hook missing\n"); - fStatus = B_UNSUPPORTED; - return; - } - - char nameBuffer[B_FILE_NAME_LENGTH]; - nameBuffer[sizeof(nameBuffer) - 1] = 0; - fStatus = vnode->ops->get_vnode_name(volume, vnode, nameBuffer, - sizeof(nameBuffer) - 1); - if (fStatus != B_OK) { - TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(fStatus)); - return; - } - - if (strcmp(nameBuffer, ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) { - // we don't want attribute overlays on the attribute dir itself - fStatus = B_UNSUPPORTED; - return; - } - - struct stat stat; - if (vnode->ops->read_stat != NULL - && vnode->ops->read_stat(volume, vnode, &stat) == B_OK) { - fFileInode = stat.st_ino; - } - - // TODO: the ".." lookup is not actually valid for non-directory vnodes. - // we make use of the fact that a filesystem probably still provides the - // lookup hook and has hardcoded ".." to resolve to the parent entry. if we - // wanted to do this correctly we need some other way to relate this vnode - // to its parent directory vnode. - const char *lookup[] - = { "..", ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, nameBuffer }; - int32 lookupCount = sizeof(lookup) / sizeof(lookup[0]); - fs_vnode currentVnode = *vnode; - ino_t lastInodeNumber = 0; - - for (int32 i = 0; i < lookupCount; i++) { - if (currentVnode.ops->lookup == NULL) { - TRACE_ALWAYS("lookup not possible, lookup hook missing\n"); - fStatus = B_UNSUPPORTED; - if (i > 0) - put_vnode(volume, lastInodeNumber); - return; - } - - ino_t inodeNumber; - fStatus = currentVnode.ops->lookup(volume, ¤tVnode, lookup[i], - &inodeNumber); - - if (i > 0) - put_vnode(volume, lastInodeNumber); - - if (fStatus != B_OK) { - if (fStatus != B_ENTRY_NOT_FOUND) { - TRACE_ALWAYS("lookup of \"%s\" failed: %s\n", lookup[i], - strerror(fStatus)); - } - return; - } - - if (i == 0) - fDirectoryInode = inodeNumber; - else if (i == 1) - fAttributeDirInode = inodeNumber; - else if (i == 2) - fAttributeFileInode = inodeNumber; - - OverlayInode *overlayInode = NULL; - fStatus = get_vnode(overlay, inodeNumber, (void **)&overlayInode); - if (fStatus != B_OK) { - TRACE_ALWAYS("getting vnode failed: %s\n", strerror(fStatus)); - return; - } - - currentVnode = *overlayInode->SuperVnode(); - lastInodeNumber = inodeNumber; - } - - if (currentVnode.ops->read_stat == NULL || currentVnode.ops->open == NULL - || currentVnode.ops->read == NULL) { - TRACE_ALWAYS("can't use attribute file, hooks missing\n"); - put_vnode(volume, lastInodeNumber); - fStatus = B_UNSUPPORTED; - return; - } - - fStatus = currentVnode.ops->read_stat(volume, ¤tVnode, &stat); - if (fStatus != B_OK) { - TRACE_ALWAYS("failed to stat attribute file: %s\n", strerror(fStatus)); - put_vnode(volume, lastInodeNumber); - return; - } - - void *attrFileCookie = NULL; - fStatus = currentVnode.ops->open(volume, ¤tVnode, O_RDONLY, - &attrFileCookie); - if (fStatus != B_OK) { - TRACE_ALWAYS("failed to open attribute file: %s\n", strerror(fStatus)); - put_vnode(volume, lastInodeNumber); - return; - } - - size_t readLength = stat.st_size; - uint8 *buffer = (uint8 *)malloc(readLength); - if (buffer == NULL) { - TRACE_ALWAYS("cannot allocate memory for read buffer\n"); - put_vnode(volume, lastInodeNumber); - fStatus = B_NO_MEMORY; - return; - } - - fStatus = currentVnode.ops->read(volume, ¤tVnode, attrFileCookie, 0, - buffer, &readLength); - if (fStatus != B_OK) { - TRACE_ALWAYS("failed to read from file: %s\n", strerror(fStatus)); - put_vnode(volume, lastInodeNumber); - return; - } - - if (currentVnode.ops->close != NULL) - currentVnode.ops->close(volume, ¤tVnode, attrFileCookie); - if (currentVnode.ops->free_cookie != NULL) - currentVnode.ops->free_cookie(volume, ¤tVnode, attrFileCookie); - - put_vnode(volume, lastInodeNumber); - - fFile = (attribute_file *)buffer; - if (fFile->magic != ATTRIBUTE_OVERLAY_FILE_MAGIC) { - TRACE_ALWAYS("attribute file has bad magic\n"); - fStatus = B_BAD_VALUE; - return; - } - - fEntries = (AttributeEntry **)malloc(fFile->entry_count - * sizeof(AttributeEntry *)); - if (fEntries == NULL) { - TRACE_ALWAYS("no memory to allocate entry pointers\n"); - fStatus = B_NO_MEMORY; - return; - } - - for (uint32 i = 0; i < fFile->entry_count; i++) - fEntries[i] = NULL; - - size_t totalSize = 0; - readLength -= sizeof(attribute_file) - 1; - for (uint32 i = 0; i < fFile->entry_count; i++) { - fEntries[i] = new(std::nothrow) AttributeEntry(this, - fFile->entries + totalSize); - if (fEntries[i] == NULL) { - TRACE_ALWAYS("no memory to allocate attribute entry\n"); - fStatus = B_NO_MEMORY; - return; - } - - totalSize += fEntries[i]->EntrySize() + fEntries[i]->DataSize(); - if (totalSize > readLength) { - TRACE_ALWAYS("attribute entries are too large for buffer\n"); - fStatus = B_BAD_VALUE; - return; - } - } -} - - -AttributeFile::~AttributeFile() -{ - if (fFile == NULL) - return; - - if (fEntries != NULL) { - for (uint32 i = 0; i < fFile->entry_count; i++) - delete fEntries[i]; - - free(fEntries); - } - - free(fFile); -} - - -status_t -AttributeFile::CreateEmpty() -{ - if (fFile == NULL) { - fFile = (attribute_file *)malloc(sizeof(attribute_file) - 1); - if (fFile == NULL) { - TRACE_ALWAYS("failed to allocate file buffer\n"); - fStatus = B_NO_MEMORY; - return fStatus; - } - - fFile->entry_count = 0; - fFile->magic = ATTRIBUTE_OVERLAY_FILE_MAGIC; - } - - fStatus = B_OK; - return B_OK; -} - - -status_t -AttributeFile::WriteAttributeFile(fs_volume *overlay, fs_volume *volume, - fs_vnode *vnode) -{ - if (fFile == NULL) - return B_NO_INIT; - - if (fDirectoryInode == 0) { - TRACE_ALWAYS("directory inode not known\n"); - return B_NO_INIT; - } - - char nameBuffer[B_FILE_NAME_LENGTH]; - nameBuffer[sizeof(nameBuffer) - 1] = 0; - status_t result = vnode->ops->get_vnode_name(volume, vnode, nameBuffer, - sizeof(nameBuffer) - 1); - if (result != B_OK) { - TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result)); - return result; - } - - fs_vnode currentVnode; - OverlayInode *overlayInode = NULL; - if (fAttributeDirInode == 0) { - result = get_vnode(overlay, fDirectoryInode, (void **)&overlayInode); - if (result != B_OK) { - TRACE_ALWAYS("failed to get directory vnode: %s\n", - strerror(result)); - return result; - } - - currentVnode = *overlayInode->SuperVnode(); - - // create the attribute directory - result = currentVnode.ops->create_dir(volume, ¤tVnode, - ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, S_IRWXU | S_IRWXG | S_IRWXO, - &fAttributeDirInode); - - put_vnode(volume, fDirectoryInode); - - if (result != B_OK) { - TRACE_ALWAYS("failed to create attribute directory: %s\n", - strerror(result)); - fAttributeDirInode = 0; - return result; - } - } - - void *attrFileCookie = NULL; - if (fAttributeFileInode == 0) { - result = get_vnode(overlay, fAttributeDirInode, (void **)&overlayInode); - if (result != B_OK) { - TRACE_ALWAYS("failed to get attribute directory vnode: %s\n", - strerror(result)); - return result; - } - - currentVnode = *overlayInode->SuperVnode(); - - // create the attribute file - result = currentVnode.ops->create(volume, ¤tVnode, - nameBuffer, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP - | S_IWGRP | S_IROTH | S_IWOTH, &attrFileCookie, - &fAttributeFileInode); - - put_vnode(volume, fAttributeDirInode); - - if (result != B_OK) { - TRACE_ALWAYS("failed to create attribute file: %s\n", - strerror(result)); - return result; - } - - result = get_vnode(overlay, fAttributeFileInode, (void **)&overlayInode); - if (result != B_OK) { - TRACE_ALWAYS("getting attribute file vnode after create failed: %s\n", - strerror(result)); - return result; - } - - currentVnode = *overlayInode->SuperVnode(); - } else { - result = get_vnode(overlay, fAttributeFileInode, (void **)&overlayInode); - if (result != B_OK) { - TRACE_ALWAYS("getting attribute file vnode failed: %s\n", - strerror(result)); - return result; - } - - currentVnode = *overlayInode->SuperVnode(); - - // open the attribute file - result = currentVnode.ops->open(volume, ¤tVnode, O_RDWR | O_TRUNC, - &attrFileCookie); - if (result != B_OK) { - TRACE_ALWAYS("failed to open attribute file for writing: %s\n", - strerror(result)); - put_vnode(volume, fAttributeFileInode); - return result; - } - } - - off_t position = 0; - size_t writeLength = sizeof(attribute_file) - 1; - result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, - position, fFile, &writeLength); - if (result != B_OK) { - TRACE_ALWAYS("failed to write to attribute file: %s\n", - strerror(result)); - goto close_and_put; - } - - for (uint32 i = 0; i < fFile->entry_count; i++) { - writeLength = fEntries[i]->EntrySize(); - result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, - position, fEntries[i]->Entry(), &writeLength); - if (result != B_OK) { - TRACE_ALWAYS("failed to write to attribute file: %s\n", - strerror(result)); - goto close_and_put; - } - - writeLength = fEntries[i]->DataSize(); - result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, - position, fEntries[i]->Data(), &writeLength); - if (result != B_OK) { - TRACE_ALWAYS("failed to write to attribute file: %s\n", - strerror(result)); - goto close_and_put; - } - } - -close_and_put: - if (currentVnode.ops->close != NULL) - currentVnode.ops->close(volume, ¤tVnode, attrFileCookie); - if (currentVnode.ops->free_cookie != NULL) - currentVnode.ops->free_cookie(volume, ¤tVnode, attrFileCookie); - - put_vnode(volume, fAttributeFileInode); - return B_OK; -} - - -uint32 -AttributeFile::CountAttributes() -{ - if (fFile == NULL) - return 0; - - return fFile->entry_count; -} - - -AttributeEntry * -AttributeFile::FindAttribute(const char *name, uint32 *index) -{ - for (uint32 i = 0; i < fFile->entry_count; i++) { - if (strncmp(fEntries[i]->Name(), name, fEntries[i]->NameLength()) == 0) { - if (index) - *index = i; - - return fEntries[i]; - } - } - - return NULL; -} - - -status_t -AttributeFile::CreateAttribute(const char *name, type_code type, int openMode, - AttributeEntry **_entry) -{ - AttributeEntry *existing = FindAttribute(name); - if (existing != NULL) { - if (openMode & O_TRUNC) - existing->SetSize(0); - - // attribute already exists, only allow if the attribute type is - // compatible or the attribute size is 0 - if (existing->Type() != type) { - if (existing->Size() != 0) - return B_FILE_EXISTS; - existing->SetType(type); - } - - if (existing->InitCheck() == B_OK) { - *_entry = existing; - return B_OK; - } - - // we tried to change the existing item but failed, try to just - // remove it instead and creating a new one - RemoveAttribute(name, NULL); - } - - AttributeEntry *entry = new(std::nothrow) AttributeEntry(this, name, type); - if (entry == NULL) - return B_NO_MEMORY; - - status_t result = AddAttribute(entry); - if (result != B_OK) { - delete entry; - return result; - } - - *_entry = entry; - return B_OK; -} - - -status_t -AttributeFile::OpenAttribute(const char *name, int openMode, - AttributeEntry **_entry) -{ - AttributeEntry *entry = FindAttribute(name); - if (entry == NULL) - return B_ENTRY_NOT_FOUND; - - if (openMode & O_TRUNC) - entry->SetSize(0); - - *_entry = entry; - return B_OK; -} - - -status_t -AttributeFile::RemoveAttribute(const char *name, AttributeEntry **_entry) -{ - uint32 index = 0; - AttributeEntry *entry = FindAttribute(name, &index); - if (entry == NULL) - return B_ENTRY_NOT_FOUND; - - for (uint32 i = index + 1; i < fFile->entry_count; i++) - fEntries[i - 1] = fEntries[i]; - fFile->entry_count--; - - if (_entry) - *_entry = entry; - else - delete entry; - - notify_attribute_changed(fVolumeID, fFileInode, name, B_ATTR_REMOVED); - return B_OK; -} - - -status_t -AttributeFile::AddAttribute(AttributeEntry *entry) -{ - status_t result = entry->InitCheck(); - if (result != B_OK) - return result; - - if (FindAttribute(entry->Name()) != NULL) - return B_FILE_EXISTS; - - AttributeEntry **newEntries = (AttributeEntry **)realloc(fEntries, - (fFile->entry_count + 1) * sizeof(AttributeEntry *)); - if (newEntries == NULL) - return B_NO_MEMORY; - - fEntries = newEntries; - fEntries[fFile->entry_count++] = entry; - - notify_attribute_changed(fVolumeID, fFileInode, entry->Name(), - B_ATTR_CREATED); - - return B_OK; -} - - -status_t -AttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize, - uint32 *numEntries, uint32 *index) -{ - if (fFile == NULL || *index >= fFile->entry_count) { - *numEntries = 0; - return B_OK; - } - - return fEntries[(*index)++]->FillDirent(dirent, bufferSize, numEntries); -} - - -// #pragma mark AttributeEntry - - -AttributeEntry::AttributeEntry(AttributeFile *parent, uint8 *buffer) - : fParent(parent), - fEntry(NULL), - fData(NULL), - fStatus(B_NO_INIT), - fAllocatedEntry(false), - fAllocatedData(false) -{ - if (buffer == NULL) - return; - - fEntry = (attribute_entry *)buffer; - fData = (uint8 *)fEntry->name + fEntry->name_length; - fStatus = B_OK; -} - - -AttributeEntry::AttributeEntry(AttributeFile *parent, const char *name, - type_code type) - : fParent(parent), - fEntry(NULL), - fData(NULL), - fStatus(B_NO_INIT), - fAllocatedEntry(false), - fAllocatedData(false) -{ - fStatus = SetName(name); - if (fStatus != B_OK) - return; - - fEntry->type = type; - fEntry->size = 0; -} - - -AttributeEntry::~AttributeEntry() -{ - if (fAllocatedEntry) - free(fEntry); - if (fAllocatedData) - free(fData); -} - - -size_t -AttributeEntry::EntrySize() -{ - return sizeof(attribute_entry) - 1 + fEntry->name_length; -} - - -status_t -AttributeEntry::SetType(type_code type) -{ - fEntry->type = type; - return B_OK; -} - - -status_t -AttributeEntry::SetSize(size_t size) -{ - if (size <= fEntry->size) { - fEntry->size = size; - return B_OK; - } - - if (fAllocatedData) { - uint8 *newData = (uint8 *)realloc(fData, size); - if (newData == NULL) { - fStatus = B_NO_MEMORY; - return fStatus; - } - - fData = newData; - fEntry->size = size; - return B_OK; - } - - uint8 *newData = (uint8 *)malloc(size); - if (newData == NULL) { - fStatus = B_NO_MEMORY; - return fStatus; - } - - memcpy(newData, fData, min_c(fEntry->size, size)); - fEntry->size = size; - fAllocatedData = true; - fData = newData; - return B_OK; -} - - -status_t -AttributeEntry::SetName(const char *name) -{ - size_t nameLength = strlen(name) + 1; - if (nameLength > 255) { - fStatus = B_NAME_TOO_LONG; - return fStatus; - } - - if (!fAllocatedEntry || fEntry->name_length < nameLength) { - attribute_entry *newEntry = (attribute_entry *)malloc( - sizeof(attribute_entry) - 1 + nameLength); - if (newEntry == NULL) { - fStatus = B_NO_MEMORY; - return fStatus; - } - - if (fEntry != NULL) - memcpy(newEntry, fEntry, sizeof(attribute_entry) - 1); - if (fAllocatedEntry) - free(fEntry); - - fAllocatedEntry = true; - fEntry = newEntry; - } - - fEntry->name_length = nameLength; - strlcpy(fEntry->name, name, nameLength); - return B_OK; -} - - -status_t -AttributeEntry::FillDirent(struct dirent *dirent, size_t bufferSize, - uint32 *numEntries) -{ - dirent->d_dev = dirent->d_pdev = fParent->VolumeID(); - dirent->d_ino = (ino_t)this; - dirent->d_pino = fParent->FileInode(); - dirent->d_reclen = sizeof(struct dirent) + fEntry->name_length; - if (bufferSize < dirent->d_reclen) { - *numEntries = 0; - return B_BAD_VALUE; - } - - strncpy(dirent->d_name, fEntry->name, fEntry->name_length); - dirent->d_name[fEntry->name_length - 1] = 0; - *numEntries = 1; - return B_OK; -} - - -status_t -AttributeEntry::Read(off_t position, void *buffer, size_t *length) -{ - *length = min_c(*length, fEntry->size - position); - memcpy(buffer, fData + position, *length); - return B_OK; -} - - -status_t -AttributeEntry::Write(off_t position, const void *buffer, size_t *length) -{ - size_t neededSize = position + *length; - if (neededSize > fEntry->size) { - status_t result = SetSize(neededSize); - if (result != B_OK) { - *length = 0; - return result; - } - } - - memcpy(fData + position, buffer, *length); - notify_attribute_changed(fParent->VolumeID(), fParent->FileInode(), - fEntry->name, B_ATTR_CHANGED); - return B_OK; -} - - -status_t -AttributeEntry::ReadStat(struct stat *stat) -{ - stat->st_dev = fParent->VolumeID(); - stat->st_ino = (ino_t)this; - stat->st_nlink = 1; - stat->st_blksize = 512; - stat->st_uid = 1; - stat->st_gid = 1; - stat->st_size = fEntry->size; - stat->st_mode = S_ATTR | 0x0777; - stat->st_type = fEntry->type; - stat->st_atime = stat->st_mtime = stat->st_crtime = time(NULL); - stat->st_blocks = (fEntry->size + stat->st_blksize - 1) / stat->st_blksize; - return B_OK; -} - - -status_t -AttributeEntry::WriteStat(const struct stat *stat, uint32 statMask) -{ - return B_UNSUPPORTED; -} - - -// #pragma mark - vnode ops - - -#define OVERLAY_CALL(op, params...) \ - TRACE("relaying op: " #op "\n"); \ - OverlayInode *node = (OverlayInode *)vnode->private_node; \ - fs_vnode *superVnode = node->SuperVnode(); \ - if (superVnode->ops->op != NULL) \ - return superVnode->ops->op(volume->super_volume, superVnode, params); - - -static status_t -overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) -{ - OverlayInode *node = (OverlayInode *)vnode->private_node; - fs_vnode *superVnode = node->SuperVnode(); - - status_t result = B_OK; - if (superVnode->ops->put_vnode != NULL) { - result = superVnode->ops->put_vnode(volume->super_volume, superVnode, - reenter); - } - - delete node; - return result; -} - - -static status_t -overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) -{ - OverlayInode *node = (OverlayInode *)vnode->private_node; - fs_vnode *superVnode = node->SuperVnode(); - - status_t result = B_OK; - if (superVnode->ops->remove_vnode != NULL) { - result = superVnode->ops->remove_vnode(volume->super_volume, superVnode, - reenter); - } - - delete node; - return result; -} - - -static status_t -overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode, - fs_volume *superVolume, fs_vnode *_superVnode) -{ - if (volume == superVolume) { - *_superVnode = *vnode; - return B_OK; - } - - OverlayInode *node = (OverlayInode *)vnode->private_node; - fs_vnode *superVnode = node->SuperVnode(); - - if (superVnode->ops->get_super_vnode != NULL) { - return superVnode->ops->get_super_vnode(volume->super_volume, - superVnode, superVolume, _superVnode); - } - - *_superVnode = *superVnode; - return B_OK; -} - - -static status_t -overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id) -{ - OVERLAY_CALL(lookup, name, id) - return B_UNSUPPORTED; -} - - -static status_t -overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer, - size_t bufferSize) -{ - OVERLAY_CALL(get_vnode_name, buffer, bufferSize) - return B_UNSUPPORTED; -} - - -static bool -overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie) -{ - OVERLAY_CALL(can_page, cookie) - return false; -} - - -static status_t -overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, - const iovec *vecs, size_t count, size_t *numBytes) -{ - OVERLAY_CALL(read_pages, cookie, pos, vecs, count, numBytes) - return B_UNSUPPORTED; -} - - -static status_t -overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, - const iovec *vecs, size_t count, size_t *numBytes) -{ - OVERLAY_CALL(write_pages, cookie, pos, vecs, count, numBytes) - return B_UNSUPPORTED; -} - - -#if 0 -static status_t -overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie, - io_request *request) -{ - OVERLAY_CALL(io, cookie, request) - return B_UNSUPPORTED; -} -#endif - - -static status_t -overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie, - io_request *request) -{ - OVERLAY_CALL(cancel_io, cookie, request) - return B_UNSUPPORTED; -} - - -static status_t -overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset, - size_t size, struct file_io_vec *vecs, size_t *count) -{ - OVERLAY_CALL(get_file_map, offset, size, vecs, count) - return B_UNSUPPORTED; -} - - -static status_t -overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, ulong op, - void *buffer, size_t length) -{ - OVERLAY_CALL(ioctl, cookie, op, buffer, length) - return B_UNSUPPORTED; -} - - -static status_t -overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie, - int flags) -{ - OVERLAY_CALL(set_flags, cookie, flags) - return B_UNSUPPORTED; -} - - -static status_t -overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, - selectsync *sync) -{ - OVERLAY_CALL(select, cookie, event, sync) - return B_UNSUPPORTED; -} - - -static status_t -overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, - selectsync *sync) -{ - OVERLAY_CALL(deselect, cookie, event, sync) - return B_UNSUPPORTED; -} - - -static status_t -overlay_fsync(fs_volume *volume, fs_vnode *vnode) -{ - OverlayInode *node = (OverlayInode *)vnode->private_node; - fs_vnode *superVnode = node->SuperVnode(); - - if (superVnode->ops->fsync != NULL) - return superVnode->ops->fsync(volume->super_volume, superVnode); - - return B_OK; -} - - -static status_t -overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer, - size_t *bufferSize) -{ - OVERLAY_CALL(read_symlink, buffer, bufferSize) - return B_UNSUPPORTED; -} - - -static status_t -overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name, - const char *path, int mode) -{ - OVERLAY_CALL(create_symlink, name, path, mode) - return B_UNSUPPORTED; -} - - -static status_t -overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name, - fs_vnode *target) -{ - OVERLAY_CALL(link, name, target) - return B_UNSUPPORTED; -} - - -static status_t -overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name) -{ - OVERLAY_CALL(unlink, name) - return B_UNSUPPORTED; -} - - -static status_t -overlay_rename(fs_volume *volume, fs_vnode *vnode, - const char *fromName, fs_vnode *toDir, const char *toName) -{ - OVERLAY_CALL(rename, fromName, toDir, toName) - return B_UNSUPPORTED; -} - - -static status_t -overlay_access(fs_volume *volume, fs_vnode *vnode, int mode) -{ - OVERLAY_CALL(access, mode) - return B_UNSUPPORTED; -} - - -static status_t -overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat) -{ - return ((OverlayInode *)vnode->private_node)->ReadStat(stat); -} - - -static status_t -overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, - uint32 statMask) -{ - OVERLAY_CALL(write_stat, stat, statMask) - return B_UNSUPPORTED; -} - - -static status_t -overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name, - int openMode, int perms, void **cookie, ino_t *newVnodeID) -{ - OVERLAY_CALL(create, name, openMode, perms, cookie, newVnodeID) - return B_UNSUPPORTED; -} - - -static status_t -overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie) -{ - return ((OverlayInode *)vnode->private_node)->Open(openMode, cookie); -} - - -static status_t -overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie) -{ - return ((OverlayInode *)vnode->private_node)->Close(cookie); -} - - -static status_t -overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) -{ - return ((OverlayInode *)vnode->private_node)->FreeCookie(cookie); -} - - -static status_t -overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, - void *buffer, size_t *length) -{ - return ((OverlayInode *)vnode->private_node)->Read(cookie, pos, buffer, - length); -} - - -static status_t -overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, - const void *buffer, size_t *length) -{ - return ((OverlayInode *)vnode->private_node)->Write(cookie, pos, buffer, - length); -} - - -static status_t -overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name, - int perms, ino_t *newVnodeID) -{ - OVERLAY_CALL(create_dir, name, perms, newVnodeID) - return B_UNSUPPORTED; -} - - -static status_t -overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name) -{ - OVERLAY_CALL(remove_dir, name) - return B_UNSUPPORTED; -} - - -static status_t -overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) -{ - OVERLAY_CALL(open_dir, cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) -{ - OVERLAY_CALL(close_dir, cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) -{ - OVERLAY_CALL(free_dir_cookie, cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, - struct dirent *buffer, size_t bufferSize, uint32 *num) -{ - TRACE("relaying op: read_dir\n"); - OverlayInode *node = (OverlayInode *)vnode->private_node; - fs_vnode *superVnode = node->SuperVnode(); - if (superVnode->ops->read_dir != NULL) { - status_t result = superVnode->ops->read_dir(volume->super_volume, - superVnode, cookie, buffer, bufferSize, num); - - // TODO: handle multiple records - if (result == B_OK && *num == 1 && strcmp(buffer->d_name, - ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) { - // skip over the attribute directory - return superVnode->ops->read_dir(volume->super_volume, superVnode, - cookie, buffer, bufferSize, num); - } - - return result; - } - - return B_UNSUPPORTED; -} - - -static status_t -overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) -{ - OVERLAY_CALL(rewind_dir, cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) -{ - OVERLAY_CALL(open_attr_dir, cookie) - - AttributeFile *attributeFile = NULL; - status_t result = node->GetAttributeFile(&attributeFile); - if (result != B_OK) - return result; - - attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)malloc( - sizeof(attribute_dir_cookie)); - if (dirCookie == NULL) - return B_NO_MEMORY; - - dirCookie->file = attributeFile; - dirCookie->index = 0; - *cookie = dirCookie; - return B_OK; -} - - -static status_t -overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) -{ - OVERLAY_CALL(close_attr_dir, cookie) - return B_OK; -} - - -static status_t -overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) -{ - OVERLAY_CALL(free_attr_dir_cookie, cookie) - free(cookie); - return B_OK; -} - - -static status_t -overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, - struct dirent *buffer, size_t bufferSize, uint32 *num) -{ - OVERLAY_CALL(read_attr_dir, cookie, buffer, bufferSize, num) - attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie; - return dirCookie->file->ReadAttributeDir(buffer, bufferSize, num, - &dirCookie->index); -} - - -static status_t -overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) -{ - OVERLAY_CALL(rewind_attr_dir, cookie) - attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie; - dirCookie->index = 0; - return B_OK; -} - - -static status_t -overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name, - uint32 type, int openMode, void **cookie) -{ - OVERLAY_CALL(create_attr, name, type, openMode, cookie) - - AttributeFile *attributeFile = NULL; - status_t result = node->GetAttributeFile(&attributeFile); - if (result != B_OK) - return result; - - return attributeFile->CreateAttribute(name, type, openMode, - (AttributeEntry **)cookie); -} - - -static status_t -overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name, - int openMode, void **cookie) -{ - OVERLAY_CALL(open_attr, name, openMode, cookie) - - AttributeFile *attributeFile = NULL; - status_t result = node->GetAttributeFile(&attributeFile); - if (result != B_OK) - return result; - - return attributeFile->OpenAttribute(name, openMode, - (AttributeEntry **)cookie); -} - - -static status_t -overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie) -{ - OVERLAY_CALL(close_attr, cookie) - return B_OK; -} - - -static status_t -overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) -{ - OVERLAY_CALL(free_attr_cookie, cookie) - return B_OK; -} - - -static status_t -overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, - void *buffer, size_t *length) -{ - OVERLAY_CALL(read_attr, cookie, pos, buffer, length) - AttributeEntry *entry = (AttributeEntry *)cookie; - return entry->Read(pos, buffer, length); -} - - -static status_t -overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, - const void *buffer, size_t *length) -{ - OVERLAY_CALL(write_attr, cookie, pos, buffer, length) - AttributeEntry *entry = (AttributeEntry *)cookie; - return entry->Write(pos, buffer, length); -} - - -static status_t -overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, - struct stat *stat) -{ - OVERLAY_CALL(read_attr_stat, cookie, stat) - AttributeEntry *entry = (AttributeEntry *)cookie; - return entry->ReadStat(stat); -} - - -static status_t -overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, - const struct stat *stat, int statMask) -{ - OVERLAY_CALL(write_attr_stat, cookie, stat, statMask) - AttributeEntry *entry = (AttributeEntry *)cookie; - return entry->WriteStat(stat, statMask); -} - - -static status_t -overlay_rename_attr(fs_volume *volume, fs_vnode *vnode, - const char *fromName, fs_vnode *toVnode, const char *toName) -{ - OVERLAY_CALL(rename_attr, fromName, toVnode, toName) - - AttributeFile *attributeFile = NULL; - status_t result = node->GetAttributeFile(&attributeFile); - if (result != B_OK) - return B_OK; - - AttributeFile *toAttributeFile = attributeFile; - if (vnode->private_node != toVnode->private_node) { - OverlayInode *toNode = (OverlayInode *)toVnode->private_node; - result = toNode->GetAttributeFile(&toAttributeFile); - if (result != B_OK) - return result; - } - - AttributeEntry *entry = NULL; - result = attributeFile->RemoveAttribute(fromName, &entry); - if (result != B_OK) - return result; - - result = entry->SetName(toName); - if (result != B_OK) { - if (attributeFile->AddAttribute(entry) != B_OK) - delete entry; - return result; - } - - result = toAttributeFile->AddAttribute(entry); - if (result != B_OK) { - if (entry->SetName(fromName) != B_OK - || attributeFile->AddAttribute(entry) != B_OK) - delete entry; - return result; - } - - return B_OK; -} - - -static status_t -overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name) -{ - OVERLAY_CALL(remove_attr, name) - - AttributeFile *attributeFile = NULL; - status_t result = node->GetAttributeFile(&attributeFile); - if (result != B_OK) - return result; - - return attributeFile->RemoveAttribute(name, NULL); -} - - -static status_t -overlay_create_special_node(fs_volume *volume, fs_vnode *vnode, - const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags, - fs_vnode *_superVnode, ino_t *nodeID) -{ - OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, nodeID) - return B_UNSUPPORTED; -} - - -static fs_vnode_ops sOverlayVnodeOps = { - &overlay_lookup, - &overlay_get_vnode_name, - - &overlay_put_vnode, - &overlay_remove_vnode, - - &overlay_can_page, - &overlay_read_pages, - &overlay_write_pages, - - // TODO: the io scheduler uses it when available but we may simply - // return B_UNSUPPORTED and I'm not sure it then falls back correctly - NULL, //&overlay_io, - &overlay_cancel_io, - - &overlay_get_file_map, - - /* common */ - &overlay_ioctl, - &overlay_set_flags, - &overlay_select, - &overlay_deselect, - &overlay_fsync, - - &overlay_read_symlink, - &overlay_create_symlink, - &overlay_link, - &overlay_unlink, - &overlay_rename, - - &overlay_access, - &overlay_read_stat, - &overlay_write_stat, - - /* file */ - &overlay_create, - &overlay_open, - &overlay_close, - &overlay_free_cookie, - &overlay_read, - &overlay_write, - - /* directory */ - &overlay_create_dir, - &overlay_remove_dir, - &overlay_open_dir, - &overlay_close_dir, - &overlay_free_dir_cookie, - &overlay_read_dir, - &overlay_rewind_dir, - - /* attribute directory operations */ - &overlay_open_attr_dir, - &overlay_close_attr_dir, - &overlay_free_attr_dir_cookie, - &overlay_read_attr_dir, - &overlay_rewind_attr_dir, - - /* attribute operations */ - &overlay_create_attr, - &overlay_open_attr, - &overlay_close_attr, - &overlay_free_attr_cookie, - &overlay_read_attr, - &overlay_write_attr, - - &overlay_read_attr_stat, - &overlay_write_attr_stat, - &overlay_rename_attr, - &overlay_remove_attr, - - /* support for node and FS layers */ - &overlay_create_special_node, - &overlay_get_super_vnode -}; - - -// #pragma mark - volume ops - - -#define OVERLAY_VOLUME_CALL(op, params...) \ - TRACE_VOLUME("relaying volume op: " #op "\n"); \ - if (volume->super_volume->ops->op != NULL) \ - return volume->super_volume->ops->op(volume->super_volume, params); - - -static status_t -overlay_unmount(fs_volume *volume) -{ - TRACE_VOLUME("relaying volume op: unmount\n"); - if (volume->super_volume != NULL - && volume->super_volume->ops != NULL - && volume->super_volume->ops->unmount != NULL) - volume->super_volume->ops->unmount(volume->super_volume); - - delete (OverlayVolume *)volume->private_volume; - return B_OK; -} - - -static status_t -overlay_read_fs_info(fs_volume *volume, struct fs_info *info) -{ - TRACE_VOLUME("relaying volume op: read_fs_info\n"); - status_t result = B_UNSUPPORTED; - if (volume->super_volume->ops->read_fs_info != NULL) { - result = volume->super_volume->ops->read_fs_info(volume->super_volume, - info); - if (result != B_OK) - return result; - - OverlayVolume *overlayVolume = (OverlayVolume *)volume->private_volume; - if (overlayVolume->WriteSupport()) - info->flags &= ~B_FS_IS_READONLY; - info->flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR /*| B_FS_HAS_QUERY*/; - return B_OK; - } - - return B_UNSUPPORTED; -} - - -static status_t -overlay_write_fs_info(fs_volume *volume, const struct fs_info *info, - uint32 mask) -{ - OVERLAY_VOLUME_CALL(write_fs_info, info, mask) - return B_UNSUPPORTED; -} - - -static status_t -overlay_sync(fs_volume *volume) -{ - TRACE_VOLUME("relaying volume op: sync\n"); - if (volume->super_volume->ops->sync != NULL) - return volume->super_volume->ops->sync(volume->super_volume); - return B_UNSUPPORTED; -} - - -static status_t -overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type, - uint32 *_flags, bool reenter) -{ - TRACE_VOLUME("relaying volume op: get_vnode\n"); - if (volume->super_volume->ops->get_vnode != NULL) { - status_t status = volume->super_volume->ops->get_vnode( - volume->super_volume, id, vnode, _type, _flags, reenter); - if (status != B_OK) - return status; - - OverlayInode *node = new(std::nothrow) OverlayInode( - (OverlayVolume *)volume->private_volume, vnode, id); - if (node == NULL) { - vnode->ops->put_vnode(volume->super_volume, vnode, reenter); - return B_NO_MEMORY; - } - - status = node->InitCheck(); - if (status != B_OK) { - delete node; - return status; - } - - vnode->private_node = node; - vnode->ops = &sOverlayVnodeOps; - return B_OK; - } - - return B_UNSUPPORTED; -} - - -static status_t -overlay_open_index_dir(fs_volume *volume, void **cookie) -{ - OVERLAY_VOLUME_CALL(open_index_dir, cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_close_index_dir(fs_volume *volume, void *cookie) -{ - OVERLAY_VOLUME_CALL(close_index_dir, cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_free_index_dir_cookie(fs_volume *volume, void *cookie) -{ - OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer, - size_t bufferSize, uint32 *_num) -{ - OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num) - return B_UNSUPPORTED; -} - - -static status_t -overlay_rewind_index_dir(fs_volume *volume, void *cookie) -{ - OVERLAY_VOLUME_CALL(rewind_index_dir, cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_create_index(fs_volume *volume, const char *name, uint32 type, - uint32 flags) -{ - OVERLAY_VOLUME_CALL(create_index, name, type, flags) - return B_UNSUPPORTED; -} - - -static status_t -overlay_remove_index(fs_volume *volume, const char *name) -{ - OVERLAY_VOLUME_CALL(remove_index, name) - return B_UNSUPPORTED; -} - - -static status_t -overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat) -{ - OVERLAY_VOLUME_CALL(read_index_stat, name, stat) - return B_UNSUPPORTED; -} - - -static status_t -overlay_open_query(fs_volume *volume, const char *query, uint32 flags, - port_id port, uint32 token, void **_cookie) -{ - OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_close_query(fs_volume *volume, void *cookie) -{ - OVERLAY_VOLUME_CALL(close_query, cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_free_query_cookie(fs_volume *volume, void *cookie) -{ - OVERLAY_VOLUME_CALL(free_query_cookie, cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer, - size_t bufferSize, uint32 *_num) -{ - OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num) - return B_UNSUPPORTED; -} - - -static status_t -overlay_rewind_query(fs_volume *volume, void *cookie) -{ - OVERLAY_VOLUME_CALL(rewind_query, cookie) - return B_UNSUPPORTED; -} - - -static status_t -overlay_all_layers_mounted(fs_volume *volume) -{ - return ((OverlayVolume *)volume->private_volume)->AllLayersMounted(); -} - - -static status_t -overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode) -{ - OverlayInode *node = new(std::nothrow) OverlayInode( - (OverlayVolume *)volume->private_volume, vnode, id); - if (node == NULL) - return B_NO_MEMORY; - - status_t status = node->InitCheck(); - if (status != B_OK) { - delete node; - return status; - } - - vnode->private_node = node; - vnode->ops = &sOverlayVnodeOps; - return B_OK; -} - - -static status_t -overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode) -{ - delete (OverlayInode *)vnode; - return B_OK; -} - - -static fs_volume_ops sOverlayVolumeOps = { - &overlay_unmount, - - &overlay_read_fs_info, - &overlay_write_fs_info, - &overlay_sync, - - &overlay_get_vnode, - &overlay_open_index_dir, - &overlay_close_index_dir, - &overlay_free_index_dir_cookie, - &overlay_read_index_dir, - &overlay_rewind_index_dir, - - &overlay_create_index, - &overlay_remove_index, - &overlay_read_index_stat, - - &overlay_open_query, - &overlay_close_query, - &overlay_free_query_cookie, - &overlay_read_query, - &overlay_rewind_query, - - &overlay_all_layers_mounted, - &overlay_create_sub_vnode, - &overlay_delete_sub_vnode -}; - - -// #pragma mark - filesystem module - - -static status_t -overlay_mount(fs_volume *volume, const char *device, uint32 flags, - const char *args, ino_t *rootID) -{ - TRACE_VOLUME("mounting overlay\n"); - volume->private_volume = new(std::nothrow) OverlayVolume(volume); - if (volume->private_volume == NULL) - return B_NO_MEMORY; - - volume->ops = &sOverlayVolumeOps; - return B_OK; -} - - -static status_t -overlay_std_ops(int32 op, ...) -{ - switch (op) { - case B_MODULE_INIT: - case B_MODULE_UNINIT: - return B_OK; - default: - return B_ERROR; - } -} - - -static file_system_module_info sOverlayFileSystem = { - { - "file_systems/overlay"B_CURRENT_FS_API_VERSION, - 0, - overlay_std_ops, - }, - - "overlay", // short_name - "Overlay File System", // pretty_name - 0, // DDM flags - - // scanning - NULL, // identify_partition - NULL, // scan_partition - NULL, // free_identify_partition_cookie - NULL, // free_partition_content_cookie - - // general operations - &overlay_mount, - - // capability querying - NULL, // get_supported_operations - - NULL, // validate_resize - NULL, // validate_move - NULL, // validate_set_content_name - NULL, // validate_set_content_parameters - NULL, // validate_initialize - - // shadow partition modification - NULL, // shadow_changed - - // writing - NULL, // defragment - NULL, // repair - NULL, // resize - NULL, // move - NULL, // set_content_name - NULL, // set_content_parameters - NULL // initialize -}; - -} // namespace _overlay - -using namespace overlay; - -module_info *modules[] = { - (module_info *)&sOverlayFileSystem, - NULL, -}; diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp index bdacabd0dd..8ed3e70bf5 100644 --- a/src/system/kernel/fs/vfs_boot.cpp +++ b/src/system/kernel/fs/vfs_boot.cpp @@ -444,7 +444,7 @@ vfs_mount_boot_file_system(kernel_args *args) const char *fsName = NULL; if (strcmp(bootPartition->ContentType(), "ISO9660 File System") == 0) - fsName = "iso9660:overlay"; + fsName = "iso9660:write_overlay:attribute_overlay"; TRACE(("trying to mount boot partition: %s\n", path.Path())); gBootDevice = _kern_mount("/boot", path.Path(), fsName, 0, NULL, 0);