Added symlink support.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37481 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
579a85af7f
commit
06b318ef9b
|
@ -22,6 +22,7 @@ HAIKU_CHECKSUM_FS_SOURCES =
|
|||
Directory.cpp
|
||||
Node.cpp
|
||||
SuperBlock.cpp
|
||||
SymLink.cpp
|
||||
Transaction.cpp
|
||||
Volume.cpp
|
||||
;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue