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
|
Directory.cpp
|
||||||
Node.cpp
|
Node.cpp
|
||||||
SuperBlock.cpp
|
SuperBlock.cpp
|
||||||
|
SymLink.cpp
|
||||||
Transaction.cpp
|
Transaction.cpp
|
||||||
Volume.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 "DebugSupport.h"
|
||||||
#include "Directory.h"
|
#include "Directory.h"
|
||||||
#include "SuperBlock.h"
|
#include "SuperBlock.h"
|
||||||
|
#include "SymLink.h"
|
||||||
|
|
||||||
|
|
||||||
Volume::Volume(uint32 flags)
|
Volume::Volume(uint32 flags)
|
||||||
|
@ -276,6 +277,9 @@ Volume::ReadNode(uint64 blockIndex, Node*& _node)
|
||||||
case S_IFDIR:
|
case S_IFDIR:
|
||||||
node = new(std::nothrow) Directory(this, blockIndex, *nodeData);
|
node = new(std::nothrow) Directory(this, blockIndex, *nodeData);
|
||||||
break;
|
break;
|
||||||
|
case S_IFLNK:
|
||||||
|
node = new(std::nothrow) SymLink(this, blockIndex, *nodeData);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
node = new(std::nothrow) Node(this, blockIndex, *nodeData);
|
node = new(std::nothrow) Node(this, blockIndex, *nodeData);
|
||||||
break;
|
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
|
status_t
|
||||||
Volume::DeleteNode(Node* node)
|
Volume::DeleteNode(Node* node)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
class BlockAllocator;
|
class BlockAllocator;
|
||||||
class Directory;
|
class Directory;
|
||||||
class Node;
|
class Node;
|
||||||
|
class SymLink;
|
||||||
class Transaction;
|
class Transaction;
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,6 +45,9 @@ public:
|
||||||
status_t CreateDirectory(mode_t mode,
|
status_t CreateDirectory(mode_t mode,
|
||||||
Transaction& transaction,
|
Transaction& transaction,
|
||||||
Directory*& _directory);
|
Directory*& _directory);
|
||||||
|
status_t CreateSymLink(mode_t mode,
|
||||||
|
Transaction& transaction,
|
||||||
|
SymLink*& _symLink);
|
||||||
status_t DeleteNode(Node* node);
|
status_t DeleteNode(Node* node);
|
||||||
|
|
||||||
inline void TransactionStarted();
|
inline void TransactionStarted();
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "DebugSupport.h"
|
#include "DebugSupport.h"
|
||||||
#include "Directory.h"
|
#include "Directory.h"
|
||||||
#include "SuperBlock.h"
|
#include "SuperBlock.h"
|
||||||
|
#include "SymLink.h"
|
||||||
#include "Transaction.h"
|
#include "Transaction.h"
|
||||||
#include "Volume.h"
|
#include "Volume.h"
|
||||||
|
|
||||||
|
@ -427,6 +428,83 @@ checksumfs_remove_vnode(fs_volume* fsVolume, fs_vnode* vnode, bool reenter)
|
||||||
// #pragma mark - common operations
|
// #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
|
static status_t
|
||||||
checksumfs_read_stat(fs_volume* fsVolume, fs_vnode* vnode, struct stat* st)
|
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_deselect,
|
||||||
NULL, // checksumfs_fsync,
|
NULL, // checksumfs_fsync,
|
||||||
|
|
||||||
NULL, // checksumfs_read_symlink,
|
checksumfs_read_symlink,
|
||||||
NULL, // checksumfs_create_symlink,
|
checksumfs_create_symlink,
|
||||||
|
|
||||||
NULL, // checksumfs_link,
|
NULL, // checksumfs_link,
|
||||||
NULL, // checksumfs_unlink,
|
checksumfs_unlink,
|
||||||
NULL, // checksumfs_rename,
|
NULL, // checksumfs_rename,
|
||||||
|
|
||||||
NULL, // checksumfs_access,
|
NULL, // checksumfs_access,
|
||||||
|
|
Loading…
Reference in New Issue