Author: bonefish Date: 2010-07-12 18:15:47 +0200 (Mon, 12 Jul 2010) New Revision: 37481 Changeset: http://dev.haiku-os.org/changeset/37481 Added: haiku/trunk/src/tests/system/kernel/file_corruption/fs/SymLink.cpp haiku/trunk/src/tests/system/kernel/file_corruption/fs/SymLink.h Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Jamfile haiku/trunk/src/tests/system/kernel/file_corruption/fs/Volume.cpp haiku/trunk/src/tests/system/kernel/file_corruption/fs/Volume.h haiku/trunk/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp Log: Added symlink support. Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Jamfile =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/Jamfile 2010-07-12 16:11:56 UTC (rev 37480) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/Jamfile 2010-07-12 16:15:47 UTC (rev 37481) @@ -22,6 +22,7 @@ Directory.cpp Node.cpp SuperBlock.cpp + SymLink.cpp Transaction.cpp Volume.cpp ; Added: haiku/trunk/src/tests/system/kernel/file_corruption/fs/SymLink.cpp =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/SymLink.cpp (rev 0) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/SymLink.cpp 2010-07-12 16:15:47 UTC (rev 37481) @@ -0,0 +1,91 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Distributed under the terms of the MIT License. + */ + + +#include "SymLink.h" + +#include <string.h> + +#include "Block.h" +#include "DebugSupport.h" + + +static const size_t kSymLinkDataOffset = sizeof(checksumfs_node); +static const size_t kMaxSymLinkSize = B_PAGE_SIZE - kSymLinkDataOffset; + + +SymLink::SymLink(Volume* volume, uint64 blockIndex, + const checksumfs_node& nodeData) + : + Node(volume, blockIndex, nodeData) +{ +} + + +SymLink::SymLink(Volume* volume, uint64 blockIndex, mode_t mode) + : + Node(volume, blockIndex, mode) +{ +} + + +SymLink::~SymLink() +{ +} + + +status_t +SymLink::Read(char* buffer, size_t toRead, size_t& _bytesRead) +{ + uint64 size = Size(); + if (size > kMaxSymLinkSize) + RETURN_ERROR(B_BAD_DATA); + + if (toRead > size) + toRead = size; + + if (toRead == 0) { + _bytesRead = 0; + return B_OK; + } + + // get the block + Block block; + if (!block.GetReadable(GetVolume(), BlockIndex())) + RETURN_ERROR(B_ERROR); + + const char* data = (char*)block.Data() + kSymLinkDataOffset; + memcpy(buffer, data, toRead); + + _bytesRead = toRead; + return B_OK; +} + + +status_t +SymLink::Write(const char* buffer, size_t toWrite, Transaction& transaction) +{ + uint64 size = Size(); + if (size > kMaxSymLinkSize) + RETURN_ERROR(B_BAD_DATA); + + if (toWrite > kMaxSymLinkSize) + RETURN_ERROR(B_NAME_TOO_LONG); + + if (toWrite == 0) { + SetSize(0); + return B_OK; + } + + Block block; + if (!block.GetWritable(GetVolume(), BlockIndex(), transaction)) + return B_ERROR; + + char* data = (char*)block.Data() + kSymLinkDataOffset; + memcpy(data, buffer, toWrite); + SetSize(toWrite); + + return B_OK; +} Added: haiku/trunk/src/tests/system/kernel/file_corruption/fs/SymLink.h =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/SymLink.h (rev 0) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/SymLink.h 2010-07-12 16:15:47 UTC (rev 37481) @@ -0,0 +1,27 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Distributed under the terms of the MIT License. + */ +#ifndef SYM_LINK_H +#define SYM_LINK_H + + +#include "Node.h" + + +class SymLink : public Node { +public: + SymLink(Volume* volume, uint64 blockIndex, + const checksumfs_node& nodeData); + SymLink(Volume* volume, uint64 blockIndex, + mode_t mode); + virtual ~SymLink(); + + status_t Read(char* buffer, size_t toRead, + size_t& _bytesRead); + status_t Write(const char* buffer, size_t toWrite, + Transaction& transaction); +}; + + +#endif // SYM_LINK_H Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Volume.cpp =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/Volume.cpp 2010-07-12 16:11:56 UTC (rev 37480) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/Volume.cpp 2010-07-12 16:15:47 UTC (rev 37481) @@ -24,6 +24,7 @@ #include "DebugSupport.h" #include "Directory.h" #include "SuperBlock.h" +#include "SymLink.h" Volume::Volume(uint32 flags) @@ -276,6 +277,9 @@ case S_IFDIR: node = new(std::nothrow) Directory(this, blockIndex, *nodeData); break; + case S_IFLNK: + node = new(std::nothrow) SymLink(this, blockIndex, *nodeData); + break; default: node = new(std::nothrow) Node(this, blockIndex, *nodeData); break; @@ -322,6 +326,35 @@ status_t +Volume::CreateSymLink(mode_t mode, Transaction& transaction, SymLink*& _symLink) +{ + // allocate a free block + AllocatedBlock allocatedBlock(fBlockAllocator, transaction); + status_t error = allocatedBlock.Allocate(); + if (error != B_OK) + return error; + + // create the symlink + SymLink* symLink = new(std::nothrow) SymLink(this, allocatedBlock.Index(), + (mode & ~(mode_t)S_IFMT) | S_IFLNK); + if (symLink == NULL) + return B_NO_MEMORY; + + // attach the directory to the transaction + error = transaction.AddNode(symLink, TRANSACTION_DELETE_NODE); + if (error != B_OK) { + delete symLink; + return error; + } + + allocatedBlock.Detach(); + _symLink = symLink; + + return B_OK; +} + + +status_t Volume::DeleteNode(Node* node) { Transaction transaction(this); Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Volume.h =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/Volume.h 2010-07-12 16:11:56 UTC (rev 37480) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/Volume.h 2010-07-12 16:15:47 UTC (rev 37481) @@ -16,6 +16,7 @@ class BlockAllocator; class Directory; class Node; +class SymLink; class Transaction; @@ -44,6 +45,9 @@ status_t CreateDirectory(mode_t mode, Transaction& transaction, Directory*& _directory); + status_t CreateSymLink(mode_t mode, + Transaction& transaction, + SymLink*& _symLink); status_t DeleteNode(Node* node); inline void TransactionStarted(); Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp 2010-07-12 16:11:56 UTC (rev 37480) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp 2010-07-12 16:15:47 UTC (rev 37481) @@ -23,6 +23,7 @@ #include "DebugSupport.h" #include "Directory.h" #include "SuperBlock.h" +#include "SymLink.h" #include "Transaction.h" #include "Volume.h" @@ -428,6 +429,83 @@ static status_t +checksumfs_read_symlink(fs_volume* fsVolume, fs_vnode* vnode, char* buffer, + size_t* _bufferSize) +{ + SymLink* symLink = dynamic_cast<SymLink*>((Node*)vnode->private_node); + if (symLink == NULL) + RETURN_ERROR(B_BAD_VALUE); + + status_t error = check_access(symLink, R_OK); + if (error != B_OK) + return error; + + return symLink->Read(buffer, *_bufferSize, *_bufferSize); +} + + +static status_t +checksumfs_create_symlink(fs_volume* fsVolume, fs_vnode* parent, + const char* name, const char* path, int mode) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Directory* directory + = dynamic_cast<Directory*>((Node*)parent->private_node); + if (directory == NULL) + return B_NOT_A_DIRECTORY; + + if (volume->IsReadOnly()) + return B_READ_ONLY_DEVICE; + + status_t error = check_access(directory, W_OK); + if (error != B_OK) + return error; + + // start a transaction + Transaction transaction(volume); + error = transaction.Start(); + if (error != B_OK) + return error; + + // attach the directory to the transaction (write locks it, too) + error = transaction.AddNode(directory); + if (error != B_OK) + return error; + + // create a symlink node + SymLink* newSymLink; + error = volume->CreateSymLink(mode, transaction, newSymLink); + if (error != B_OK) + return error; + + // write it + error = newSymLink->Write(path, strlen(path), transaction); + if (error != B_OK) + return error; + + // insert the new symlink + error = directory->InsertEntry(name, newSymLink->BlockIndex(), transaction); + if (error != B_OK) + return error; + + // update stat data + newSymLink->SetHardLinks(1); + + directory->Touched(NODE_MODIFIED); + + // commit the transaction + return transaction.Commit(); +} + + +static status_t +checksumfs_unlink(fs_volume* fsVolume, fs_vnode* dir, const char* name) +{ + return remove_entry(fsVolume, dir, name, false); +} + + +static status_t checksumfs_read_stat(fs_volume* fsVolume, fs_vnode* vnode, struct stat* st) { Node* node = (Node*)vnode->private_node; @@ -869,11 +947,11 @@ NULL, // checksumfs_deselect, NULL, // checksumfs_fsync, - NULL, // checksumfs_read_symlink, - NULL, // checksumfs_create_symlink, + checksumfs_read_symlink, + checksumfs_create_symlink, NULL, // checksumfs_link, - NULL, // checksumfs_unlink, + checksumfs_unlink, NULL, // checksumfs_rename, NULL, // checksumfs_access,