11553Srgrimes/* 21553Srgrimes * Copyright 2009-2010, Haiku Inc. All rights reserved. 31553Srgrimes * Distributed under the terms of the MIT License. 41553Srgrimes * 51553Srgrimes * Authors: 61553Srgrimes * Michael Lotz <mmlr@mlotz.ch> 71553Srgrimes */ 81553Srgrimes 91553Srgrimes 101553Srgrimes#include <new> 111553Srgrimes#include <stdlib.h> 121553Srgrimes#include <string.h> 131553Srgrimes 141553Srgrimes#include <dirent.h> 151553Srgrimes 161553Srgrimes#include <util/kernel_cpp.h> 171553Srgrimes 181553Srgrimes#include <fs_info.h> 191553Srgrimes#include <fs_interface.h> 201553Srgrimes 211553Srgrimes#include <debug.h> 221553Srgrimes#include <KernelExport.h> 231553Srgrimes#include <NodeMonitor.h> 241553Srgrimes 251553Srgrimes 261553Srgrimes//#define TRACE_OVERLAY 271553Srgrimes#ifdef TRACE_OVERLAY 281553Srgrimes# define TRACE(x...) dprintf("attribute_overlay: " x) 291553Srgrimes# define TRACE_VOLUME(x...) dprintf("attribute_overlay: " x) 301553Srgrimes# define TRACE_ALWAYS(x...) dprintf("attribute_overlay: " x) 311553Srgrimes#else 3231492Swollman# define TRACE(x...) /* nothing */ 331553Srgrimes# define TRACE_VOLUME(x...) /* nothing */ 341553Srgrimes# define TRACE_ALWAYS(x...) dprintf("attribute_overlay: " x) 351553Srgrimes#endif 361553Srgrimes 37117599Sgad 381553Srgrimes#define ATTRIBUTE_OVERLAY_FILE_MAGIC 'attr' 3915648Sjoerg#define ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME "_HAIKU" 401553Srgrimes 41117599Sgad 421553Srgrimes#define OVERLAY_CALL(op, params...) \ 43117599Sgad TRACE("relaying op: " #op "\n"); \ 44117599Sgad OverlayInode *node = (OverlayInode *)vnode->private_node; \ 45117599Sgad fs_vnode *superVnode = node->SuperVnode(); \ 461553Srgrimes if (superVnode->ops->op != NULL) \ 471553Srgrimes return superVnode->ops->op(volume->super_volume, superVnode, params); \ 481553Srgrimes return B_UNSUPPORTED; 491553Srgrimes 501553Srgrimes 511553Srgrimes#define OVERLAY_VOLUME_CALL(op, params...) \ 521553Srgrimes TRACE_VOLUME("relaying volume op: " #op "\n"); \ 5315648Sjoerg if (volume->super_volume->ops->op != NULL) \ 541553Srgrimes return volume->super_volume->ops->op(volume->super_volume, params); 551553Srgrimes 561553Srgrimes 57241852Seadlernamespace attribute_overlay { 581553Srgrimes 591553Srgrimesclass AttributeFile; 601553Srgrimesclass AttributeEntry; 611553Srgrimes 621553Srgrimes 631553Srgrimesstruct attribute_dir_cookie { 641553Srgrimes AttributeFile * file; 651553Srgrimes uint32 index; 661553Srgrimes}; 671553Srgrimes 681553Srgrimes 691553Srgrimesclass OverlayVolume { 701553Srgrimespublic: 7198152Sgad OverlayVolume(fs_volume *volume); 7298152Sgad ~OverlayVolume(); 7398152Sgad 7498152Sgad fs_volume * Volume() { return fVolume; } 7598152Sgad fs_volume * SuperVolume() { return fVolume->super_volume; } 7698152Sgad 7798152Sgadprivate: 7898152Sgad fs_volume * fVolume; 7998267Sgad}; 8078146Sgad 81231723Skevlo 8298152Sgadclass OverlayInode { 83234244Sdelphijpublic: 8478146Sgad OverlayInode(OverlayVolume *volume, 8578146Sgad fs_vnode *superVnode, ino_t inodeNumber); 8698267Sgad ~OverlayInode(); 8778750Sgad 881553Srgrimes status_t InitCheck(); 891553Srgrimes 9031492Swollman fs_volume * Volume() { return fVolume->Volume(); } 9131492Swollman fs_volume * SuperVolume() { return fVolume->SuperVolume(); } 921553Srgrimes fs_vnode * SuperVnode() { return &fSuperVnode; } 9378750Sgad ino_t InodeNumber() { return fInodeNumber; } 9478750Sgad 9578750Sgad status_t GetAttributeFile(AttributeFile **attributeFile); 9678750Sgad status_t WriteAttributeFile(); 9778750Sgad status_t RemoveAttributeFile(); 9878750Sgad 9978750Sgadprivate: 10078750Sgad OverlayVolume * fVolume; 10178750Sgad fs_vnode fSuperVnode; 10298268Sgad ino_t fInodeNumber; 10398267Sgad AttributeFile * fAttributeFile; 10478750Sgad}; 10578750Sgad 10678750Sgad 1071553Srgrimesclass AttributeFile { 10898267Sgadpublic: 10978750Sgad AttributeFile(fs_volume *overlay, 1101553Srgrimes fs_volume *volume, fs_vnode *vnode); 11178750Sgad ~AttributeFile(); 11278750Sgad 11398268Sgad status_t InitCheck() { return fStatus; } 1141553Srgrimes 1151553Srgrimes dev_t VolumeID() { return fVolumeID; } 11698278Sgad ino_t FileInode() { return fFileInode; } 11798278Sgad 11898278Sgad status_t CreateEmpty(); 11998278Sgad status_t WriteAttributeFile(fs_volume *overlay, 12098278Sgad fs_volume *volume, fs_vnode *vnode); 12198267Sgad status_t RemoveAttributeFile(fs_volume *overlay, 12298278Sgad fs_volume *volume, fs_vnode *vnode); 12398278Sgad 12498278Sgad status_t ReadAttributeDir(struct dirent *dirent, 12598278Sgad size_t bufferSize, uint32 *numEntries, 12698267Sgad uint32 *index); 12798267Sgad 1281553Srgrimes uint32 CountAttributes(); 1291553Srgrimes AttributeEntry * FindAttribute(const char *name, 13078750Sgad uint32 *index = NULL); 13198268Sgad 13298268Sgad status_t CreateAttribute(const char *name, type_code type, 13398268Sgad int openMode, AttributeEntry **entry); 13498268Sgad status_t OpenAttribute(const char *name, int openMode, 13578750Sgad AttributeEntry **entry); 13678750Sgad status_t RemoveAttribute(const char *name, 13778750Sgad AttributeEntry **entry); 13878750Sgad status_t AddAttribute(AttributeEntry *entry); 13978750Sgad 14078750Sgadprivate: 14178750Sgad struct attribute_file { 14278750Sgad uint32 magic; 14378750Sgad // ATTRIBUTE_OVERLAY_FILE_MAGIC 14478750Sgad uint32 entry_count; 14578750Sgad uint8 entries[1]; 14678750Sgad } _PACKED; 14778750Sgad 14878750Sgad status_t fStatus; 14978750Sgad dev_t fVolumeID; 15078750Sgad ino_t fFileInode; 15178750Sgad ino_t fDirectoryInode; 15298267Sgad ino_t fAttributeDirInode; 15398267Sgad ino_t fAttributeFileInode; 15498267Sgad attribute_file * fFile; 15598267Sgad uint32 fAttributeDirIndex; 15698267Sgad AttributeEntry ** fEntries; 15798267Sgad}; 15898267Sgad 15998267Sgad 16098268Sgadclass AttributeEntry { 16198267Sgadpublic: 16298267Sgad AttributeEntry(AttributeFile *parent, 16398267Sgad uint8 *buffer); 16498267Sgad AttributeEntry(AttributeFile *parent, 16598267Sgad const char *name, type_code type); 16698267Sgad ~AttributeEntry(); 167234824Sgad 168234824Sgad status_t InitCheck() { return fStatus; } 169234824Sgad 170234824Sgad uint8 * Entry() { return (uint8 *)fEntry; } 171234824Sgad size_t EntrySize(); 172234824Sgad uint8 * Data() { return fData; } 173234824Sgad size_t DataSize() { return fEntry->size; } 174234824Sgad 17598267Sgad status_t SetType(type_code type); 17698267Sgad type_code Type() { return fEntry->type; } 17778750Sgad 17878750Sgad status_t SetSize(size_t size); 17978750Sgad uint32 Size() { return fEntry->size; } 18078750Sgad 18178750Sgad status_t SetName(const char *name); 18278750Sgad const char * Name() { return fEntry->name; } 18398268Sgad uint8 NameLength() { return fEntry->name_length; } 18498268Sgad 18598268Sgad status_t FillDirent(struct dirent *dirent, 18698268Sgad size_t bufferSize, uint32 *numEntries); 18798268Sgad 18878750Sgad status_t Read(off_t position, void *buffer, 18978750Sgad size_t *length); 19098268Sgad status_t Write(off_t position, const void *buffer, 19198268Sgad size_t *length); 19298268Sgad 19398268Sgad status_t ReadStat(struct stat *stat); 19498268Sgad status_t WriteStat(const struct stat *stat, 19598268Sgad uint32 statMask); 19698268Sgad 19798268Sgadprivate: 19898268Sgad struct attribute_entry { 19978750Sgad type_code type; 20078750Sgad uint32 size; 20178750Sgad uint8 name_length; // including 0 byte 20298268Sgad char name[1]; // 0 terminated, followed by data 20378750Sgad } _PACKED; 20478146Sgad 20578146Sgad AttributeFile * fParent; 20631492Swollman attribute_entry * fEntry; 20731492Swollman uint8 * fData; 20878146Sgad status_t fStatus; 20931492Swollman bool fAllocatedEntry; 21078146Sgad bool fAllocatedData; 21131492Swollman}; 21278146Sgad 21331492Swollman 21431492Swollman// #pragma mark OverlayVolume 21531492Swollman 21631492Swollman 21731492SwollmanOverlayVolume::OverlayVolume(fs_volume *volume) 21831492Swollman : 21931492Swollman fVolume(volume) 22079739Sgad{ 22131492Swollman} 22278146Sgad 2231553Srgrimes 22478750SgadOverlayVolume::~OverlayVolume() 2251553Srgrimes{ 22678750Sgad} 22778750Sgad 22898268Sgad 22931492Swollman// #pragma mark OverlayInode 23078146Sgad 23178146Sgad 23231492SwollmanOverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode, 23379739Sgad ino_t inodeNumber) 23431492Swollman : 23531492Swollman fVolume(volume), 2361553Srgrimes fSuperVnode(*superVnode), 23731492Swollman fInodeNumber(inodeNumber), 23831492Swollman fAttributeFile(NULL) 23931492Swollman{ 24031492Swollman TRACE("inode created\n"); 24131492Swollman} 24231492Swollman 24331492Swollman 24478146SgadOverlayInode::~OverlayInode() 2451553Srgrimes{ 24678750Sgad TRACE("inode destroyed\n"); 24778750Sgad delete fAttributeFile; 24878750Sgad} 24978750Sgad 25078750Sgad 25199846Sgadstatus_t 25298267SgadOverlayInode::InitCheck() 25398267Sgad{ 25498267Sgad return B_OK; 25578750Sgad} 25698267Sgad 25798267Sgad 25898267Sgadstatus_t 25998267SgadOverlayInode::GetAttributeFile(AttributeFile **attributeFile) 26098267Sgad{ 26198267Sgad if (fAttributeFile == NULL) { 26298267Sgad fAttributeFile = new(std::nothrow) AttributeFile(Volume(), 26398267Sgad SuperVolume(), &fSuperVnode); 26498267Sgad if (fAttributeFile == NULL) { 26598267Sgad TRACE_ALWAYS("no memory to allocate attribute file\n"); 26698267Sgad return B_NO_MEMORY; 26798267Sgad } 26898267Sgad } 26998267Sgad 27098267Sgad status_t result = fAttributeFile->InitCheck(); 27198267Sgad if (result != B_OK) { 27298267Sgad if (result == B_ENTRY_NOT_FOUND) { 27398267Sgad // TODO: need to check if we're able to create the file 27498267Sgad // but at least allow virtual attributes for now 27598267Sgad } 27698267Sgad 27798267Sgad result = fAttributeFile->CreateEmpty(); 27898267Sgad if (result != B_OK) 27998267Sgad return result; 2801553Srgrimes } 2811553Srgrimes 28231492Swollman *attributeFile = fAttributeFile; 28398152Sgad return B_OK; 28498152Sgad} 28598152Sgad 28698152Sgad 28798152Sgadstatus_t 28898152SgadOverlayInode::WriteAttributeFile() 28998152Sgad{ 29098152Sgad if (fAttributeFile == NULL) 29198152Sgad return B_NO_INIT; 292241852Seadler 29398152Sgad status_t result = fAttributeFile->InitCheck(); 29498152Sgad if (result != B_OK) 295241852Seadler return result; 29698152Sgad 29798152Sgad return fAttributeFile->WriteAttributeFile(Volume(), SuperVolume(), 29898152Sgad &fSuperVnode); 29998152Sgad} 30098152Sgad 30198152Sgad 30298152Sgadstatus_t 30398152SgadOverlayInode::RemoveAttributeFile() 30498152Sgad{ 30598152Sgad if (fAttributeFile == NULL) 30698152Sgad return B_NO_INIT; 30798152Sgad 30898152Sgad status_t result = fAttributeFile->InitCheck(); 30998152Sgad if (result != B_OK) 31098152Sgad return result; 31198152Sgad 31298152Sgad return fAttributeFile->RemoveAttributeFile(Volume(), SuperVolume(), 31398152Sgad &fSuperVnode); 31498152Sgad} 31598152Sgad 31698152Sgad 31798152Sgad// #pragma mark AttributeFile 31898152Sgad 31998152Sgad 32098152SgadAttributeFile::AttributeFile(fs_volume *overlay, fs_volume *volume, 32198152Sgad fs_vnode *vnode) 32298152Sgad : 32398152Sgad fStatus(B_NO_INIT), 32498152Sgad fVolumeID(volume->id), 32598152Sgad fFileInode(0), 32698152Sgad fDirectoryInode(0), 32798152Sgad fAttributeDirInode(0), 32898152Sgad fAttributeFileInode(0), 32998152Sgad fFile(NULL), 33098152Sgad fAttributeDirIndex(0), 33198152Sgad fEntries(NULL) 33298152Sgad{ 333241852Seadler if (vnode->ops->get_vnode_name == NULL) { 33498152Sgad TRACE_ALWAYS("cannot get vnode name, hook missing\n"); 33598152Sgad fStatus = B_UNSUPPORTED; 336241852Seadler return; 33798152Sgad } 33898152Sgad 33998152Sgad char nameBuffer[B_FILE_NAME_LENGTH]; 34098152Sgad nameBuffer[sizeof(nameBuffer) - 1] = 0; 34198152Sgad fStatus = vnode->ops->get_vnode_name(volume, vnode, nameBuffer, 34298152Sgad sizeof(nameBuffer) - 1); 34398152Sgad if (fStatus != B_OK) { 34498152Sgad TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(fStatus)); 34598152Sgad return; 34698152Sgad } 34798152Sgad 34898152Sgad if (strcmp(nameBuffer, ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) { 34998152Sgad // we don't want attribute overlays on the attribute dir itself 35098152Sgad fStatus = B_UNSUPPORTED; 35198152Sgad return; 35298152Sgad } 35398152Sgad 35498152Sgad struct stat stat; 35598152Sgad if (vnode->ops->read_stat != NULL 35698152Sgad && vnode->ops->read_stat(volume, vnode, &stat) == B_OK) { 35798152Sgad fFileInode = stat.st_ino; 35898152Sgad } 35998152Sgad 36098152Sgad // TODO: the ".." lookup is not actually valid for non-directory vnodes. 36198152Sgad // we make use of the fact that a filesystem probably still provides the 36298152Sgad // lookup hook and has hardcoded ".." to resolve to the parent entry. if we 36398152Sgad // wanted to do this correctly we need some other way to relate this vnode 36498152Sgad // to its parent directory vnode. 36598152Sgad const char *lookup[] 36698152Sgad = { "..", ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, nameBuffer }; 36798152Sgad int32 lookupCount = sizeof(lookup) / sizeof(lookup[0]); 36898152Sgad fs_vnode currentVnode = *vnode; 36998152Sgad ino_t lastInodeNumber = 0; 3701553Srgrimes 3711553Srgrimes for (int32 i = 0; i < lookupCount; i++) { 3721553Srgrimes if (currentVnode.ops->lookup == NULL) { 37398267Sgad TRACE_ALWAYS("lookup not possible, lookup hook missing\n"); 3741553Srgrimes fStatus = B_UNSUPPORTED; 37598267Sgad if (i > 0) 37627748Simp put_vnode(volume, lastInodeNumber); 3771553Srgrimes return; 37831492Swollman } 3791553Srgrimes 380241852Seadler ino_t inodeNumber; 38131492Swollman fStatus = currentVnode.ops->lookup(volume, ¤tVnode, lookup[i], 382241852Seadler &inodeNumber); 38331492Swollman 38431492Swollman if (i > 0) 3851553Srgrimes put_vnode(volume, lastInodeNumber); 3861553Srgrimes 3871553Srgrimes if (fStatus != B_OK) { 388231723Skevlo if (fStatus != B_ENTRY_NOT_FOUND) { 3891553Srgrimes TRACE_ALWAYS("lookup of \"%s\" failed: %s\n", lookup[i], 3901553Srgrimes strerror(fStatus)); 3911553Srgrimes } 3921553Srgrimes return; 39398267Sgad } 39498267Sgad 39598267Sgad if (i == 0) 39698267Sgad fDirectoryInode = inodeNumber; 39798267Sgad else if (i == 1) 39898267Sgad fAttributeDirInode = inodeNumber; 3991553Srgrimes else if (i == 2) 4001553Srgrimes fAttributeFileInode = inodeNumber; 40178750Sgad 40298152Sgad OverlayInode *overlayInode = NULL; 40398152Sgad fStatus = get_vnode(overlay, inodeNumber, (void **)&overlayInode); 40498152Sgad if (fStatus != B_OK) { 40598152Sgad TRACE_ALWAYS("getting vnode failed: %s\n", strerror(fStatus)); 40698152Sgad return; 40798152Sgad } 40898152Sgad 40998152Sgad currentVnode = *overlayInode->SuperVnode(); 41098152Sgad lastInodeNumber = inodeNumber; 41198152Sgad } 41298152Sgad 41398152Sgad if (currentVnode.ops->read_stat == NULL || currentVnode.ops->open == NULL 41498152Sgad || currentVnode.ops->read == NULL) { 41598152Sgad TRACE_ALWAYS("can't use attribute file, hooks missing\n"); 41698152Sgad put_vnode(volume, lastInodeNumber); 41798152Sgad fStatus = B_UNSUPPORTED; 41898152Sgad return; 41998152Sgad } 42098152Sgad 42198152Sgad fStatus = currentVnode.ops->read_stat(volume, ¤tVnode, &stat); 42298152Sgad if (fStatus != B_OK) { 42398152Sgad TRACE_ALWAYS("failed to stat attribute file: %s\n", strerror(fStatus)); 42498152Sgad put_vnode(volume, lastInodeNumber); 42598152Sgad return; 42698152Sgad } 42798152Sgad 42898152Sgad void *attrFileCookie = NULL; 42998152Sgad fStatus = currentVnode.ops->open(volume, ¤tVnode, O_RDONLY, 43098152Sgad &attrFileCookie); 43198152Sgad if (fStatus != B_OK) { 43298152Sgad TRACE_ALWAYS("failed to open attribute file: %s\n", strerror(fStatus)); 43398152Sgad put_vnode(volume, lastInodeNumber); 43498152Sgad return; 43598152Sgad } 43698152Sgad 43798152Sgad size_t readLength = stat.st_size; 43898152Sgad uint8 *buffer = (uint8 *)malloc(readLength); 43998152Sgad if (buffer == NULL) { 44098152Sgad TRACE_ALWAYS("cannot allocate memory for read buffer\n"); 44198152Sgad put_vnode(volume, lastInodeNumber); 44298152Sgad fStatus = B_NO_MEMORY; 44398152Sgad return; 44498152Sgad } 44598152Sgad 44698267Sgad fStatus = currentVnode.ops->read(volume, ¤tVnode, attrFileCookie, 0, 44798267Sgad buffer, &readLength); 44898152Sgad if (fStatus != B_OK) { 44998152Sgad TRACE_ALWAYS("failed to read from file: %s\n", strerror(fStatus)); 45098152Sgad put_vnode(volume, lastInodeNumber); 45178750Sgad return; 45278750Sgad } 45378750Sgad 45478750Sgad if (currentVnode.ops->close != NULL) 45578750Sgad currentVnode.ops->close(volume, ¤tVnode, attrFileCookie); 45678750Sgad if (currentVnode.ops->free_cookie != NULL) 45778750Sgad currentVnode.ops->free_cookie(volume, ¤tVnode, attrFileCookie); 45878750Sgad 45978750Sgad put_vnode(volume, lastInodeNumber); 46078750Sgad 46178750Sgad fFile = (attribute_file *)buffer; 4621553Srgrimes if (fFile->magic != ATTRIBUTE_OVERLAY_FILE_MAGIC) { 463231723Skevlo TRACE_ALWAYS("attribute file has bad magic\n"); 4641553Srgrimes fStatus = B_BAD_VALUE; 4651553Srgrimes return; 4661553Srgrimes } 46787034Sgad 46887034Sgad fEntries = (AttributeEntry **)malloc(fFile->entry_count 46978750Sgad * sizeof(AttributeEntry *)); 47078750Sgad if (fEntries == NULL) { 47178750Sgad TRACE_ALWAYS("no memory to allocate entry pointers\n"); 47278750Sgad fStatus = B_NO_MEMORY; 47378750Sgad return; 47478750Sgad } 47578750Sgad 47678750Sgad for (uint32 i = 0; i < fFile->entry_count; i++) 47778750Sgad fEntries[i] = NULL; 47878750Sgad 4791553Srgrimes size_t totalSize = 0; 4801553Srgrimes readLength -= sizeof(attribute_file) - 1; 4811553Srgrimes for (uint32 i = 0; i < fFile->entry_count; i++) { 48284034Sgad fEntries[i] = new(std::nothrow) AttributeEntry(this, 48384034Sgad fFile->entries + totalSize); 48484034Sgad if (fEntries[i] == NULL) { 48587034Sgad TRACE_ALWAYS("no memory to allocate attribute entry\n"); 48687034Sgad fStatus = B_NO_MEMORY; 48787034Sgad return; 48887034Sgad } 48987034Sgad 49087034Sgad totalSize += fEntries[i]->EntrySize() + fEntries[i]->DataSize(); 49187034Sgad if (totalSize > readLength) { 49287034Sgad TRACE_ALWAYS("attribute entries are too large for buffer\n"); 49387034Sgad fStatus = B_BAD_VALUE; 49487034Sgad return; 49587034Sgad } 4961553Srgrimes } 4971553Srgrimes} 498234244Sdelphij 4991553Srgrimes 50084034SgadAttributeFile::~AttributeFile() 50184034Sgad{ 50284034Sgad if (fFile == NULL) 5031553Srgrimes return; 504234244Sdelphij 505234244Sdelphij if (fEntries != NULL) { 50684034Sgad for (uint32 i = 0; i < fFile->entry_count; i++) 50784034Sgad delete fEntries[i]; 508228990Suqs 50987034Sgad free(fEntries); 51087034Sgad } 51187034Sgad 51284034Sgad free(fFile); 51384034Sgad} 51484034Sgad 51584034Sgad 51684034Sgadstatus_t 51784034SgadAttributeFile::CreateEmpty() 51884034Sgad{ 51984034Sgad if (fFile == NULL) { 52084034Sgad fFile = (attribute_file *)malloc(sizeof(attribute_file) - 1); 52184691Sgad if (fFile == NULL) { 52284034Sgad TRACE_ALWAYS("failed to allocate file buffer\n"); 52384034Sgad fStatus = B_NO_MEMORY; 52484034Sgad return fStatus; 52584034Sgad } 52684034Sgad 52784034Sgad fFile->entry_count = 0; 52887034Sgad fFile->magic = ATTRIBUTE_OVERLAY_FILE_MAGIC; 52987034Sgad } 53084034Sgad 53187034Sgad fStatus = B_OK; 53284034Sgad return B_OK; 53384034Sgad} 53484034Sgad 53584034Sgad 53684034Sgadstatus_t 53784034SgadAttributeFile::WriteAttributeFile(fs_volume *overlay, fs_volume *volume, 53884034Sgad fs_vnode *vnode) 53984034Sgad{ 54084034Sgad if (fFile == NULL) 54184034Sgad return B_NO_INIT; 54284034Sgad 54384034Sgad char nameBuffer[B_FILE_NAME_LENGTH]; 54484034Sgad nameBuffer[sizeof(nameBuffer) - 1] = 0; 54584034Sgad status_t result = vnode->ops->get_vnode_name(volume, vnode, nameBuffer, 54684034Sgad sizeof(nameBuffer) - 1); 54784034Sgad if (result != B_OK) { 54884034Sgad TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result)); 54984034Sgad return result; 55084034Sgad } 55184034Sgad 55284034Sgad fs_vnode currentVnode = *vnode; 55384034Sgad if (fDirectoryInode == 0) { 55484034Sgad if (currentVnode.ops->lookup == NULL) { 55584034Sgad TRACE_ALWAYS("lookup not possible, lookup hook missing\n"); 55684034Sgad return B_UNSUPPORTED; 55784034Sgad } 55884034Sgad 55984034Sgad // see TODO above 56084034Sgad result = currentVnode.ops->lookup(volume, ¤tVnode, "..", 56184034Sgad &fDirectoryInode); 56284034Sgad if (result != B_OK) { 56384034Sgad TRACE_ALWAYS("lookup of parent directory failed: %s\n", 56484034Sgad strerror(result)); 56587034Sgad return B_UNSUPPORTED; 56684034Sgad } 56784034Sgad 56884034Sgad put_vnode(volume, fDirectoryInode); 56984034Sgad } 57084034Sgad 57184034Sgad OverlayInode *overlayInode = NULL; 57284034Sgad if (fAttributeDirInode == 0) { 57384034Sgad result = get_vnode(overlay, fDirectoryInode, (void **)&overlayInode); 574228990Suqs if (result != B_OK) { 57584034Sgad TRACE_ALWAYS("failed to get directory vnode: %s\n", 57684034Sgad strerror(result)); 57784034Sgad return result; 57884034Sgad } 57984034Sgad 58084034Sgad currentVnode = *overlayInode->SuperVnode(); 58184034Sgad 58284034Sgad // create the attribute directory 58384034Sgad result = currentVnode.ops->create_dir(volume, ¤tVnode, 58484034Sgad ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, S_IRWXU | S_IRWXG | S_IRWXO); 585228990Suqs 586228990Suqs if (result == B_OK) { 58784034Sgad result = currentVnode.ops->lookup(volume, ¤tVnode, 58884034Sgad ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, &fAttributeDirInode); 58984034Sgad 59084034Sgad // lookup() got us a reference we don't need -- put it 59184034Sgad if (result == B_OK) 59284034Sgad put_vnode(volume, fAttributeDirInode); 59384034Sgad } 59484034Sgad 59584034Sgad put_vnode(volume, fDirectoryInode); 59684034Sgad 59784034Sgad if (result != B_OK) { 59884034Sgad TRACE_ALWAYS("failed to create attribute directory: %s\n", 59984034Sgad strerror(result)); 60084034Sgad fAttributeDirInode = 0; 60184034Sgad return result; 60284034Sgad } 60384034Sgad } 60484034Sgad 60584034Sgad void *attrFileCookie = NULL; 60684034Sgad if (fAttributeFileInode == 0) { 60784034Sgad result = get_vnode(overlay, fAttributeDirInode, (void **)&overlayInode); 60884034Sgad if (result != B_OK) { 60984034Sgad TRACE_ALWAYS("failed to get attribute directory vnode: %s\n", 6101553Srgrimes strerror(result)); 6111553Srgrimes return result; 6121553Srgrimes } 61331492Swollman 61431492Swollman currentVnode = *overlayInode->SuperVnode(); 6151553Srgrimes 6161553Srgrimes // create the attribute file 61778750Sgad result = currentVnode.ops->create(volume, ¤tVnode, 61831492Swollman nameBuffer, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP 61998279Sgad | S_IWGRP | S_IROTH | S_IWOTH, &attrFileCookie, 6201553Srgrimes &fAttributeFileInode); 62178750Sgad 62278750Sgad put_vnode(volume, fAttributeDirInode); 62378750Sgad 62478750Sgad if (result != B_OK) { 62578750Sgad TRACE_ALWAYS("failed to create attribute file: %s\n", 62678750Sgad strerror(result)); 62778750Sgad return result; 62878750Sgad } 62978750Sgad 63078750Sgad result = get_vnode(overlay, fAttributeFileInode, 63178750Sgad (void **)&overlayInode); 63278750Sgad if (result != B_OK) { 63398268Sgad TRACE_ALWAYS("getting attribute file vnode after create failed: " 63478750Sgad "%s\n", strerror(result)); 63578750Sgad return result; 63678750Sgad } 63778750Sgad 63884034Sgad currentVnode = *overlayInode->SuperVnode(); 63978750Sgad } else { 64078750Sgad result = get_vnode(overlay, fAttributeFileInode, 64178750Sgad (void **)&overlayInode); 64278750Sgad if (result != B_OK) { 64378750Sgad TRACE_ALWAYS("getting attribute file vnode failed: %s\n", 64478750Sgad strerror(result)); 64578750Sgad return result; 64678750Sgad } 64778750Sgad 64878750Sgad currentVnode = *overlayInode->SuperVnode(); 64978750Sgad 65098279Sgad // open the attribute file 65178750Sgad result = currentVnode.ops->open(volume, ¤tVnode, O_RDWR | O_TRUNC, 65278750Sgad &attrFileCookie); 65378750Sgad if (result != B_OK) { 65478750Sgad TRACE_ALWAYS("failed to open attribute file for writing: %s\n", 65598279Sgad strerror(result)); 65678750Sgad put_vnode(volume, fAttributeFileInode); 65778750Sgad return result; 65878750Sgad } 65978750Sgad } 66078750Sgad 66178750Sgad off_t position = 0; 66278750Sgad size_t writeLength = sizeof(attribute_file) - 1; 66378750Sgad result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, 66478750Sgad position, fFile, &writeLength); 6651553Srgrimes if (result != B_OK) { 66678750Sgad TRACE_ALWAYS("failed to write to attribute file: %s\n", 66778750Sgad strerror(result)); 6681553Srgrimes goto close_and_put; 66978750Sgad } 6701553Srgrimes 67178750Sgad for (uint32 i = 0; i < fFile->entry_count; i++) { 67278750Sgad writeLength = fEntries[i]->EntrySize(); 67378750Sgad result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, 67478750Sgad position, fEntries[i]->Entry(), &writeLength); 67578750Sgad if (result != B_OK) { 67678750Sgad TRACE_ALWAYS("failed to write to attribute file: %s\n", 67731492Swollman strerror(result)); 67831492Swollman goto close_and_put; 67931492Swollman } 68031492Swollman 68131492Swollman writeLength = fEntries[i]->DataSize(); 68231492Swollman result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, 6831553Srgrimes position, fEntries[i]->Data(), &writeLength); 68478750Sgad if (result != B_OK) { 6851553Srgrimes TRACE_ALWAYS("failed to write to attribute file: %s\n", 68678750Sgad strerror(result)); 687241852Seadler goto close_and_put; 68831492Swollman } 689241852Seadler } 6901553Srgrimes 69178750Sgadclose_and_put: 69278750Sgad if (currentVnode.ops->close != NULL) 69378750Sgad currentVnode.ops->close(volume, ¤tVnode, attrFileCookie); 69478750Sgad if (currentVnode.ops->free_cookie != NULL) 6951553Srgrimes currentVnode.ops->free_cookie(volume, ¤tVnode, attrFileCookie); 6961553Srgrimes 6971553Srgrimes put_vnode(volume, fAttributeFileInode); 69878750Sgad return B_OK; 69978750Sgad} 70078750Sgad 70178750Sgad 70278750Sgadstatus_t 70378750SgadAttributeFile::RemoveAttributeFile(fs_volume *overlay, fs_volume *volume, 70478750Sgad fs_vnode *vnode) 7051553Srgrimes{ 7061553Srgrimes bool hasAttributeFile = fAttributeFileInode != 0; 70778750Sgad ino_t attributeDirInode = fAttributeDirInode; 70878750Sgad 70984034Sgad // invalidate all of our cached inode numbers 71084034Sgad fDirectoryInode = 0; 71184034Sgad fAttributeDirInode = 0; 71284034Sgad fAttributeFileInode = 0; 71384034Sgad 71484034Sgad if (!hasAttributeFile) { 71584034Sgad // there is no backing file at all yet 71684034Sgad return B_OK; 71784034Sgad } 7181553Srgrimes 7191553Srgrimes char nameBuffer[B_FILE_NAME_LENGTH]; 7201553Srgrimes nameBuffer[sizeof(nameBuffer) - 1] = 0; 72178750Sgad status_t result = vnode->ops->get_vnode_name(volume, vnode, nameBuffer, 7221553Srgrimes sizeof(nameBuffer) - 1); 72378750Sgad if (result != B_OK) { 72478750Sgad TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result)); 72578750Sgad return result; 72678750Sgad } 72778750Sgad 72878750Sgad OverlayInode *overlayInode = NULL; 72978750Sgad result = get_vnode(overlay, attributeDirInode, (void **)&overlayInode); 73078750Sgad if (result != B_OK) { 73178750Sgad TRACE_ALWAYS("getting attribute directory vnode failed: %s\n", 73278750Sgad strerror(result)); 7331553Srgrimes return result; 7341553Srgrimes } 7351553Srgrimes 7361553Srgrimes fs_vnode attributeDir = *overlayInode->SuperVnode(); 7371553Srgrimes if (attributeDir.ops->unlink == NULL) { 7381553Srgrimes TRACE_ALWAYS("cannot remove attribute file, unlink hook missing\n"); 7391553Srgrimes put_vnode(volume, attributeDirInode); 7401553Srgrimes return B_UNSUPPORTED; 7411553Srgrimes } 74278750Sgad 7431553Srgrimes result = attributeDir.ops->unlink(volume, &attributeDir, nameBuffer); 74478750Sgad if (result != B_OK) { 74578750Sgad TRACE_ALWAYS("failed to unlink attribute file: %s\n", strerror(result)); 74678750Sgad put_vnode(volume, attributeDirInode); 74778750Sgad return result; 74878750Sgad } 7491553Srgrimes 7501553Srgrimes put_vnode(volume, attributeDirInode); 7511553Srgrimes return B_OK; 75287034Sgad} 75387034Sgad 7541553Srgrimes 75578750Sgaduint32 75678750SgadAttributeFile::CountAttributes() 75778750Sgad{ 75878750Sgad if (fFile == NULL) 75978750Sgad return 0; 76078750Sgad 76178750Sgad return fFile->entry_count; 76278750Sgad} 76378750Sgad 76478750Sgad 7651553SrgrimesAttributeEntry * 7661553SrgrimesAttributeFile::FindAttribute(const char *name, uint32 *index) 7671553Srgrimes{ 7681553Srgrimes for (uint32 i = 0; i < fFile->entry_count; i++) { 76978750Sgad if (strcmp(fEntries[i]->Name(), name) == 0) { 77078750Sgad if (index) 77178750Sgad *index = i; 77278750Sgad 77378750Sgad return fEntries[i]; 77478750Sgad } 77578750Sgad } 77678750Sgad 77778750Sgad return NULL; 77878750Sgad} 77978750Sgad 78078750Sgad 78178750Sgadstatus_t 78278750SgadAttributeFile::CreateAttribute(const char *name, type_code type, int openMode, 78378750Sgad AttributeEntry **_entry) 78427618Simp{ 7851553Srgrimes AttributeEntry *existing = FindAttribute(name); 78678146Sgad if (existing != NULL) { 7871553Srgrimes if ((openMode & O_TRUNC) != 0) 78878750Sgad existing->SetSize(0); 78978750Sgad 79078750Sgad // attribute already exists, only allow if the attribute type is 79178750Sgad // compatible or the attribute size is 0 79278750Sgad if (existing->Type() != type) { 79378750Sgad if (existing->Size() != 0) 79478750Sgad return B_FILE_EXISTS; 79578750Sgad existing->SetType(type); 79678750Sgad } 79778750Sgad 79878750Sgad if (existing->InitCheck() == B_OK) { 799241852Seadler *_entry = existing; 80078750Sgad return B_OK; 801241852Seadler } 80278750Sgad 80378750Sgad // we tried to change the existing item but failed, try to just 80478750Sgad // remove it instead and creating a new one 80578750Sgad RemoveAttribute(name, NULL); 80678750Sgad } 80778750Sgad 80878750Sgad AttributeEntry *entry = new(std::nothrow) AttributeEntry(this, name, type); 80978750Sgad if (entry == NULL) 81084034Sgad return B_NO_MEMORY; 81178750Sgad 81278750Sgad status_t result = AddAttribute(entry); 81378750Sgad if (result != B_OK) { 81478750Sgad delete entry; 81578750Sgad return result; 81678750Sgad } 81778750Sgad 81878750Sgad *_entry = entry; 81978750Sgad return B_OK; 82078750Sgad} 82178750Sgad 82278750Sgad 823241852Seadlerstatus_t 82478750SgadAttributeFile::OpenAttribute(const char *name, int openMode, 825241852Seadler AttributeEntry **_entry) 82678750Sgad{ 82778750Sgad AttributeEntry *entry = FindAttribute(name); 82878750Sgad if (entry == NULL) 82978750Sgad return B_ENTRY_NOT_FOUND; 83078750Sgad 83178750Sgad if (openMode & O_TRUNC) 83278750Sgad entry->SetSize(0); 83378750Sgad 83478750Sgad *_entry = entry; 83578750Sgad return B_OK; 83678750Sgad} 83778750Sgad 83878750Sgad 83978750Sgadstatus_t 84078750SgadAttributeFile::RemoveAttribute(const char *name, AttributeEntry **_entry) 84178750Sgad{ 84278750Sgad uint32 index = 0; 84378750Sgad AttributeEntry *entry = FindAttribute(name, &index); 84478750Sgad if (entry == NULL) 845241852Seadler return B_ENTRY_NOT_FOUND; 84678750Sgad 847241852Seadler for (uint32 i = index + 1; i < fFile->entry_count; i++) 84878750Sgad fEntries[i - 1] = fEntries[i]; 84978750Sgad fFile->entry_count--; 85078750Sgad 85178750Sgad if (_entry) 85278750Sgad *_entry = entry; 85378750Sgad else 85478750Sgad delete entry; 85578750Sgad 85678750Sgad notify_attribute_changed(fVolumeID, fFileInode, name, B_ATTR_REMOVED); 85778750Sgad return B_OK; 85878750Sgad} 85978750Sgad 86078750Sgad 86178750Sgadstatus_t 86278750SgadAttributeFile::AddAttribute(AttributeEntry *entry) 86378750Sgad{ 86478750Sgad status_t result = entry->InitCheck(); 86578750Sgad if (result != B_OK) 86678750Sgad return result; 86778750Sgad 86878750Sgad if (FindAttribute(entry->Name()) != NULL) 86978750Sgad return B_FILE_EXISTS; 8701553Srgrimes 8711553Srgrimes AttributeEntry **newEntries = (AttributeEntry **)realloc(fEntries, 8721553Srgrimes (fFile->entry_count + 1) * sizeof(AttributeEntry *)); 87398152Sgad if (newEntries == NULL) 87498152Sgad return B_NO_MEMORY; 87598152Sgad 87698152Sgad fEntries = newEntries; 87798152Sgad fEntries[fFile->entry_count++] = entry; 87898152Sgad 87998152Sgad notify_attribute_changed(fVolumeID, fFileInode, entry->Name(), 88098152Sgad B_ATTR_CREATED); 88198152Sgad 88298152Sgad return B_OK; 88398152Sgad} 88498152Sgad 88598152Sgad 88698152Sgadstatus_t 88798152SgadAttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize, 8881553Srgrimes uint32 *numEntries, uint32 *index) 8891553Srgrimes{ 8901553Srgrimes if (fFile == NULL || *index >= fFile->entry_count) { 89198152Sgad *numEntries = 0; 89298152Sgad return B_OK; 89398152Sgad } 89498152Sgad 89598152Sgad return fEntries[(*index)++]->FillDirent(dirent, bufferSize, numEntries); 89698152Sgad} 89798152Sgad 89898152Sgad 89998152Sgad// #pragma mark AttributeEntry 90098152Sgad 90198152Sgad 90298152SgadAttributeEntry::AttributeEntry(AttributeFile *parent, uint8 *buffer) 9031553Srgrimes : 90498278Sgad fParent(parent), 90598278Sgad fEntry(NULL), 90698278Sgad fData(NULL), 90798278Sgad fStatus(B_NO_INIT), 90898278Sgad fAllocatedEntry(false), 90998278Sgad fAllocatedData(false) 91098278Sgad{ 91198278Sgad if (buffer == NULL) 91298278Sgad return; 91398278Sgad 91498278Sgad fEntry = (attribute_entry *)buffer; 91598278Sgad fData = (uint8 *)fEntry->name + fEntry->name_length; 91698278Sgad fStatus = B_OK; 91798278Sgad} 91898278Sgad 91998278Sgad 92098278SgadAttributeEntry::AttributeEntry(AttributeFile *parent, const char *name, 92198278Sgad type_code type) 92298278Sgad : 92398278Sgad fParent(parent), 92498278Sgad fEntry(NULL), 92598278Sgad fData(NULL), 92698278Sgad fStatus(B_NO_INIT), 92798278Sgad fAllocatedEntry(false), 92898278Sgad fAllocatedData(false) 92998278Sgad{ 93098278Sgad fStatus = SetName(name); 93198278Sgad if (fStatus != B_OK) 93298278Sgad return; 93398278Sgad 93498278Sgad fEntry->type = type; 93598278Sgad fEntry->size = 0; 93698278Sgad} 93798278Sgad 93898278Sgad 93998278SgadAttributeEntry::~AttributeEntry() 94098278Sgad{ 94198278Sgad if (fAllocatedEntry) 94298278Sgad free(fEntry); 94398278Sgad if (fAllocatedData) 94498278Sgad free(fData); 94598278Sgad} 94698278Sgad 94798278Sgad 94898278Sgadsize_t 94998278SgadAttributeEntry::EntrySize() 95098278Sgad{ 95198278Sgad return sizeof(attribute_entry) - 1 + fEntry->name_length; 95298278Sgad} 95398278Sgad 95498278Sgad 95598278Sgadstatus_t 95698278SgadAttributeEntry::SetType(type_code type) 9571553Srgrimes{ 9581553Srgrimes fEntry->type = type; 9591553Srgrimes return B_OK; 96078146Sgad} 9611553Srgrimes 9621553Srgrimes 9631553Srgrimesstatus_t 9641553SrgrimesAttributeEntry::SetSize(size_t size) 9651553Srgrimes{ 9661553Srgrimes if (size <= fEntry->size) { 9671553Srgrimes fEntry->size = size; 9681553Srgrimes return B_OK; 96998152Sgad } 97098152Sgad 97198152Sgad if (fAllocatedData) { 97298152Sgad uint8 *newData = (uint8 *)realloc(fData, size); 97398152Sgad if (newData == NULL) { 97498152Sgad fStatus = B_NO_MEMORY; 97598152Sgad return fStatus; 97698152Sgad } 97798152Sgad 97898152Sgad fData = newData; 97998152Sgad fEntry->size = size; 98098152Sgad return B_OK; 98198152Sgad } 98298152Sgad 98398152Sgad uint8 *newData = (uint8 *)malloc(size); 98498152Sgad if (newData == NULL) { 98598152Sgad fStatus = B_NO_MEMORY; 98698152Sgad return fStatus; 987241852Seadler } 98898152Sgad 989241852Seadler memcpy(newData, fData, min_c(fEntry->size, size)); 99098152Sgad fEntry->size = size; 99198152Sgad fAllocatedData = true; 99298152Sgad fData = newData; 99398152Sgad return B_OK; 99498152Sgad} 99598152Sgad 99698152Sgad 99798267Sgadstatus_t 99898267SgadAttributeEntry::SetName(const char *name) 99998267Sgad{ 100098267Sgad size_t nameLength = strlen(name) + 1; 100198267Sgad if (nameLength > 255) { 100298267Sgad fStatus = B_NAME_TOO_LONG; 100398267Sgad return fStatus; 100498267Sgad } 100598267Sgad 100698267Sgad if (!fAllocatedEntry || fEntry->name_length < nameLength) { 100798267Sgad attribute_entry *newEntry = (attribute_entry *)malloc( 100898267Sgad sizeof(attribute_entry) - 1 + nameLength); 100998267Sgad if (newEntry == NULL) { 101098267Sgad fStatus = B_NO_MEMORY; 101198267Sgad return fStatus; 101298267Sgad } 1013234826Sgad 1014234826Sgad if (fEntry != NULL) 101598267Sgad memcpy(newEntry, fEntry, sizeof(attribute_entry) - 1); 101698267Sgad if (fAllocatedEntry) 101798267Sgad free(fEntry); 101898267Sgad 101998267Sgad fAllocatedEntry = true; 102098267Sgad fEntry = newEntry; 1021234826Sgad } 1022234826Sgad 1023234826Sgad fEntry->name_length = nameLength; 1024234826Sgad strlcpy(fEntry->name, name, nameLength); 1025234826Sgad return B_OK; 1026234826Sgad} 1027234826Sgad 1028234826Sgad 1029234826Sgadstatus_t 1030234826SgadAttributeEntry::FillDirent(struct dirent *dirent, size_t bufferSize, 1031234826Sgad uint32 *numEntries) 1032234826Sgad{ 1033234826Sgad dirent->d_dev = dirent->d_pdev = fParent->VolumeID(); 1034234826Sgad dirent->d_ino = (ino_t)this; 1035234826Sgad dirent->d_pino = fParent->FileInode(); 1036234826Sgad dirent->d_reclen = sizeof(struct dirent) + fEntry->name_length; 103798267Sgad if (bufferSize < dirent->d_reclen) { 103898267Sgad *numEntries = 0; 103998267Sgad return B_BAD_VALUE; 10401553Srgrimes } 10411553Srgrimes 10421553Srgrimes strncpy(dirent->d_name, fEntry->name, fEntry->name_length); 104398152Sgad dirent->d_name[fEntry->name_length - 1] = 0; 104498152Sgad *numEntries = 1; 104598152Sgad return B_OK; 104698152Sgad} 104798152Sgad 104898152Sgad 104998152Sgadstatus_t 105098152SgadAttributeEntry::Read(off_t position, void *buffer, size_t *length) 105198152Sgad{ 105298152Sgad *length = min_c(*length, fEntry->size - position); 1053241852Seadler memcpy(buffer, fData + position, *length); 105498152Sgad return B_OK; 1055241852Seadler} 105698152Sgad 105798152Sgad 105898152Sgadstatus_t 105998152SgadAttributeEntry::Write(off_t position, const void *buffer, size_t *length) 1060241852Seadler{ 106198152Sgad size_t neededSize = position + *length; 106298152Sgad if (neededSize > fEntry->size) { 106398152Sgad status_t result = SetSize(neededSize); 106431492Swollman if (result != B_OK) { 10651553Srgrimes *length = 0; 10661553Srgrimes return result; 106778146Sgad } 10681553Srgrimes } 10691553Srgrimes 10701553Srgrimes memcpy(fData + position, buffer, *length); 10711553Srgrimes notify_attribute_changed(fParent->VolumeID(), fParent->FileInode(), 10721553Srgrimes fEntry->name, B_ATTR_CHANGED); 107331492Swollman return B_OK; 10741553Srgrimes} 107531492Swollman 107631492Swollman 107731492Swollmanstatus_t 10781553SrgrimesAttributeEntry::ReadStat(struct stat *stat) 107931492Swollman{ 108031492Swollman stat->st_dev = fParent->VolumeID(); 10811553Srgrimes stat->st_ino = (ino_t)this; 108231492Swollman stat->st_nlink = 1; 108331492Swollman stat->st_blksize = 512; 10841553Srgrimes stat->st_uid = 1; 10851553Srgrimes stat->st_gid = 1; 10861553Srgrimes stat->st_size = fEntry->size; 10871553Srgrimes stat->st_mode = S_ATTR | 0x0777; 108831492Swollman stat->st_type = fEntry->type; 10891553Srgrimes stat->st_atime = stat->st_mtime = stat->st_crtime = time(NULL); 10901553Srgrimes stat->st_blocks = (fEntry->size + stat->st_blksize - 1) / stat->st_blksize; 10911553Srgrimes return B_OK; 10921553Srgrimes} 10931553Srgrimes 10941553Srgrimes 10951553Srgrimesstatus_t 10961553SrgrimesAttributeEntry::WriteStat(const struct stat *stat, uint32 statMask) 10971553Srgrimes{ 10981553Srgrimes return B_UNSUPPORTED; 109931492Swollman} 11001553Srgrimes 11011553Srgrimes 11021553Srgrimes// #pragma mark - vnode ops 11031553Srgrimes 110431492Swollman 11051553Srgrimesstatic status_t 11061553Srgrimesoverlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) 110719202Simp{ 11081553Srgrimes OverlayInode *node = (OverlayInode *)vnode->private_node; 11091553Srgrimes fs_vnode *superVnode = node->SuperVnode(); 11101553Srgrimes 111125789Sbrian status_t result = B_OK; 111231492Swollman if (superVnode->ops->put_vnode != NULL) { 111331492Swollman result = superVnode->ops->put_vnode(volume->super_volume, superVnode, 11141553Srgrimes reenter); 111525789Sbrian } 111625789Sbrian 111725789Sbrian delete node; 111825789Sbrian return result; 111925789Sbrian} 112025789Sbrian 11211553Srgrimes 11221553Srgrimesstatic status_t 11231553Srgrimesoverlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) 11241553Srgrimes{ 11251553Srgrimes OverlayInode *node = (OverlayInode *)vnode->private_node; 11261553Srgrimes fs_vnode *superVnode = node->SuperVnode(); 11271553Srgrimes 11281553Srgrimes status_t result = B_OK; 11291553Srgrimes if (superVnode->ops->remove_vnode != NULL) { 113098152Sgad result = superVnode->ops->remove_vnode(volume->super_volume, superVnode, 113198152Sgad reenter); 113298152Sgad } 113398152Sgad 113498152Sgad delete node; 113598152Sgad return result; 113698152Sgad} 113798152Sgad 113898152Sgad 113998152Sgadstatic status_t 114098267Sgadoverlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode, 114198267Sgad fs_volume *superVolume, fs_vnode *_superVnode) 114298152Sgad{ 114398152Sgad if (volume == superVolume) { 114468401Sgad *_superVnode = *vnode; 11451553Srgrimes return B_OK; 11461553Srgrimes } 11471553Srgrimes 11481553Srgrimes OverlayInode *node = (OverlayInode *)vnode->private_node; 11491553Srgrimes fs_vnode *superVnode = node->SuperVnode(); 11501553Srgrimes 11511553Srgrimes if (superVnode->ops->get_super_vnode != NULL) { 115278146Sgad return superVnode->ops->get_super_vnode(volume->super_volume, 11531553Srgrimes superVnode, superVolume, _superVnode); 11541553Srgrimes } 11551553Srgrimes 115678146Sgad *_superVnode = *superVnode; 115731492Swollman return B_OK; 11581553Srgrimes} 11591553Srgrimes 116095258Sdes 11611553Srgrimesstatic status_t 11621553Srgrimesoverlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id) 11631553Srgrimes{ 11641553Srgrimes OVERLAY_CALL(lookup, name, id) 116531492Swollman} 116631492Swollman 116778146Sgad 116878146Sgadstatic status_t 116931492Swollmanoverlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer, 117079739Sgad size_t bufferSize) 117131492Swollman{ 117231492Swollman OVERLAY_CALL(get_vnode_name, buffer, bufferSize) 11731553Srgrimes} 117431492Swollman 117531492Swollman 117631492Swollmanstatic bool 117731492Swollmanoverlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie) 117831492Swollman{ 117931492Swollman TRACE("relaying op: can_page\n"); 118031492Swollman OverlayInode *node = (OverlayInode *)vnode->private_node; 11811553Srgrimes fs_vnode *superVnode = node->SuperVnode(); 1182241852Seadler 118331492Swollman if (superVnode->ops->can_page != NULL) { 118431492Swollman return superVnode->ops->can_page(volume->super_volume, superVnode, 118527618Simp cookie); 11861553Srgrimes } 1187241852Seadler 118831492Swollman return false; 11891553Srgrimes} 11901553Srgrimes 11911553Srgrimes 119268401Sgadstatic status_t 11931553Srgrimesoverlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 11941553Srgrimes const iovec *vecs, size_t count, size_t *numBytes) 11951553Srgrimes{ 11961553Srgrimes OVERLAY_CALL(read_pages, cookie, pos, vecs, count, numBytes) 11971553Srgrimes} 11981553Srgrimes 11991553Srgrimes 12001553Srgrimesstatic status_t 12011553Srgrimesoverlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 12021553Srgrimes const iovec *vecs, size_t count, size_t *numBytes) 12031553Srgrimes{ 12041553Srgrimes OVERLAY_CALL(write_pages, cookie, pos, vecs, count, numBytes) 12051553Srgrimes} 12061553Srgrimes 12071553Srgrimes 12081553Srgrimesstatic status_t 12091553Srgrimesoverlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie, 12101553Srgrimes io_request *request) 1211241852Seadler{ 121231492Swollman OVERLAY_CALL(io, cookie, request) 121331492Swollman} 12141553Srgrimes 121527618Simp 1216241852Seadlerstatic status_t 121727618Simpoverlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie, 121827618Simp io_request *request) 12191553Srgrimes{ 12201553Srgrimes OVERLAY_CALL(cancel_io, cookie, request) 12211553Srgrimes} 12221553Srgrimes 12231553Srgrimes 122478146Sgadstatic status_t 12251553Srgrimesoverlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset, 12261553Srgrimes size_t size, struct file_io_vec *vecs, size_t *count) 122727618Simp{ 12281553Srgrimes OVERLAY_CALL(get_file_map, offset, size, vecs, count) 12291553Srgrimes} 12301553Srgrimes 1231241852Seadler 123278146Sgadstatic status_t 1233241852Seadleroverlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op, 123427618Simp void *buffer, size_t length) 12351553Srgrimes{ 12361553Srgrimes OVERLAY_CALL(ioctl, cookie, op, buffer, length) 12371553Srgrimes} 12381553Srgrimes 12391553Srgrimes 12401553Srgrimesstatic status_t 12411553Srgrimesoverlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie, 124278146Sgad int flags) 12431553Srgrimes{ 124468401Sgad OVERLAY_CALL(set_flags, cookie, flags) 12451553Srgrimes} 12461553Srgrimes 12471553Srgrimes 12481553Srgrimesstatic status_t 12491553Srgrimesoverlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, 12501553Srgrimes selectsync *sync) 125127748Simp{ 125227748Simp OVERLAY_CALL(select, cookie, event, sync) 12531553Srgrimes} 125427635Simp 12551553Srgrimes 12561553Srgrimesstatic status_t 12571553Srgrimesoverlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, 12581553Srgrimes selectsync *sync) 12591553Srgrimes{ 12601553Srgrimes OVERLAY_CALL(deselect, cookie, event, sync) 12611553Srgrimes} 12621553Srgrimes 12631553Srgrimes 12641553Srgrimesstatic status_t 12651553Srgrimesoverlay_fsync(fs_volume *volume, fs_vnode *vnode) 12661553Srgrimes{ 12671553Srgrimes OverlayInode *node = (OverlayInode *)vnode->private_node; 12681553Srgrimes fs_vnode *superVnode = node->SuperVnode(); 12691553Srgrimes 12701553Srgrimes if (superVnode->ops->fsync != NULL) 127168401Sgad return superVnode->ops->fsync(volume->super_volume, superVnode); 12721553Srgrimes 12731553Srgrimes return B_OK; 12741553Srgrimes} 12751553Srgrimes 12761553Srgrimes 12771553Srgrimesstatic status_t 12781553Srgrimesoverlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer, 12791553Srgrimes size_t *bufferSize) 128068401Sgad{ 12811553Srgrimes OVERLAY_CALL(read_symlink, buffer, bufferSize) 12821553Srgrimes} 12831553Srgrimes 12841553Srgrimes 12851553Srgrimesstatic status_t 12861553Srgrimesoverlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name, 12871553Srgrimes const char *path, int mode) 12881553Srgrimes{ 12891553Srgrimes OVERLAY_CALL(create_symlink, name, path, mode) 1290241852Seadler} 129168401Sgad 1292241852Seadler 129327618Simpstatic status_t 12941553Srgrimesoverlay_link(fs_volume *volume, fs_vnode *vnode, const char *name, 12951553Srgrimes fs_vnode *target) 12961553Srgrimes{ 12971553Srgrimes OverlayInode *targetNode = (OverlayInode *)target->private_node; 12981553Srgrimes OVERLAY_CALL(link, name, targetNode->SuperVnode()) 12991553Srgrimes} 13001553Srgrimes 13011553Srgrimes 130268401Sgadstatic status_t 13031553Srgrimesoverlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name) 13041553Srgrimes{ 13051553Srgrimes OVERLAY_CALL(unlink, name) 13061553Srgrimes} 13071553Srgrimes 13081553Srgrimes 13091553Srgrimesstatic status_t 131098152Sgadoverlay_rename(fs_volume *volume, fs_vnode *vnode, 131198152Sgad const char *fromName, fs_vnode *toDir, const char *toName) 131298152Sgad{ 131398152Sgad OverlayInode *toDirNode = (OverlayInode *)toDir->private_node; 131498152Sgad OVERLAY_CALL(rename, fromName, toDirNode->SuperVnode(), toName) 131598152Sgad} 131698152Sgad 131798152Sgad 131898152Sgadstatic status_t 131998152Sgadoverlay_access(fs_volume *volume, fs_vnode *vnode, int mode) 132098152Sgad{ 132198152Sgad OVERLAY_CALL(access, mode) 132298152Sgad} 1323241852Seadler 132498152Sgad 1325241852Seadlerstatic status_t 132698152Sgadoverlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat) 132798152Sgad{ 132898152Sgad OVERLAY_CALL(read_stat, stat) 132998152Sgad} 133098152Sgad 1331 1332static status_t 1333overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, 1334 uint32 statMask) 1335{ 1336 OVERLAY_CALL(write_stat, stat, statMask) 1337} 1338 1339 1340static status_t 1341overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name, 1342 int openMode, int perms, void **cookie, ino_t *newVnodeID) 1343{ 1344 OVERLAY_CALL(create, name, openMode, perms, cookie, newVnodeID) 1345} 1346 1347 1348static status_t 1349overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie) 1350{ 1351 OVERLAY_CALL(open, openMode, cookie) 1352} 1353 1354 1355static status_t 1356overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie) 1357{ 1358 OVERLAY_CALL(close, cookie) 1359} 1360 1361 1362static status_t 1363overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1364{ 1365 OVERLAY_CALL(free_cookie, cookie) 1366} 1367 1368 1369static status_t 1370overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1371 void *buffer, size_t *length) 1372{ 1373 OVERLAY_CALL(read, cookie, pos, buffer, length) 1374} 1375 1376 1377static status_t 1378overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1379 const void *buffer, size_t *length) 1380{ 1381 OVERLAY_CALL(write, cookie, pos, buffer, length) 1382} 1383 1384 1385static status_t 1386overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name, 1387 int perms) 1388{ 1389 OVERLAY_CALL(create_dir, name, perms) 1390} 1391 1392 1393static status_t 1394overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name) 1395{ 1396 OVERLAY_CALL(remove_dir, name) 1397} 1398 1399 1400static status_t 1401overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) 1402{ 1403 OVERLAY_CALL(open_dir, cookie) 1404} 1405 1406 1407static status_t 1408overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1409{ 1410 OVERLAY_CALL(close_dir, cookie) 1411} 1412 1413 1414static status_t 1415overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1416{ 1417 OVERLAY_CALL(free_dir_cookie, cookie) 1418} 1419 1420 1421static status_t 1422overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, 1423 struct dirent *buffer, size_t bufferSize, uint32 *num) 1424{ 1425 TRACE("relaying op: read_dir\n"); 1426 OverlayInode *node = (OverlayInode *)vnode->private_node; 1427 fs_vnode *superVnode = node->SuperVnode(); 1428 if (superVnode->ops->read_dir != NULL) { 1429 status_t result = superVnode->ops->read_dir(volume->super_volume, 1430 superVnode, cookie, buffer, bufferSize, num); 1431 1432 // TODO: handle multiple records 1433 if (result == B_OK && *num == 1 && strcmp(buffer->d_name, 1434 ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) { 1435 // skip over the attribute directory 1436 return superVnode->ops->read_dir(volume->super_volume, superVnode, 1437 cookie, buffer, bufferSize, num); 1438 } 1439 1440 return result; 1441 } 1442 1443 return B_UNSUPPORTED; 1444} 1445 1446 1447static status_t 1448overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1449{ 1450 OVERLAY_CALL(rewind_dir, cookie) 1451} 1452 1453 1454static status_t 1455overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) 1456{ 1457 OverlayInode *node = (OverlayInode *)vnode->private_node; 1458 AttributeFile *attributeFile = NULL; 1459 status_t result = node->GetAttributeFile(&attributeFile); 1460 if (result != B_OK) 1461 return result; 1462 1463 attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)malloc( 1464 sizeof(attribute_dir_cookie)); 1465 if (dirCookie == NULL) 1466 return B_NO_MEMORY; 1467 1468 dirCookie->file = attributeFile; 1469 dirCookie->index = 0; 1470 *cookie = dirCookie; 1471 return B_OK; 1472} 1473 1474 1475static status_t 1476overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1477{ 1478 return B_OK; 1479} 1480 1481 1482static status_t 1483overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1484{ 1485 free(cookie); 1486 return B_OK; 1487} 1488 1489 1490static status_t 1491overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, 1492 struct dirent *buffer, size_t bufferSize, uint32 *num) 1493{ 1494 attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie; 1495 return dirCookie->file->ReadAttributeDir(buffer, bufferSize, num, 1496 &dirCookie->index); 1497} 1498 1499 1500static status_t 1501overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1502{ 1503 attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie; 1504 dirCookie->index = 0; 1505 return B_OK; 1506} 1507 1508 1509static status_t 1510overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name, 1511 uint32 type, int openMode, void **cookie) 1512{ 1513 OverlayInode *node = (OverlayInode *)vnode->private_node; 1514 AttributeFile *attributeFile = NULL; 1515 status_t result = node->GetAttributeFile(&attributeFile); 1516 if (result != B_OK) 1517 return result; 1518 1519 return attributeFile->CreateAttribute(name, type, openMode, 1520 (AttributeEntry **)cookie); 1521} 1522 1523 1524static status_t 1525overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name, 1526 int openMode, void **cookie) 1527{ 1528 OverlayInode *node = (OverlayInode *)vnode->private_node; 1529 AttributeFile *attributeFile = NULL; 1530 status_t result = node->GetAttributeFile(&attributeFile); 1531 if (result != B_OK) 1532 return result; 1533 1534 return attributeFile->OpenAttribute(name, openMode, 1535 (AttributeEntry **)cookie); 1536} 1537 1538 1539static status_t 1540overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie) 1541{ 1542 return B_OK; 1543} 1544 1545 1546static status_t 1547overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1548{ 1549 return B_OK; 1550} 1551 1552 1553static status_t 1554overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1555 void *buffer, size_t *length) 1556{ 1557 return ((AttributeEntry *)cookie)->Read(pos, buffer, length); 1558} 1559 1560 1561static status_t 1562overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1563 const void *buffer, size_t *length) 1564{ 1565 return ((AttributeEntry *)cookie)->Write(pos, buffer, length); 1566} 1567 1568 1569static status_t 1570overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, 1571 struct stat *stat) 1572{ 1573 return ((AttributeEntry *)cookie)->ReadStat(stat); 1574} 1575 1576 1577static status_t 1578overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, 1579 const struct stat *stat, int statMask) 1580{ 1581 return ((AttributeEntry *)cookie)->WriteStat(stat, statMask); 1582} 1583 1584 1585static status_t 1586overlay_rename_attr(fs_volume *volume, fs_vnode *vnode, 1587 const char *fromName, fs_vnode *toVnode, const char *toName) 1588{ 1589 OverlayInode *node = (OverlayInode *)vnode->private_node; 1590 AttributeFile *attributeFile = NULL; 1591 status_t result = node->GetAttributeFile(&attributeFile); 1592 if (result != B_OK) 1593 return B_OK; 1594 1595 AttributeFile *toAttributeFile = attributeFile; 1596 if (vnode->private_node != toVnode->private_node) { 1597 OverlayInode *toNode = (OverlayInode *)toVnode->private_node; 1598 result = toNode->GetAttributeFile(&toAttributeFile); 1599 if (result != B_OK) 1600 return result; 1601 } 1602 1603 AttributeEntry *entry = NULL; 1604 result = attributeFile->RemoveAttribute(fromName, &entry); 1605 if (result != B_OK) 1606 return result; 1607 1608 result = entry->SetName(toName); 1609 if (result != B_OK) { 1610 if (attributeFile->AddAttribute(entry) != B_OK) 1611 delete entry; 1612 return result; 1613 } 1614 1615 result = toAttributeFile->AddAttribute(entry); 1616 if (result != B_OK) { 1617 if (entry->SetName(fromName) != B_OK 1618 || attributeFile->AddAttribute(entry) != B_OK) 1619 delete entry; 1620 return result; 1621 } 1622 1623 return B_OK; 1624} 1625 1626 1627static status_t 1628overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name) 1629{ 1630 OverlayInode *node = (OverlayInode *)vnode->private_node; 1631 AttributeFile *attributeFile = NULL; 1632 status_t result = node->GetAttributeFile(&attributeFile); 1633 if (result != B_OK) 1634 return result; 1635 1636 return attributeFile->RemoveAttribute(name, NULL); 1637} 1638 1639 1640static status_t 1641overlay_create_special_node(fs_volume *volume, fs_vnode *vnode, 1642 const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags, 1643 fs_vnode *_superVnode, ino_t *nodeID) 1644{ 1645 OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, 1646 nodeID) 1647} 1648 1649 1650static fs_vnode_ops sOverlayVnodeOps = { 1651 &overlay_lookup, 1652 &overlay_get_vnode_name, 1653 1654 &overlay_put_vnode, 1655 &overlay_remove_vnode, 1656 1657 &overlay_can_page, 1658 &overlay_read_pages, 1659 &overlay_write_pages, 1660 1661 &overlay_io, 1662 &overlay_cancel_io, 1663 1664 &overlay_get_file_map, 1665 1666 /* common */ 1667 &overlay_ioctl, 1668 &overlay_set_flags, 1669 &overlay_select, 1670 &overlay_deselect, 1671 &overlay_fsync, 1672 1673 &overlay_read_symlink, 1674 &overlay_create_symlink, 1675 &overlay_link, 1676 &overlay_unlink, 1677 &overlay_rename, 1678 1679 &overlay_access, 1680 &overlay_read_stat, 1681 &overlay_write_stat, 1682 NULL, // fs_preallocate 1683 1684 /* file */ 1685 &overlay_create, 1686 &overlay_open, 1687 &overlay_close, 1688 &overlay_free_cookie, 1689 &overlay_read, 1690 &overlay_write, 1691 1692 /* directory */ 1693 &overlay_create_dir, 1694 &overlay_remove_dir, 1695 &overlay_open_dir, 1696 &overlay_close_dir, 1697 &overlay_free_dir_cookie, 1698 &overlay_read_dir, 1699 &overlay_rewind_dir, 1700 1701 /* attribute directory operations */ 1702 &overlay_open_attr_dir, 1703 &overlay_close_attr_dir, 1704 &overlay_free_attr_dir_cookie, 1705 &overlay_read_attr_dir, 1706 &overlay_rewind_attr_dir, 1707 1708 /* attribute operations */ 1709 &overlay_create_attr, 1710 &overlay_open_attr, 1711 &overlay_close_attr, 1712 &overlay_free_attr_cookie, 1713 &overlay_read_attr, 1714 &overlay_write_attr, 1715 1716 &overlay_read_attr_stat, 1717 &overlay_write_attr_stat, 1718 &overlay_rename_attr, 1719 &overlay_remove_attr, 1720 1721 /* support for node and FS layers */ 1722 &overlay_create_special_node, 1723 &overlay_get_super_vnode 1724}; 1725 1726 1727// #pragma mark - volume ops 1728 1729 1730static status_t 1731overlay_unmount(fs_volume *volume) 1732{ 1733 TRACE_VOLUME("relaying volume op: unmount\n"); 1734 if (volume->super_volume != NULL 1735 && volume->super_volume->ops != NULL 1736 && volume->super_volume->ops->unmount != NULL) 1737 volume->super_volume->ops->unmount(volume->super_volume); 1738 1739 delete (OverlayVolume *)volume->private_volume; 1740 return B_OK; 1741} 1742 1743 1744static status_t 1745overlay_read_fs_info(fs_volume *volume, struct fs_info *info) 1746{ 1747 TRACE_VOLUME("relaying volume op: read_fs_info\n"); 1748 status_t result = B_UNSUPPORTED; 1749 if (volume->super_volume->ops->read_fs_info != NULL) { 1750 result = volume->super_volume->ops->read_fs_info(volume->super_volume, 1751 info); 1752 if (result != B_OK) 1753 return result; 1754 1755 info->flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR /*| B_FS_HAS_QUERY*/; 1756 return B_OK; 1757 } 1758 1759 return B_UNSUPPORTED; 1760} 1761 1762 1763static status_t 1764overlay_write_fs_info(fs_volume *volume, const struct fs_info *info, 1765 uint32 mask) 1766{ 1767 OVERLAY_VOLUME_CALL(write_fs_info, info, mask) 1768 return B_UNSUPPORTED; 1769} 1770 1771 1772static status_t 1773overlay_sync(fs_volume *volume) 1774{ 1775 TRACE_VOLUME("relaying volume op: sync\n"); 1776 if (volume->super_volume->ops->sync != NULL) 1777 return volume->super_volume->ops->sync(volume->super_volume); 1778 return B_UNSUPPORTED; 1779} 1780 1781 1782static status_t 1783overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type, 1784 uint32 *_flags, bool reenter) 1785{ 1786 TRACE_VOLUME("relaying volume op: get_vnode\n"); 1787 if (volume->super_volume->ops->get_vnode != NULL) { 1788 status_t status = volume->super_volume->ops->get_vnode( 1789 volume->super_volume, id, vnode, _type, _flags, reenter); 1790 if (status != B_OK) 1791 return status; 1792 1793 OverlayInode *node = new(std::nothrow) OverlayInode( 1794 (OverlayVolume *)volume->private_volume, vnode, id); 1795 if (node == NULL) { 1796 vnode->ops->put_vnode(volume->super_volume, vnode, reenter); 1797 return B_NO_MEMORY; 1798 } 1799 1800 status = node->InitCheck(); 1801 if (status != B_OK) { 1802 vnode->ops->put_vnode(volume->super_volume, vnode, reenter); 1803 delete node; 1804 return status; 1805 } 1806 1807 vnode->private_node = node; 1808 vnode->ops = &sOverlayVnodeOps; 1809 return B_OK; 1810 } 1811 1812 return B_UNSUPPORTED; 1813} 1814 1815 1816static status_t 1817overlay_open_index_dir(fs_volume *volume, void **cookie) 1818{ 1819 OVERLAY_VOLUME_CALL(open_index_dir, cookie) 1820 return B_UNSUPPORTED; 1821} 1822 1823 1824static status_t 1825overlay_close_index_dir(fs_volume *volume, void *cookie) 1826{ 1827 OVERLAY_VOLUME_CALL(close_index_dir, cookie) 1828 return B_UNSUPPORTED; 1829} 1830 1831 1832static status_t 1833overlay_free_index_dir_cookie(fs_volume *volume, void *cookie) 1834{ 1835 OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie) 1836 return B_UNSUPPORTED; 1837} 1838 1839 1840static status_t 1841overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer, 1842 size_t bufferSize, uint32 *_num) 1843{ 1844 OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num) 1845 return B_UNSUPPORTED; 1846} 1847 1848 1849static status_t 1850overlay_rewind_index_dir(fs_volume *volume, void *cookie) 1851{ 1852 OVERLAY_VOLUME_CALL(rewind_index_dir, cookie) 1853 return B_UNSUPPORTED; 1854} 1855 1856 1857static status_t 1858overlay_create_index(fs_volume *volume, const char *name, uint32 type, 1859 uint32 flags) 1860{ 1861 OVERLAY_VOLUME_CALL(create_index, name, type, flags) 1862 return B_UNSUPPORTED; 1863} 1864 1865 1866static status_t 1867overlay_remove_index(fs_volume *volume, const char *name) 1868{ 1869 OVERLAY_VOLUME_CALL(remove_index, name) 1870 return B_UNSUPPORTED; 1871} 1872 1873 1874static status_t 1875overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat) 1876{ 1877 OVERLAY_VOLUME_CALL(read_index_stat, name, stat) 1878 return B_UNSUPPORTED; 1879} 1880 1881 1882static status_t 1883overlay_open_query(fs_volume *volume, const char *query, uint32 flags, 1884 port_id port, uint32 token, void **_cookie) 1885{ 1886 OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie) 1887 return B_UNSUPPORTED; 1888} 1889 1890 1891static status_t 1892overlay_close_query(fs_volume *volume, void *cookie) 1893{ 1894 OVERLAY_VOLUME_CALL(close_query, cookie) 1895 return B_UNSUPPORTED; 1896} 1897 1898 1899static status_t 1900overlay_free_query_cookie(fs_volume *volume, void *cookie) 1901{ 1902 OVERLAY_VOLUME_CALL(free_query_cookie, cookie) 1903 return B_UNSUPPORTED; 1904} 1905 1906 1907static status_t 1908overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer, 1909 size_t bufferSize, uint32 *_num) 1910{ 1911 OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num) 1912 return B_UNSUPPORTED; 1913} 1914 1915 1916static status_t 1917overlay_rewind_query(fs_volume *volume, void *cookie) 1918{ 1919 OVERLAY_VOLUME_CALL(rewind_query, cookie) 1920 return B_UNSUPPORTED; 1921} 1922 1923 1924static status_t 1925overlay_all_layers_mounted(fs_volume *volume) 1926{ 1927 return B_OK; 1928} 1929 1930 1931static status_t 1932overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode) 1933{ 1934 OverlayInode *node = new(std::nothrow) OverlayInode( 1935 (OverlayVolume *)volume->private_volume, vnode, id); 1936 if (node == NULL) 1937 return B_NO_MEMORY; 1938 1939 status_t status = node->InitCheck(); 1940 if (status != B_OK) { 1941 delete node; 1942 return status; 1943 } 1944 1945 vnode->private_node = node; 1946 vnode->ops = &sOverlayVnodeOps; 1947 return B_OK; 1948} 1949 1950 1951static status_t 1952overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode) 1953{ 1954 delete (OverlayInode *)vnode->private_node; 1955 return B_OK; 1956} 1957 1958 1959static fs_volume_ops sOverlayVolumeOps = { 1960 &overlay_unmount, 1961 1962 &overlay_read_fs_info, 1963 &overlay_write_fs_info, 1964 &overlay_sync, 1965 1966 &overlay_get_vnode, 1967 &overlay_open_index_dir, 1968 &overlay_close_index_dir, 1969 &overlay_free_index_dir_cookie, 1970 &overlay_read_index_dir, 1971 &overlay_rewind_index_dir, 1972 1973 &overlay_create_index, 1974 &overlay_remove_index, 1975 &overlay_read_index_stat, 1976 1977 &overlay_open_query, 1978 &overlay_close_query, 1979 &overlay_free_query_cookie, 1980 &overlay_read_query, 1981 &overlay_rewind_query, 1982 1983 &overlay_all_layers_mounted, 1984 &overlay_create_sub_vnode, 1985 &overlay_delete_sub_vnode 1986}; 1987 1988 1989// #pragma mark - filesystem module 1990 1991 1992static status_t 1993overlay_mount(fs_volume *volume, const char *device, uint32 flags, 1994 const char *args, ino_t *rootID) 1995{ 1996 TRACE_VOLUME("mounting attribute overlay\n"); 1997 volume->private_volume = new(std::nothrow) OverlayVolume(volume); 1998 if (volume->private_volume == NULL) 1999 return B_NO_MEMORY; 2000 2001 volume->ops = &sOverlayVolumeOps; 2002 return B_OK; 2003} 2004 2005 2006static status_t 2007overlay_std_ops(int32 op, ...) 2008{ 2009 switch (op) { 2010 case B_MODULE_INIT: 2011 case B_MODULE_UNINIT: 2012 return B_OK; 2013 default: 2014 return B_ERROR; 2015 } 2016} 2017 2018 2019static file_system_module_info sOverlayFileSystem = { 2020 { 2021 "file_systems/attribute_overlay" B_CURRENT_FS_API_VERSION, 2022 0, 2023 overlay_std_ops, 2024 }, 2025 2026 "attribute_overlay", // short_name 2027 "Attribute Overlay File System", // pretty_name 2028 0, // DDM flags 2029 2030 // scanning 2031 NULL, // identify_partition 2032 NULL, // scan_partition 2033 NULL, // free_identify_partition_cookie 2034 NULL, // free_partition_content_cookie 2035 2036 // general operations 2037 &overlay_mount, 2038 2039 // capability querying 2040 NULL, // get_supported_operations 2041 2042 NULL, // validate_resize 2043 NULL, // validate_move 2044 NULL, // validate_set_content_name 2045 NULL, // validate_set_content_parameters 2046 NULL, // validate_initialize 2047 2048 // shadow partition modification 2049 NULL, // shadow_changed 2050 2051 // writing 2052 NULL, // defragment 2053 NULL, // repair 2054 NULL, // resize 2055 NULL, // move 2056 NULL, // set_content_name 2057 NULL, // set_content_parameters 2058 NULL // initialize 2059}; 2060 2061} // namespace attribute_overlay 2062 2063using namespace attribute_overlay; 2064 2065module_info *modules[] = { 2066 (module_info *)&sOverlayFileSystem, 2067 NULL, 2068}; 2069