xfs: Symbolic links support
- Necessary hooks for reading symlinks are implemented - Added support for local symlinks - Added support for extent based symlinks - This patch completes #17791 Change-Id: If6847974562b21f751097df357326f4643eff757 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5621 Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org> Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk>
This commit is contained in:
parent
f31b83f7ef
commit
99071c0c0b
@ -32,6 +32,7 @@ local xfsSources =
|
||||
Node.cpp
|
||||
ShortAttribute.cpp
|
||||
ShortDirectory.cpp
|
||||
Symlink.cpp
|
||||
Volume.cpp
|
||||
xfs.cpp
|
||||
;
|
||||
|
141
src/add-ons/kernel/file_systems/xfs/Symlink.cpp
Normal file
141
src/add-ons/kernel/file_systems/xfs/Symlink.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2022, Raghav Sharma, raghavself28@gmail.com
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Symlink.h"
|
||||
|
||||
#include "VerifyHeader.h"
|
||||
|
||||
|
||||
Symlink::Symlink(Inode* inode)
|
||||
:
|
||||
fInode(inode),
|
||||
fSymlinkBuffer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Symlink::~Symlink()
|
||||
{
|
||||
delete fSymlinkBuffer;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Symlink::_FillMapEntry()
|
||||
{
|
||||
void* pointerToMap = DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize());
|
||||
|
||||
uint64 firstHalf = *((uint64*)pointerToMap);
|
||||
uint64 secondHalf = *((uint64*)pointerToMap + 1);
|
||||
//dividing the 128 bits into 2 parts.
|
||||
firstHalf = B_BENDIAN_TO_HOST_INT64(firstHalf);
|
||||
secondHalf = B_BENDIAN_TO_HOST_INT64(secondHalf);
|
||||
fMap.br_state = firstHalf >> 63;
|
||||
fMap.br_startoff = (firstHalf & MASK(63)) >> 9;
|
||||
fMap.br_startblock = ((firstHalf & MASK(9)) << 43) | (secondHalf >> 21);
|
||||
fMap.br_blockcount = secondHalf & MASK(21);
|
||||
TRACE("Extent::Init: startoff:(%" B_PRIu64 "), startblock:(%" B_PRIu64 "),"
|
||||
"blockcount:(%" B_PRIu64 "),state:(%" B_PRIu8 ")\n", fMap.br_startoff, fMap.br_startblock,
|
||||
fMap.br_blockcount, fMap.br_state);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Symlink::_FillBuffer()
|
||||
{
|
||||
if (fMap.br_state != 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
int len = fInode->DirBlockSize();
|
||||
fSymlinkBuffer = new(std::nothrow) char[len];
|
||||
if (fSymlinkBuffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
xfs_daddr_t readPos =
|
||||
fInode->FileSystemBlockToAddr(fMap.br_startblock);
|
||||
|
||||
if (read_pos(fInode->GetVolume()->Device(), readPos, fSymlinkBuffer, len)
|
||||
!= len) {
|
||||
ERROR("Extent::FillBlockBuffer(): IO Error");
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Symlink::_ReadLocalLink(off_t pos, char* buffer, size_t* _length)
|
||||
{
|
||||
// All symlinks contents are inside inode itself
|
||||
|
||||
size_t lengthToRead = fInode->Size();
|
||||
|
||||
if (*_length < lengthToRead)
|
||||
lengthToRead = *_length;
|
||||
|
||||
char* offset = (char*)(DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize()));
|
||||
|
||||
memcpy(buffer, offset, lengthToRead);
|
||||
|
||||
*_length = lengthToRead;
|
||||
|
||||
return B_OK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Symlink::_ReadExtentLink(off_t pos, char* buffer, size_t* _length)
|
||||
{
|
||||
status_t status;
|
||||
// First fill up extent, then Symlink block buffer
|
||||
status = _FillMapEntry();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
status = _FillBuffer();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
uint32 offset = 0;
|
||||
// If it is Version 5 xfs then we have Symlink header
|
||||
if (fInode->Version() == 3) {
|
||||
SymlinkHeader* header = (SymlinkHeader*)fSymlinkBuffer;
|
||||
if (!VerifyHeader<SymlinkHeader>(header, fSymlinkBuffer, fInode, 0, &fMap, 0)) {
|
||||
ERROR("Invalid data header");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
offset += sizeof(SymlinkHeader);
|
||||
}
|
||||
|
||||
size_t lengthToRead = fInode->Size();
|
||||
|
||||
if (*_length < lengthToRead)
|
||||
lengthToRead = *_length;
|
||||
|
||||
memcpy(buffer, fSymlinkBuffer + offset, lengthToRead);
|
||||
|
||||
*_length = lengthToRead;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Symlink::ReadLink(off_t pos, char* buffer, size_t* _length)
|
||||
{
|
||||
switch (fInode->Format()) {
|
||||
case XFS_DINODE_FMT_LOCAL:
|
||||
return _ReadLocalLink(pos, buffer, _length);
|
||||
case XFS_DINODE_FMT_EXTENTS:
|
||||
return _ReadExtentLink(pos, buffer, _length);
|
||||
default:
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
}
|
68
src/add-ons/kernel/file_systems/xfs/Symlink.h
Normal file
68
src/add-ons/kernel/file_systems/xfs/Symlink.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2022, Raghav Sharma, raghavself28@gmail.com
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef XFS_SYMLINK_H
|
||||
#define XFS_SYMLINK_H
|
||||
|
||||
|
||||
#include "Inode.h"
|
||||
|
||||
|
||||
#define SYMLINK_MAGIC 0x58534c4d
|
||||
|
||||
|
||||
// Used only on Version 5
|
||||
struct SymlinkHeader {
|
||||
public:
|
||||
|
||||
uint32 Magic()
|
||||
{ return B_BENDIAN_TO_HOST_INT32(sl_magic); }
|
||||
|
||||
uint64 Blockno()
|
||||
{ return B_BENDIAN_TO_HOST_INT64(sl_blkno); }
|
||||
|
||||
uuid_t* Uuid()
|
||||
{ return &sl_uuid; }
|
||||
|
||||
uint64 Owner()
|
||||
{ return B_BENDIAN_TO_HOST_INT64(sl_owner); }
|
||||
|
||||
static uint32 ExpectedMagic(int8 whichDirectory, Inode* inode)
|
||||
{ return SYMLINK_MAGIC; }
|
||||
|
||||
static uint32 CRCOffset()
|
||||
{ return offsetof(SymlinkHeader, sl_crc); }
|
||||
|
||||
private:
|
||||
uint32 sl_magic;
|
||||
uint32 sl_offset;
|
||||
uint32 sl_bytes;
|
||||
public:
|
||||
uint32 sl_crc;
|
||||
private:
|
||||
uuid_t sl_uuid;
|
||||
uint64 sl_owner;
|
||||
uint64 sl_blkno;
|
||||
uint64 sl_lsn;
|
||||
};
|
||||
|
||||
|
||||
// This class will handle all formats of Symlinks in xfs
|
||||
class Symlink {
|
||||
public:
|
||||
Symlink(Inode* inode);
|
||||
~Symlink();
|
||||
status_t ReadLink(off_t pos, char* buffer, size_t* _length);
|
||||
private:
|
||||
status_t _FillMapEntry();
|
||||
status_t _FillBuffer();
|
||||
status_t _ReadLocalLink(off_t pos, char* buffer, size_t* _length);
|
||||
status_t _ReadExtentLink(off_t pos, char* buffer, size_t* _length);
|
||||
|
||||
Inode* fInode;
|
||||
ExtentMapEntry fMap;
|
||||
char* fSymlinkBuffer;
|
||||
};
|
||||
|
||||
#endif
|
@ -9,6 +9,7 @@
|
||||
#include "Directory.h"
|
||||
#include "Inode.h"
|
||||
#include "ShortAttribute.h"
|
||||
#include "Symlink.h"
|
||||
#include "Utility.h"
|
||||
#include "Volume.h"
|
||||
|
||||
@ -353,7 +354,18 @@ static status_t
|
||||
xfs_read_link(fs_volume *_volume, fs_vnode *_node, char *buffer,
|
||||
size_t *_bufferSize)
|
||||
{
|
||||
return B_NOT_SUPPORTED;
|
||||
TRACE("XFS_READ_SYMLINK\n");
|
||||
|
||||
Inode* inode = (Inode*)_node->private_node;
|
||||
|
||||
if (!inode->IsSymLink())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
Symlink symlink(inode);
|
||||
|
||||
status_t result = symlink.ReadLink(0, buffer, _bufferSize);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -51,6 +51,7 @@ local xfsSource =
|
||||
Node.cpp
|
||||
ShortAttribute.cpp
|
||||
ShortDirectory.cpp
|
||||
Symlink.cpp
|
||||
Volume.cpp
|
||||
xfs.cpp
|
||||
;
|
||||
|
Loading…
Reference in New Issue
Block a user