Added symlink support.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37481 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2010-07-12 16:15:47 +00:00
parent 579a85af7f
commit 06b318ef9b
6 changed files with 237 additions and 3 deletions

View File

@ -22,6 +22,7 @@ HAIKU_CHECKSUM_FS_SOURCES =
Directory.cpp
Node.cpp
SuperBlock.cpp
SymLink.cpp
Transaction.cpp
Volume.cpp
;

View File

@ -0,0 +1,91 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* 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;
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* 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

View File

@ -24,6 +24,7 @@
#include "DebugSupport.h"
#include "Directory.h"
#include "SuperBlock.h"
#include "SymLink.h"
Volume::Volume(uint32 flags)
@ -276,6 +277,9 @@ Volume::ReadNode(uint64 blockIndex, Node*& _node)
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;
@ -321,6 +325,35 @@ Volume::CreateDirectory(mode_t mode, Transaction& transaction,
}
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)
{

View File

@ -16,6 +16,7 @@
class BlockAllocator;
class Directory;
class Node;
class SymLink;
class Transaction;
@ -44,6 +45,9 @@ public:
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();

View File

@ -23,6 +23,7 @@
#include "DebugSupport.h"
#include "Directory.h"
#include "SuperBlock.h"
#include "SymLink.h"
#include "Transaction.h"
#include "Volume.h"
@ -427,6 +428,83 @@ checksumfs_remove_vnode(fs_volume* fsVolume, fs_vnode* vnode, bool reenter)
// #pragma mark - common operations
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)
{
@ -869,11 +947,11 @@ fs_vnode_ops gCheckSumFSVnodeOps = {
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,