added 5 changesets to branch 'refs/remotes/pdziepak-github/nfs4_attr' old head: 0000000000000000000000000000000000000000 new head: 7cca381a1508e72d80be45370f7f44bdc5ef667a overview: https://github.com/pdziepak/Haiku/compare/7cca381 ---------------------------------------------------------------------------- 996c494: attribute_overlay: Do not require get_vnode_name() hook File systems that support hard links cannot really implement get_vnode_name(). That prevents attribute_overlay from working with such file systems. It is true that attribute_overlay does not support hard links either, but if the user knows about its limitations there is no reason to prevent it from being used. 2cadf56: attribute_overlay: Fix NULL dereference a0d8b49: attribute_overlay: Save modified attributes b6fa76f: attribute_overlay: read_dir: Handle multiple entries properly 7cca381: attribute_overlay: Ignore errors at creating _HAIKU directory Someone else may have created that directory after out initial lookup. [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- 1 file changed, 163 insertions(+), 61 deletions(-) .../attribute_overlay/attribute_overlay.cpp | 224 ++++++++++++++----- ############################################################################ Commit: 996c494e026dfb9b5926f5f760c25d0f59a068a2 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Mon Feb 24 02:43:36 2014 UTC attribute_overlay: Do not require get_vnode_name() hook File systems that support hard links cannot really implement get_vnode_name(). That prevents attribute_overlay from working with such file systems. It is true that attribute_overlay does not support hard links either, but if the user knows about its limitations there is no reason to prevent it from being used. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp index 201c558..df7c310 100644 --- a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp +++ b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp @@ -1,8 +1,9 @@ /* - * Copyright 2009-2010, Haiku Inc. All rights reserved. + * Copyright 2009-2014, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: + * Paweł Dziepak <pdziepak@xxxxxxxxxxx> * Michael Lotz <mmlr@xxxxxxxx> */ @@ -92,6 +93,8 @@ public: fs_vnode * SuperVnode() { return &fSuperVnode; } ino_t InodeNumber() { return fInodeNumber; } + status_t GetName(char* name, size_t length); + status_t GetAttributeFile(AttributeFile **attributeFile); status_t WriteAttributeFile(); status_t RemoveAttributeFile(); @@ -106,8 +109,8 @@ private: class AttributeFile { public: - AttributeFile(fs_volume *overlay, - fs_volume *volume, fs_vnode *vnode); + AttributeFile(fs_volume* overlay, + fs_volume* volume, OverlayInode* subVnode); ~AttributeFile(); status_t InitCheck() { return fStatus; } @@ -116,10 +119,10 @@ public: ino_t FileInode() { return fFileInode; } status_t CreateEmpty(); - status_t WriteAttributeFile(fs_volume *overlay, - fs_volume *volume, fs_vnode *vnode); - status_t RemoveAttributeFile(fs_volume *overlay, - fs_volume *volume, fs_vnode *vnode); + status_t WriteAttributeFile(fs_volume* overlay, + fs_volume* volume, OverlayInode* subVnode); + status_t RemoveAttributeFile(fs_volume* overlay, + fs_volume* volume, OverlayInode* subVnode); status_t ReadAttributeDir(struct dirent *dirent, size_t bufferSize, uint32 *numEntries, @@ -256,11 +259,97 @@ OverlayInode::InitCheck() status_t +OverlayInode::GetName(char* name, size_t length) +{ + if (fSuperVnode.ops->get_vnode_name != NULL) { + name[length - 1] = '\0'; + status_t result = fSuperVnode.ops->get_vnode_name(Volume(), + &fSuperVnode, name, length - 1); + if (result == B_OK) + return B_OK; + } + + if (fSuperVnode.ops->lookup == NULL) { + TRACE_ALWAYS("cannot get vnode name, required hooks missing\n"); + return B_UNSUPPORTED; + } + + // TODO: we are using a hack here, cf. TODO in AttributeFile constructor + ino_t parentInode; + status_t result + = fSuperVnode.ops->lookup(Volume(), &fSuperVnode, "..", &parentInode); + if (result != B_OK) + return result; + + if (parentInode == fInodeNumber) + strlcpy(name, "_ROOT_DIR", length); + else { + OverlayInode* overlayInode; + result = get_vnode(Volume(), parentInode, (void **)&overlayInode); + if (result != B_OK) { + TRACE_ALWAYS("getting vnode failed: %s\n", strerror(result)); + return result; + } + + fs_vnode parentVnode = *overlayInode->SuperVnode(); + + if (parentVnode.ops->open_dir == NULL + || parentVnode.ops->read_dir == NULL) { + TRACE_ALWAYS("cannot get vnode name, required hooks missing\n"); + put_vnode(Volume(), parentInode); + return B_UNSUPPORTED; + } + + void* cookie; + result = parentVnode.ops->open_dir(Volume(), &parentVnode, &cookie); + if (result != B_OK) { + TRACE_ALWAYS("cannot open parent directory\n"); + put_vnode(Volume(), parentInode); + return result; + } + + uint8 directoryEntryBuffer[sizeof(dirent) + B_FILE_NAME_LENGTH]; + dirent* directoryEntry = (dirent*)directoryEntryBuffer; + while (true) { + uint32 entriesRead = 1; + + result = parentVnode.ops->read_dir(Volume(), &parentVnode, cookie, + (dirent*)directoryEntryBuffer, sizeof(directoryEntryBuffer), + &entriesRead); + if (entriesRead == 0) + result = B_ENTRY_NOT_FOUND; + if (result != B_OK) + break; + if (directoryEntry->d_ino != fInodeNumber) + continue; + + strlcpy(name, directoryEntry->d_name, length); + break; + } + + if (parentVnode.ops->close_dir != NULL) + parentVnode.ops->close_dir(Volume(), &parentVnode, cookie); + if (parentVnode.ops->free_dir_cookie != NULL) + parentVnode.ops->free_dir_cookie(Volume(), &parentVnode, cookie); + + put_vnode(Volume(), parentInode); + + if (result != B_OK) { + TRACE_ALWAYS("could not find vnode in its parent directory\n"); + return result; + } + } + + return B_OK; +} + + +status_t OverlayInode::GetAttributeFile(AttributeFile **attributeFile) { if (fAttributeFile == NULL) { fAttributeFile = new(std::nothrow) AttributeFile(Volume(), - SuperVolume(), &fSuperVnode); + SuperVolume(), this); if (fAttributeFile == NULL) { TRACE_ALWAYS("no memory to allocate attribute file\n"); return B_NO_MEMORY; @@ -294,8 +383,7 @@ OverlayInode::WriteAttributeFile() if (result != B_OK) return result; - return fAttributeFile->WriteAttributeFile(Volume(), SuperVolume(), - &fSuperVnode); + return fAttributeFile->WriteAttributeFile(Volume(), SuperVolume(), this); } @@ -309,8 +397,7 @@ OverlayInode::RemoveAttributeFile() if (result != B_OK) return result; - return fAttributeFile->RemoveAttributeFile(Volume(), SuperVolume(), - &fSuperVnode); + return fAttributeFile->RemoveAttributeFile(Volume(), SuperVolume(), this); } @@ -318,11 +405,11 @@ OverlayInode::RemoveAttributeFile() AttributeFile::AttributeFile(fs_volume *overlay, fs_volume *volume, - fs_vnode *vnode) + OverlayInode* subVnode) : fStatus(B_NO_INIT), fVolumeID(volume->id), - fFileInode(0), + fFileInode(subVnode->InodeNumber()), fDirectoryInode(0), fAttributeDirInode(0), fAttributeFileInode(0), @@ -330,20 +417,10 @@ AttributeFile::AttributeFile(fs_volume *overlay, fs_volume *volume, 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)); + fStatus = subVnode->GetName(nameBuffer, B_FILE_NAME_LENGTH); + if (fStatus != B_OK) return; - } if (strcmp(nameBuffer, ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) { // we don't want attribute overlays on the attribute dir itself @@ -351,12 +428,6 @@ AttributeFile::AttributeFile(fs_volume *overlay, fs_volume *volume, 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 @@ -365,7 +436,7 @@ AttributeFile::AttributeFile(fs_volume *overlay, fs_volume *volume, const char *lookup[] = { "..", ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, nameBuffer }; int32 lookupCount = sizeof(lookup) / sizeof(lookup[0]); - fs_vnode currentVnode = *vnode; + fs_vnode currentVnode = *subVnode->SuperVnode(); ino_t lastInodeNumber = 0; for (int32 i = 0; i < lookupCount; i++) { @@ -418,6 +489,7 @@ AttributeFile::AttributeFile(fs_volume *overlay, fs_volume *volume, return; } + struct stat stat; fStatus = currentVnode.ops->read_stat(volume, ¤tVnode, &stat); if (fStatus != B_OK) { TRACE_ALWAYS("failed to stat attribute file: %s\n", strerror(fStatus)); @@ -534,22 +606,20 @@ AttributeFile::CreateEmpty() status_t -AttributeFile::WriteAttributeFile(fs_volume *overlay, fs_volume *volume, - fs_vnode *vnode) +AttributeFile::WriteAttributeFile(fs_volume* overlay, fs_volume* volume, + OverlayInode* subVnode) { if (fFile == NULL) 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); + status_t result = subVnode->GetName(nameBuffer, B_FILE_NAME_LENGTH); if (result != B_OK) { TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result)); return result; } - fs_vnode currentVnode = *vnode; + fs_vnode currentVnode = *subVnode->SuperVnode(); if (fDirectoryInode == 0) { if (currentVnode.ops->lookup == NULL) { TRACE_ALWAYS("lookup not possible, lookup hook missing\n"); @@ -700,8 +770,8 @@ close_and_put: status_t -AttributeFile::RemoveAttributeFile(fs_volume *overlay, fs_volume *volume, - fs_vnode *vnode) +AttributeFile::RemoveAttributeFile(fs_volume* overlay, fs_volume* volume, + OverlayInode* subVnode) { bool hasAttributeFile = fAttributeFileInode != 0; ino_t attributeDirInode = fAttributeDirInode; @@ -717,9 +787,7 @@ AttributeFile::RemoveAttributeFile(fs_volume *overlay, fs_volume *volume, } 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); + status_t result = subVnode->GetName(nameBuffer, B_FILE_NAME_LENGTH); if (result != B_OK) { TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result)); return result; ############################################################################ Commit: 2cadf566f140374926d9d9f5d6d0e0f3b6ba8967 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Tue Feb 25 00:10:52 2014 UTC attribute_overlay: Fix NULL dereference ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp index df7c310..c8da506 100644 --- a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp +++ b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp @@ -833,6 +833,9 @@ AttributeFile::CountAttributes() AttributeEntry * AttributeFile::FindAttribute(const char *name, uint32 *index) { + if (fEntries == NULL) + return NULL; + for (uint32 i = 0; i < fFile->entry_count; i++) { if (strcmp(fEntries[i]->Name(), name) == 0) { if (index) ############################################################################ Commit: a0d8b4924b18dc3d3c1791d182f5c67ee590908f Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Tue Feb 25 00:14:47 2014 UTC attribute_overlay: Save modified attributes ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp index c8da506..b8d9a46 100644 --- a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp +++ b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp @@ -732,6 +732,7 @@ AttributeFile::WriteAttributeFile(fs_volume* overlay, fs_volume* volume, size_t writeLength = sizeof(attribute_file) - 1; result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, position, fFile, &writeLength); + position += writeLength; if (result != B_OK) { TRACE_ALWAYS("failed to write to attribute file: %s\n", strerror(result)); @@ -742,6 +743,7 @@ AttributeFile::WriteAttributeFile(fs_volume* overlay, fs_volume* volume, writeLength = fEntries[i]->EntrySize(); result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, position, fEntries[i]->Entry(), &writeLength); + position += writeLength; if (result != B_OK) { TRACE_ALWAYS("failed to write to attribute file: %s\n", strerror(result)); @@ -751,6 +753,7 @@ AttributeFile::WriteAttributeFile(fs_volume* overlay, fs_volume* volume, writeLength = fEntries[i]->DataSize(); result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, position, fEntries[i]->Data(), &writeLength); + position += writeLength; if (result != B_OK) { TRACE_ALWAYS("failed to write to attribute file: %s\n", strerror(result)); @@ -1617,6 +1620,8 @@ overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie) static status_t overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) { + OverlayInode* node = (OverlayInode* )vnode->private_node; + node->WriteAttributeFile(); return B_OK; } @@ -1649,7 +1654,13 @@ static status_t overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, const struct stat *stat, int statMask) { - return ((AttributeEntry *)cookie)->WriteStat(stat, statMask); + status_t result = ((AttributeEntry *)cookie)->WriteStat(stat, statMask); + if (result == B_OK) { + OverlayInode* node = (OverlayInode*)vnode->private_node; + node->WriteAttributeFile(); + } + + return result; } @@ -1691,7 +1702,7 @@ overlay_rename_attr(fs_volume *volume, fs_vnode *vnode, return result; } - return B_OK; + return node->WriteAttributeFile(); } @@ -1704,7 +1715,11 @@ overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name) if (result != B_OK) return result; - return attributeFile->RemoveAttribute(name, NULL); + result = attributeFile->RemoveAttribute(name, NULL); + if (result != B_OK) + return result; + + return node->WriteAttributeFile(); } ############################################################################ Commit: b6fa76f4611f45b559179562cf7f715b0c73cce7 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Tue Feb 25 00:54:08 2014 UTC attribute_overlay: read_dir: Handle multiple entries properly ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp index b8d9a46..ff41bda 100644 --- a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp +++ b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp @@ -1502,13 +1502,31 @@ overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, if (superVnode->ops->read_dir != NULL) { status_t result = superVnode->ops->read_dir(volume->super_volume, superVnode, cookie, buffer, bufferSize, num); + if (result != B_OK) + return result; + + dirent* currentEntry = buffer; + size_t bufferPosition = 0; + for (uint32 i = 0; i < *num; i++) { + size_t entrySize = currentEntry->d_reclen; + dirent* nextEntry = (dirent*)((uint8*)currentEntry + entrySize); + + bufferPosition += entrySize; + if (strcmp(currentEntry->d_name, + ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) { + + // skip over the attribute directory + (*num)--; + if (*num == 0) { + return superVnode->ops->read_dir(volume->super_volume, + superVnode, cookie, buffer, bufferSize, num); + } else { + memmove(currentEntry, nextEntry, + bufferSize - bufferPosition); + } + } - // 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); + currentEntry = nextEntry; } return result; ############################################################################ Commit: 7cca381a1508e72d80be45370f7f44bdc5ef667a Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Tue Feb 25 01:08:08 2014 UTC attribute_overlay: Ignore errors at creating _HAIKU directory Someone else may have created that directory after out initial lookup. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp index ff41bda..b7f0a41 100644 --- a/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp +++ b/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp @@ -650,17 +650,15 @@ AttributeFile::WriteAttributeFile(fs_volume* overlay, fs_volume* volume, currentVnode = *overlayInode->SuperVnode(); // create the attribute directory - result = currentVnode.ops->create_dir(volume, ¤tVnode, + currentVnode.ops->create_dir(volume, ¤tVnode, ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, S_IRWXU | S_IRWXG | S_IRWXO); - if (result == B_OK) { - result = currentVnode.ops->lookup(volume, ¤tVnode, - ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, &fAttributeDirInode); + result = currentVnode.ops->lookup(volume, ¤tVnode, + ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, &fAttributeDirInode); - // lookup() got us a reference we don't need -- put it - if (result == B_OK) - put_vnode(volume, fAttributeDirInode); - } + // lookup() got us a reference we don't need -- put it + if (result == B_OK) + put_vnode(volume, fAttributeDirInode); put_vnode(volume, fDirectoryInode);