Implemented the attribute directory methods. Untested yet -- sshfs doesn't
support the respective xattr hooks. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29656 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
fd4f53a7a0
commit
f11f17301f
@ -432,16 +432,14 @@ FUSEFileSystem::_InitCapabilities()
|
||||
fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, readDirSupport);
|
||||
|
||||
// attribute directory operations
|
||||
// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR,
|
||||
// fFS->ops.open_attrdir);
|
||||
// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR,
|
||||
// fFS->ops.close_attrdir);
|
||||
// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE,
|
||||
// fFS->ops.free_attrdircookie);
|
||||
// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR,
|
||||
// fFS->ops.read_attrdir);
|
||||
// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR,
|
||||
// fFS->ops.rewind_attrdir);
|
||||
bool hasAttributes = fFS->ops.listxattr != NULL;
|
||||
fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, hasAttributes);
|
||||
// fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR, true);
|
||||
// not needed
|
||||
fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE,
|
||||
hasAttributes);
|
||||
fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, hasAttributes);
|
||||
fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, hasAttributes);
|
||||
|
||||
// attribute operations
|
||||
// // we emulate open_attr() and free_attr_dir_cookie() if either read_attr()
|
||||
|
@ -178,6 +178,97 @@ struct FUSEVolume::FileCookie : fuse_file_info {
|
||||
};
|
||||
|
||||
|
||||
struct FUSEVolume::AttrDirCookie {
|
||||
AttrDirCookie()
|
||||
:
|
||||
fAttributes(NULL),
|
||||
fAttributesSize(0),
|
||||
fCurrentOffset(0),
|
||||
fValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
~AttrDirCookie()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
free(fAttributes);
|
||||
fAttributes = NULL;
|
||||
fAttributesSize = 0;
|
||||
fCurrentOffset = 0;
|
||||
fValid = false;
|
||||
}
|
||||
|
||||
status_t Allocate(size_t size)
|
||||
{
|
||||
Clear();
|
||||
|
||||
if (size == 0)
|
||||
return B_OK;
|
||||
|
||||
fAttributes = (char*)malloc(size);
|
||||
if (fAttributes == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fAttributesSize = size;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return fValid;
|
||||
}
|
||||
|
||||
void SetValid(bool valid)
|
||||
{
|
||||
fValid = valid;
|
||||
}
|
||||
|
||||
char* AttributesBuffer() const
|
||||
{
|
||||
return fAttributes;
|
||||
}
|
||||
|
||||
bool ReadNextEntry(dev_t volumeID, ino_t nodeID, bool align,
|
||||
dirent* buffer, size_t bufferSize)
|
||||
{
|
||||
if (fCurrentOffset >= fAttributesSize)
|
||||
return false;
|
||||
|
||||
const char* name = fAttributes + fCurrentOffset;
|
||||
size_t nameLen = strlen(name);
|
||||
|
||||
// get and check the size
|
||||
size_t size = sizeof(dirent) + nameLen;
|
||||
if (size > bufferSize)
|
||||
return false;
|
||||
|
||||
// align the size, if requested
|
||||
if (align)
|
||||
size = std::min(bufferSize, (size + 7) / 8 * 8);
|
||||
|
||||
// fill in the dirent
|
||||
buffer->d_dev = volumeID;
|
||||
buffer->d_ino = nodeID;
|
||||
memcpy(buffer->d_name, name, nameLen + 1);
|
||||
buffer->d_reclen = size;
|
||||
|
||||
fCurrentOffset += nameLen + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
char* fAttributes;
|
||||
size_t fAttributesSize;
|
||||
size_t fCurrentOffset;
|
||||
bool fValid;
|
||||
};
|
||||
|
||||
|
||||
struct FUSEVolume::ReadDirBuffer {
|
||||
FUSEVolume* volume;
|
||||
FUSENode* directory;
|
||||
@ -690,7 +781,7 @@ PRINT(("FUSEVolume::Open(%p (%lld), %#x)\n", node, node->id, openMode));
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
// open the dir
|
||||
// open the file
|
||||
int fuseError = fuse_fs_open(fFS, path, cookie);
|
||||
if (fuseError != 0)
|
||||
return fuseError;
|
||||
@ -987,6 +1078,118 @@ PRINT(("FUSEVolume::RewindDir(%p, %p)\n", _node, _cookie));
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - attribute directories
|
||||
|
||||
|
||||
// OpenAttrDir
|
||||
status_t
|
||||
FUSEVolume::OpenAttrDir(void* _node, void** _cookie)
|
||||
{
|
||||
// allocate an attribute directory cookie
|
||||
AttrDirCookie* cookie = new(std::nothrow) AttrDirCookie;
|
||||
if (cookie == NULL)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
|
||||
*_cookie = cookie;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// CloseAttrDir
|
||||
status_t
|
||||
FUSEVolume::CloseAttrDir(void* node, void* cookie)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// FreeAttrDirCookie
|
||||
status_t
|
||||
FUSEVolume::FreeAttrDirCookie(void* _node, void* _cookie)
|
||||
{
|
||||
delete (AttrDirCookie*)_cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// ReadAttrDir
|
||||
status_t
|
||||
FUSEVolume::ReadAttrDir(void* _node, void* _cookie, void* buffer,
|
||||
size_t bufferSize, uint32 count, uint32* _countRead)
|
||||
{
|
||||
FUSENode* node = (FUSENode*)_node;
|
||||
AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
|
||||
|
||||
*_countRead = 0;
|
||||
|
||||
AutoLocker<Locker> locker(fLock);
|
||||
|
||||
// get a path for the node
|
||||
char path[B_PATH_NAME_LENGTH];
|
||||
size_t pathLen;
|
||||
status_t error = _BuildPath(node, path, pathLen);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
if (!cookie->IsValid()) {
|
||||
// cookie not yet valid -- get the length of the list
|
||||
int listSize = fuse_fs_listxattr(fFS, path, NULL, 0);
|
||||
if (listSize < 0)
|
||||
RETURN_ERROR(listSize);
|
||||
|
||||
while (true) {
|
||||
// allocate space for the listing
|
||||
error = cookie->Allocate(listSize);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// read the listing
|
||||
int bytesRead = fuse_fs_listxattr(fFS, path,
|
||||
cookie->AttributesBuffer(), listSize);
|
||||
if (bytesRead < 0)
|
||||
RETURN_ERROR(bytesRead);
|
||||
|
||||
if (bytesRead == listSize)
|
||||
break;
|
||||
|
||||
// attributes listing changed -- reread it
|
||||
listSize = bytesRead;
|
||||
}
|
||||
|
||||
cookie->SetValid(true);
|
||||
}
|
||||
|
||||
// we have a valid cookie now -- get the next entries from the cookie
|
||||
uint32 countRead = 0;
|
||||
dirent* entryBuffer = (dirent*)buffer;
|
||||
while (countRead < count
|
||||
&& cookie->ReadNextEntry(fID, node->id, countRead + 1 < count,
|
||||
entryBuffer, bufferSize)) {
|
||||
countRead++;
|
||||
bufferSize -= entryBuffer->d_reclen;
|
||||
entryBuffer = (dirent*)((uint8*)entryBuffer + entryBuffer->d_reclen);
|
||||
}
|
||||
|
||||
*_countRead = countRead;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// RewindAttrDir
|
||||
status_t
|
||||
FUSEVolume::RewindAttrDir(void* _node, void* _cookie)
|
||||
{
|
||||
AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
|
||||
|
||||
cookie->Clear();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
|
@ -118,10 +118,21 @@ public:
|
||||
uint32 count, uint32* countRead);
|
||||
virtual status_t RewindDir(void* node, void* cookie);
|
||||
|
||||
// attribute directories
|
||||
virtual status_t OpenAttrDir(void* node, void** cookie);
|
||||
virtual status_t CloseAttrDir(void* node, void* cookie);
|
||||
virtual status_t FreeAttrDirCookie(void* node,
|
||||
void* cookie);
|
||||
virtual status_t ReadAttrDir(void* node, void* cookie,
|
||||
void* buffer, size_t bufferSize,
|
||||
uint32 count, uint32* countRead);
|
||||
virtual status_t RewindAttrDir(void* node, void* cookie);
|
||||
|
||||
private:
|
||||
struct DirEntryCache;
|
||||
struct DirCookie;
|
||||
struct FileCookie;
|
||||
struct AttrDirCookie;
|
||||
struct ReadDirBuffer;
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user