From 3b5507a987354eecb93bb2763df41f2b88f5bbad Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Tue, 17 Feb 2009 02:05:58 +0000 Subject: [PATCH] * Added create/write/remove/rename support for attributes to the overlay fs. * Implemented writing attributes back to attribute files. Not tested or enabled. * Fix reading attribute dirs, they need a separate cookie that links attribute files to the dir index as multiple read-dirs could happen at the same time. * Fix some obvious bugs in size calculations. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29239 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/file_systems/overlay/overlay.cpp | 644 ++++++++++++++++-- 1 file changed, 578 insertions(+), 66 deletions(-) diff --git a/src/add-ons/kernel/file_systems/overlay/overlay.cpp b/src/add-ons/kernel/file_systems/overlay/overlay.cpp index 876f4aa112..12e018e851 100644 --- a/src/add-ons/kernel/file_systems/overlay/overlay.cpp +++ b/src/add-ons/kernel/file_systems/overlay/overlay.cpp @@ -40,6 +40,12 @@ class AttributeFile; class AttributeEntry; +struct attribute_dir_cookie { + AttributeFile * file; + uint32 index; +}; + + class OverlayInode { public: OverlayInode(fs_volume *superVolume, @@ -51,12 +57,14 @@ public: fs_volume * SuperVolume() { return fSuperVolume; } fs_vnode * SuperVnode() { return &fSuperVnode; } - AttributeFile * GetAttributeFile(); + status_t GetAttributeFile(AttributeFile **attributeFile); + status_t WriteAttributeFile(); private: fs_volume * fSuperVolume; fs_vnode fSuperVnode; AttributeFile * fAttributeFile; + bool fAttributeFileMissing; }; @@ -68,18 +76,27 @@ public: status_t InitCheck() { return fStatus; } dev_t VolumeID() { return fVolumeID; } - ino_t ParentInode() { return fParentInode; } + ino_t FileInode() { return fFileInode; } - uint32 CountAttributes(); - AttributeEntry * FindAttribute(const char *name); + status_t CreateEmpty(); + status_t WriteAttributeFile(fs_volume *volume, + fs_vnode *vnode); status_t ReadAttributeDir(struct dirent *dirent, - size_t bufferSize, uint32 *numEntries); - status_t RewindAttributeDir() - { - fAttributeDirIndex = 0; - return B_OK; - } + 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' @@ -93,7 +110,10 @@ private: status_t fStatus; dev_t fVolumeID; - ino_t fParentInode; + ino_t fFileInode; + ino_t fDirectoryInode; + ino_t fAttributeDirInode; + ino_t fAttributeFileInode; attribute_file * fFile; uint32 fAttributeDirIndex; AttributeEntry ** fEntries; @@ -104,18 +124,36 @@ class AttributeEntry { public: AttributeEntry(AttributeFile *parent, uint8 *buffer); + AttributeEntry(AttributeFile *parent, + const char *name, type_code type); ~AttributeEntry(); - size_t EntrySize(); + status_t InitCheck() { return fStatus; } - uint8 NameLength() { return fEntry->name_length; } + 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 { @@ -128,6 +166,9 @@ private: AttributeFile * fParent; attribute_entry * fEntry; uint8 * fData; + status_t fStatus; + bool fAllocatedEntry; + bool fAllocatedData; }; @@ -137,7 +178,8 @@ private: OverlayInode::OverlayInode(fs_volume *superVolume, fs_vnode *superVnode) : fSuperVolume(superVolume), fSuperVnode(*superVnode), - fAttributeFile(NULL) + fAttributeFile(NULL), + fAttributeFileMissing(false) { TRACE("inode created\n"); } @@ -157,22 +199,46 @@ OverlayInode::InitCheck() } -AttributeFile * -OverlayInode::GetAttributeFile() +status_t +OverlayInode::GetAttributeFile(AttributeFile **attributeFile) { if (fAttributeFile == NULL) { fAttributeFile = new(std::nothrow) AttributeFile(fSuperVolume, &fSuperVnode); if (fAttributeFile == NULL) { TRACE_ALWAYS("no memory to allocate attribute file\n"); - return NULL; + return B_NO_MEMORY; } } - if (fAttributeFile->InitCheck() != B_OK) - return NULL; + 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 + } - return fAttributeFile; + 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(fSuperVolume, &fSuperVnode); } @@ -182,7 +248,10 @@ OverlayInode::GetAttributeFile() AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode) : fStatus(B_NO_INIT), fVolumeID(volume->id), - fParentInode(0), + fFileInode(0), + fDirectoryInode(0), + fAttributeDirInode(0), + fAttributeFileInode(0), fFile(NULL), fAttributeDirIndex(0), fEntries(NULL) @@ -211,7 +280,7 @@ AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode) struct stat stat; if (vnode->ops->read_stat != NULL && vnode->ops->read_stat(volume, vnode, &stat) == B_OK) { - fParentInode = stat.st_ino; + fFileInode = stat.st_ino; } // TODO: the ".." lookup is not actually valid for non-directory vnodes. @@ -249,6 +318,13 @@ AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode) return; } + if (i == 0) + fDirectoryInode = inodeNumber; + else if (i == 1) + fAttributeDirInode = inodeNumber; + else if (i == 2) + fAttributeFileInode = inodeNumber; + fStatus = get_vnode(volume, inodeNumber, ¤tVnode.private_node, ¤tVnode.ops); if (fStatus != B_OK) { @@ -314,7 +390,8 @@ AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode) return; } - fEntries = new(std::nothrow) AttributeEntry *[fFile->entry_count]; + fEntries = (AttributeEntry **)malloc(fFile->entry_count + * sizeof(AttributeEntry *)); if (fEntries == NULL) { TRACE_ALWAYS("no memory to allocate entry pointers\n"); fStatus = B_NO_MEMORY; @@ -335,7 +412,7 @@ AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode) return; } - totalSize += fEntries[i]->EntrySize(); + totalSize += fEntries[i]->EntrySize() + fEntries[i]->DataSize(); if (totalSize > readLength) { TRACE_ALWAYS("attribute entries are too large for buffer\n"); fStatus = B_BAD_VALUE; @@ -354,13 +431,170 @@ AttributeFile::~AttributeFile() for (uint32 i = 0; i < fFile->entry_count; i++) delete fEntries[i]; - delete [] fEntries; + 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 *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; + if (fAttributeDirInode == 0) { + result = get_vnode(volume, fDirectoryInode, + ¤tVnode.private_node, ¤tVnode.ops); + if (result != B_OK) { + TRACE_ALWAYS("failed to get directory vnode: %s\n", + strerror(result)); + return result; + } + + // 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(volume, fAttributeDirInode, + ¤tVnode.private_node, ¤tVnode.ops); + if (result != B_OK) { + TRACE_ALWAYS("failed to get attribute directory vnode: %s\n", + strerror(result)); + return result; + } + + // 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(volume, fAttributeFileInode, + ¤tVnode.private_node, ¤tVnode.ops); + if (result != B_OK) { + TRACE_ALWAYS("getting attribute file vnode after create failed: %s\n", + strerror(result)); + return result; + } + } else { + result = get_vnode(volume, fAttributeFileInode, + ¤tVnode.private_node, ¤tVnode.ops); + if (result != B_OK) { + TRACE_ALWAYS("getting attribute file vnode failed: %s\n", + strerror(result)); + return result; + } + + // 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() { @@ -372,14 +606,15 @@ AttributeFile::CountAttributes() AttributeEntry * -AttributeFile::FindAttribute(const char *name) +AttributeFile::FindAttribute(const char *name, uint32 *index) { - if (fFile == NULL) - return NULL; - for (uint32 i = 0; i < fFile->entry_count; i++) { - if (strncmp(fEntries[i]->Name(), name, fEntries[i]->NameLength()) == 0) + if (strncmp(fEntries[i]->Name(), name, fEntries[i]->NameLength()) == 0) { + if (index) + *index = i; + return fEntries[i]; + } } return NULL; @@ -387,16 +622,115 @@ AttributeFile::FindAttribute(const char *name) status_t -AttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize, - uint32 *numEntries) +AttributeFile::CreateAttribute(const char *name, type_code type, int openMode, + AttributeEntry **_entry) { - if (fFile == NULL || fAttributeDirIndex >= fFile->entry_count) { + 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; + + 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; + 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[fAttributeDirIndex++]->FillDirent(dirent, bufferSize, - numEntries); + return fEntries[(*index)++]->FillDirent(dirent, bufferSize, numEntries); } @@ -406,22 +740,124 @@ AttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize, AttributeEntry::AttributeEntry(AttributeFile *parent, uint8 *buffer) : fParent(parent), fEntry(NULL), - fData(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 + fEntry->size; + 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)); + 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; } @@ -431,7 +867,7 @@ AttributeEntry::FillDirent(struct dirent *dirent, size_t bufferSize, { dirent->d_dev = dirent->d_pdev = fParent->VolumeID(); dirent->d_ino = (ino_t)this; - dirent->d_pino = fParent->ParentInode(); + dirent->d_pino = fParent->FileInode(); dirent->d_reclen = sizeof(struct dirent) + fEntry->name_length; if (bufferSize < dirent->d_reclen) { *numEntries = 0; @@ -448,14 +884,25 @@ AttributeEntry::FillDirent(struct dirent *dirent, size_t bufferSize, status_t AttributeEntry::Read(off_t position, void *buffer, size_t *length) { - *length = min_c(*length, fEntry->size); - if (*length <= position) { - *length = 0; - return B_OK; + *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; + } } - *length -= position; - memcpy(buffer, fData + position, *length); + memcpy(fData + position, buffer, *length); return B_OK; } @@ -478,6 +925,13 @@ AttributeEntry::ReadStat(struct stat *stat) } +status_t +AttributeEntry::WriteStat(const struct stat *stat, uint32 statMask) +{ + return B_UNSUPPORTED; +} + + // #pragma mark - vnode ops @@ -860,11 +1314,20 @@ static status_t overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) { OVERLAY_CALL(open_attr_dir, cookie) - AttributeFile *attributeFile = node->GetAttributeFile(); - if (attributeFile == NULL) - return B_UNSUPPORTED; - *cookie = attributeFile; + 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; } @@ -881,6 +1344,7 @@ 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; } @@ -890,8 +1354,9 @@ 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) - AttributeFile *attributeFile = (AttributeFile *)cookie; - return attributeFile->ReadAttributeDir(buffer, bufferSize, num); + attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie; + return dirCookie->file->ReadAttributeDir(buffer, bufferSize, num, + &dirCookie->index); } @@ -899,8 +1364,9 @@ static status_t overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) { OVERLAY_CALL(rewind_attr_dir, cookie) - AttributeFile *attributeFile = (AttributeFile *)cookie; - return attributeFile->RewindAttributeDir(); + attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie; + dirCookie->index = 0; + return B_OK; } @@ -909,7 +1375,14 @@ 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) - return B_UNSUPPORTED; + + AttributeFile *attributeFile = NULL; + status_t result = node->GetAttributeFile(&attributeFile); + if (result != B_OK) + return result; + + return attributeFile->CreateAttribute(name, type, openMode, + (AttributeEntry **)cookie); } @@ -919,16 +1392,13 @@ overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name, { OVERLAY_CALL(open_attr, name, openMode, cookie) - AttributeFile *attributeFile = node->GetAttributeFile(); - if (attributeFile == NULL) - return B_UNSUPPORTED; + AttributeFile *attributeFile = NULL; + status_t result = node->GetAttributeFile(&attributeFile); + if (result != B_OK) + return result; - AttributeEntry *entry = attributeFile->FindAttribute(name); - if (entry == NULL) - return B_ENTRY_NOT_FOUND; - - *cookie = entry; - return B_OK; + return attributeFile->OpenAttribute(name, openMode, + (AttributeEntry **)cookie); } @@ -963,7 +1433,8 @@ 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) - return B_UNSUPPORTED; + AttributeEntry *entry = (AttributeEntry *)cookie; + return entry->Write(pos, buffer, length); } @@ -982,7 +1453,8 @@ 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) - return B_UNSUPPORTED; + AttributeEntry *entry = (AttributeEntry *)cookie; + return entry->WriteStat(stat, statMask); } @@ -991,7 +1463,41 @@ 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) - return B_UNSUPPORTED; + + 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; } @@ -999,7 +1505,13 @@ static status_t overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name) { OVERLAY_CALL(remove_attr, name) - return B_UNSUPPORTED; + + AttributeFile *attributeFile = NULL; + status_t result = node->GetAttributeFile(&attributeFile); + if (result != B_OK) + return result; + + return attributeFile->RemoveAttribute(name, NULL); }