From e69641817887c1c0b7eff8e2de791da945b8db3d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 23 Feb 2007 01:01:26 +0000 Subject: [PATCH] * Split the Node references and referrers concepts. One can now have a reference without being a referring entry. * Reworked entry renaming. We do now remove the original entry first and then create a target entry. Renaming directories didn't work before since there would temporarily have been two links to a directory, which is not allowed. Replacing an entry was also broken: The original entry was not removed. Due to reversing the entry creation/deletion order we also do no longer suffer from the Tracker bug, that entries would disappear from queries when being renamed. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20204 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../r5/src/test/ramfs/Directory.cpp | 2 +- .../userlandfs/r5/src/test/ramfs/Node.cpp | 57 ++++++++++++------- .../userlandfs/r5/src/test/ramfs/Node.h | 5 +- .../r5/src/test/ramfs/kernel_interface.cpp | 52 ++++++++++++----- 4 files changed, 78 insertions(+), 38 deletions(-) diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Directory.cpp b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Directory.cpp index b936bd6082..1f54efd305 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Directory.cpp +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Directory.cpp @@ -32,7 +32,7 @@ Directory::~Directory() status_t Directory::Link(Entry *entry) { - if (GetRefCount() == 0) + if (fReferrers.IsEmpty()) return Node::Link(entry); return B_IS_A_DIRECTORY; } diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Node.cpp b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Node.cpp index e8947d5a5b..bf01a2b7c6 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Node.cpp +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Node.cpp @@ -80,23 +80,44 @@ Node::InitCheck() const return (fVolume && fID >= 0 ? B_OK : B_NO_INIT); } +// AddReference +status_t +Node::AddReference() +{ + if (++fRefCount == 1) { + status_t error = GetVolume()->NewNode(this); + if (error != B_OK) { + fRefCount--; + return error; + } + + fIsKnownToVFS = true; + } + + return B_OK; +} + +// RemoveReference +void +Node::RemoveReference() +{ + if (--fRefCount == 0) { + GetVolume()->RemoveNode(this); + fRefCount++; + } +} + // Link status_t Node::Link(Entry *entry) { PRINT(("Node[%Ld]::Link(): %ld ->...\n", fID, fRefCount)); - status_t error = B_OK; fReferrers.Insert(entry); - if (++fRefCount == 1) { -// error = GetVolume()->NodeAdded(this); - error = GetVolume()->NewNode(this); - if (error == B_OK) - fIsKnownToVFS = true; - else { - fRefCount--; - fReferrers.Remove(entry); - } - } + + status_t error = AddReference(); + if (error != B_OK) + fReferrers.Remove(entry); + return error; } @@ -105,16 +126,10 @@ status_t Node::Unlink(Entry *entry) { PRINT(("Node[%Ld]::Unlink(): %ld ->...\n", fID, fRefCount)); - status_t error = B_OK; - if (--fRefCount == 0) { -// error = GetVolume()->NodeRemoved(this); - error = GetVolume()->RemoveNode(this); - if (error != B_OK) - fRefCount++; - } - if (error == B_OK) - fReferrers.Remove(entry); - return error; + RemoveReference(); + fReferrers.Remove(entry); + + return B_OK; } // SetMTime diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Node.h b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Node.h index d7e51f1a78..c85fd13d4e 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Node.h +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Node.h @@ -41,9 +41,12 @@ public: inline vnode_id GetID() const { return fID; } + status_t AddReference(); + void RemoveReference(); + int32 GetRefCount() { return fRefCount; } + virtual status_t Link(Entry *entry); virtual status_t Unlink(Entry *entry); - int32 GetRefCount() { return fRefCount; } inline bool IsDirectory() const { return S_ISDIR(fMode); } inline bool IsFile() const { return S_ISREG(fMode); } diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/kernel_interface.cpp b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/kernel_interface.cpp index 207a9973c0..031be352e6 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/kernel_interface.cpp +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/kernel_interface.cpp @@ -873,15 +873,18 @@ ramfs_rename(void *ns, void *_oldDir, const char *oldName, Directory *oldDir = dynamic_cast((Node*)_oldDir); Directory *newDir = dynamic_cast((Node*)_newDir); status_t error = B_OK; + // check name if (!oldName || *oldName == '\0' || !strcmp(oldName, ".") || !strcmp(oldName, "..") || !newName || *newName == '\0' || !strcmp(newName, ".") || !strcmp(newName, "..")) { SET_ERROR(error, B_BAD_VALUE); + // check nodes } else if (!oldDir || !newDir) { SET_ERROR(error, B_BAD_VALUE); + // check if the entry isn't actually moved or renamed } else if (oldDir == newDir && !strcmp(oldName, newName)) { SET_ERROR(error, B_BAD_VALUE); @@ -890,14 +893,17 @@ FUNCTION(("old dir: %Ld, old name: `%s', new dir: %Ld, new name: `%s'\n", oldDir->GetID(), oldName, newDir->GetID(), newName)); NodeMTimeUpdater mTimeUpdater1(oldDir); NodeMTimeUpdater mTimeUpdater2(newDir); + // target directory deleted? if (is_vnode_removed(volume->GetID(), newDir->GetID()) > 0) SET_ERROR(error, B_NOT_ALLOWED); + // check directory write permissions if (error == B_OK) error = oldDir->CheckPermissions(ACCESS_W); if (error == B_OK) error = newDir->CheckPermissions(ACCESS_W); + Node *node = NULL; Entry *entry = NULL; if (error == B_OK) { @@ -919,6 +925,7 @@ oldDir->GetID(), oldName, newDir->GetID(), newName)); } } } + // check the target directory situation Node *clobberNode = NULL; Entry *clobberEntry = NULL; @@ -931,33 +938,47 @@ oldDir->GetID(), oldName, newDir->GetID(), newName)); } } } + // do the job if (error == B_OK) { - if (clobberEntry) { - error = clobberEntry->Link(node); - // notify listeners + // temporarily acquire an additional reference to make + // sure the node isn't deleted when we remove the entry + error = node->AddReference(); + if (error == B_OK) { + // delete the original entry + error = oldDir->DeleteEntry(entry); if (error == B_OK) { - notify_listener(B_ENTRY_REMOVED, - volume->GetID(), newDir->GetID(), 0, - clobberNode->GetID(), NULL); - } - } else { - Entry *newEntry = NULL; -// TODO: If the node is a directory, this does fail!!! - error = newDir->CreateEntry(node, newName, &newEntry); - if (error == B_OK) { - error = oldDir->DeleteEntry(entry); - if (error != B_OK) - newDir->DeleteEntry(newEntry); + // create the new one/relink the target entry + if (clobberEntry) + error = clobberEntry->Link(node); + else + error = newDir->CreateEntry(node, newName); + + if (error == B_OK) { + // send a "removed" notification for the clobbered + // entry + if (clobberEntry) { + notify_listener(B_ENTRY_REMOVED, + volume->GetID(), newDir->GetID(), 0, + clobberNode->GetID(), newName); + } + } else { + // try to recreate the original entry, in case of + // failure + newDir->CreateEntry(node, oldName); + } } + node->RemoveReference(); } } + // release the entries if (clobberEntry) volume->PutNode(clobberNode); if (entry) volume->PutNode(node); } + // notify listeners if (error == B_OK) { notify_listener(B_ENTRY_MOVED, volume->GetID(), oldDir->GetID(), @@ -965,6 +986,7 @@ oldDir->GetID(), oldName, newDir->GetID(), newName)); } } else SET_ERROR(error, B_ERROR); + RETURN_ERROR(error); }