* Added create/write/remove/rename support for attributes to the overlay fs.

* Implemented writing attributes back to attribute files. Not tested or enabled.
* Fix reading attribute dirs, they need a separate cookie that links attribute
  files to the dir index as multiple read-dirs could happen at the same time.
* Fix some obvious bugs in size calculations.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29239 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2009-02-17 02:05:58 +00:00
parent 5076aaf050
commit 3b5507a987
1 changed files with 578 additions and 66 deletions

View File

@ -40,6 +40,12 @@ class AttributeFile;
class AttributeEntry; class AttributeEntry;
struct attribute_dir_cookie {
AttributeFile * file;
uint32 index;
};
class OverlayInode { class OverlayInode {
public: public:
OverlayInode(fs_volume *superVolume, OverlayInode(fs_volume *superVolume,
@ -51,12 +57,14 @@ public:
fs_volume * SuperVolume() { return fSuperVolume; } fs_volume * SuperVolume() { return fSuperVolume; }
fs_vnode * SuperVnode() { return &fSuperVnode; } fs_vnode * SuperVnode() { return &fSuperVnode; }
AttributeFile * GetAttributeFile(); status_t GetAttributeFile(AttributeFile **attributeFile);
status_t WriteAttributeFile();
private: private:
fs_volume * fSuperVolume; fs_volume * fSuperVolume;
fs_vnode fSuperVnode; fs_vnode fSuperVnode;
AttributeFile * fAttributeFile; AttributeFile * fAttributeFile;
bool fAttributeFileMissing;
}; };
@ -68,18 +76,27 @@ public:
status_t InitCheck() { return fStatus; } status_t InitCheck() { return fStatus; }
dev_t VolumeID() { return fVolumeID; } dev_t VolumeID() { return fVolumeID; }
ino_t ParentInode() { return fParentInode; } ino_t FileInode() { return fFileInode; }
uint32 CountAttributes(); status_t CreateEmpty();
AttributeEntry * FindAttribute(const char *name); status_t WriteAttributeFile(fs_volume *volume,
fs_vnode *vnode);
status_t ReadAttributeDir(struct dirent *dirent, status_t ReadAttributeDir(struct dirent *dirent,
size_t bufferSize, uint32 *numEntries); size_t bufferSize, uint32 *numEntries,
status_t RewindAttributeDir() uint32 *index);
{
fAttributeDirIndex = 0; uint32 CountAttributes();
return B_OK; AttributeEntry * FindAttribute(const char *name,
} uint32 *index = NULL);
status_t CreateAttribute(const char *name, type_code type,
int openMode, AttributeEntry **entry);
status_t OpenAttribute(const char *name, int openMode,
AttributeEntry **entry);
status_t RemoveAttribute(const char *name,
AttributeEntry **entry);
status_t AddAttribute(AttributeEntry *entry);
private: private:
#define ATTRIBUTE_OVERLAY_FILE_MAGIC 'attr' #define ATTRIBUTE_OVERLAY_FILE_MAGIC 'attr'
@ -93,7 +110,10 @@ private:
status_t fStatus; status_t fStatus;
dev_t fVolumeID; dev_t fVolumeID;
ino_t fParentInode; ino_t fFileInode;
ino_t fDirectoryInode;
ino_t fAttributeDirInode;
ino_t fAttributeFileInode;
attribute_file * fFile; attribute_file * fFile;
uint32 fAttributeDirIndex; uint32 fAttributeDirIndex;
AttributeEntry ** fEntries; AttributeEntry ** fEntries;
@ -104,18 +124,36 @@ class AttributeEntry {
public: public:
AttributeEntry(AttributeFile *parent, AttributeEntry(AttributeFile *parent,
uint8 *buffer); uint8 *buffer);
AttributeEntry(AttributeFile *parent,
const char *name, type_code type);
~AttributeEntry(); ~AttributeEntry();
size_t EntrySize(); status_t InitCheck() { return fStatus; }
uint8 NameLength() { return fEntry->name_length; } uint8 * Entry() { return (uint8 *)fEntry; }
size_t EntrySize();
uint8 * Data() { return fData; }
size_t DataSize() { return fEntry->size; }
status_t SetType(type_code type);
type_code Type() { return fEntry->type; }
status_t SetSize(size_t size);
uint32 Size() { return fEntry->size; }
status_t SetName(const char *name);
const char * Name() { return fEntry->name; } const char * Name() { return fEntry->name; }
uint8 NameLength() { return fEntry->name_length; }
status_t FillDirent(struct dirent *dirent, status_t FillDirent(struct dirent *dirent,
size_t bufferSize, uint32 *numEntries); size_t bufferSize, uint32 *numEntries);
status_t Read(off_t position, void *buffer, size_t *length); status_t Read(off_t position, void *buffer, size_t *length);
status_t Write(off_t position, const void *buffer,
size_t *length);
status_t ReadStat(struct stat *stat); status_t ReadStat(struct stat *stat);
status_t WriteStat(const struct stat *stat, uint32 statMask);
private: private:
struct attribute_entry { struct attribute_entry {
@ -128,6 +166,9 @@ private:
AttributeFile * fParent; AttributeFile * fParent;
attribute_entry * fEntry; attribute_entry * fEntry;
uint8 * fData; uint8 * fData;
status_t fStatus;
bool fAllocatedEntry;
bool fAllocatedData;
}; };
@ -137,7 +178,8 @@ private:
OverlayInode::OverlayInode(fs_volume *superVolume, fs_vnode *superVnode) OverlayInode::OverlayInode(fs_volume *superVolume, fs_vnode *superVnode)
: fSuperVolume(superVolume), : fSuperVolume(superVolume),
fSuperVnode(*superVnode), fSuperVnode(*superVnode),
fAttributeFile(NULL) fAttributeFile(NULL),
fAttributeFileMissing(false)
{ {
TRACE("inode created\n"); TRACE("inode created\n");
} }
@ -157,22 +199,46 @@ OverlayInode::InitCheck()
} }
AttributeFile * status_t
OverlayInode::GetAttributeFile() OverlayInode::GetAttributeFile(AttributeFile **attributeFile)
{ {
if (fAttributeFile == NULL) { if (fAttributeFile == NULL) {
fAttributeFile = new(std::nothrow) AttributeFile(fSuperVolume, fAttributeFile = new(std::nothrow) AttributeFile(fSuperVolume,
&fSuperVnode); &fSuperVnode);
if (fAttributeFile == NULL) { if (fAttributeFile == NULL) {
TRACE_ALWAYS("no memory to allocate attribute file\n"); TRACE_ALWAYS("no memory to allocate attribute file\n");
return NULL; return B_NO_MEMORY;
} }
} }
if (fAttributeFile->InitCheck() != B_OK) status_t result = fAttributeFile->InitCheck();
return NULL; if (result != B_OK) {
if (result == B_ENTRY_NOT_FOUND) {
// TODO: need to check if we're able to create the file
// but at least allow virtual attributes for now
}
return fAttributeFile; result = fAttributeFile->CreateEmpty();
if (result != B_OK)
return result;
}
*attributeFile = fAttributeFile;
return B_OK;
}
status_t
OverlayInode::WriteAttributeFile()
{
if (fAttributeFile == NULL)
return B_NO_INIT;
status_t result = fAttributeFile->InitCheck();
if (result != B_OK)
return result;
return fAttributeFile->WriteAttributeFile(fSuperVolume, &fSuperVnode);
} }
@ -182,7 +248,10 @@ OverlayInode::GetAttributeFile()
AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode) AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode)
: fStatus(B_NO_INIT), : fStatus(B_NO_INIT),
fVolumeID(volume->id), fVolumeID(volume->id),
fParentInode(0), fFileInode(0),
fDirectoryInode(0),
fAttributeDirInode(0),
fAttributeFileInode(0),
fFile(NULL), fFile(NULL),
fAttributeDirIndex(0), fAttributeDirIndex(0),
fEntries(NULL) fEntries(NULL)
@ -211,7 +280,7 @@ AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode)
struct stat stat; struct stat stat;
if (vnode->ops->read_stat != NULL if (vnode->ops->read_stat != NULL
&& vnode->ops->read_stat(volume, vnode, &stat) == B_OK) { && vnode->ops->read_stat(volume, vnode, &stat) == B_OK) {
fParentInode = stat.st_ino; fFileInode = stat.st_ino;
} }
// TODO: the ".." lookup is not actually valid for non-directory vnodes. // TODO: the ".." lookup is not actually valid for non-directory vnodes.
@ -249,6 +318,13 @@ AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode)
return; return;
} }
if (i == 0)
fDirectoryInode = inodeNumber;
else if (i == 1)
fAttributeDirInode = inodeNumber;
else if (i == 2)
fAttributeFileInode = inodeNumber;
fStatus = get_vnode(volume, inodeNumber, &currentVnode.private_node, fStatus = get_vnode(volume, inodeNumber, &currentVnode.private_node,
&currentVnode.ops); &currentVnode.ops);
if (fStatus != B_OK) { if (fStatus != B_OK) {
@ -314,7 +390,8 @@ AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode)
return; return;
} }
fEntries = new(std::nothrow) AttributeEntry *[fFile->entry_count]; fEntries = (AttributeEntry **)malloc(fFile->entry_count
* sizeof(AttributeEntry *));
if (fEntries == NULL) { if (fEntries == NULL) {
TRACE_ALWAYS("no memory to allocate entry pointers\n"); TRACE_ALWAYS("no memory to allocate entry pointers\n");
fStatus = B_NO_MEMORY; fStatus = B_NO_MEMORY;
@ -335,7 +412,7 @@ AttributeFile::AttributeFile(fs_volume *volume, fs_vnode *vnode)
return; return;
} }
totalSize += fEntries[i]->EntrySize(); totalSize += fEntries[i]->EntrySize() + fEntries[i]->DataSize();
if (totalSize > readLength) { if (totalSize > readLength) {
TRACE_ALWAYS("attribute entries are too large for buffer\n"); TRACE_ALWAYS("attribute entries are too large for buffer\n");
fStatus = B_BAD_VALUE; fStatus = B_BAD_VALUE;
@ -354,13 +431,170 @@ AttributeFile::~AttributeFile()
for (uint32 i = 0; i < fFile->entry_count; i++) for (uint32 i = 0; i < fFile->entry_count; i++)
delete fEntries[i]; delete fEntries[i];
delete [] fEntries; free(fEntries);
} }
free(fFile); free(fFile);
} }
status_t
AttributeFile::CreateEmpty()
{
if (fFile == NULL) {
fFile = (attribute_file *)malloc(sizeof(attribute_file) - 1);
if (fFile == NULL) {
TRACE_ALWAYS("failed to allocate file buffer\n");
fStatus = B_NO_MEMORY;
return fStatus;
}
fFile->entry_count = 0;
fFile->magic = ATTRIBUTE_OVERLAY_FILE_MAGIC;
}
fStatus = B_OK;
return B_OK;
}
status_t
AttributeFile::WriteAttributeFile(fs_volume *volume, fs_vnode *vnode)
{
if (fFile == NULL)
return B_NO_INIT;
if (fDirectoryInode == 0) {
TRACE_ALWAYS("directory inode not known\n");
return B_NO_INIT;
}
char nameBuffer[B_FILE_NAME_LENGTH];
nameBuffer[sizeof(nameBuffer) - 1] = 0;
status_t result = vnode->ops->get_vnode_name(volume, vnode, nameBuffer,
sizeof(nameBuffer) - 1);
if (result != B_OK) {
TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result));
return result;
}
fs_vnode currentVnode;
if (fAttributeDirInode == 0) {
result = get_vnode(volume, fDirectoryInode,
&currentVnode.private_node, &currentVnode.ops);
if (result != B_OK) {
TRACE_ALWAYS("failed to get directory vnode: %s\n",
strerror(result));
return result;
}
// create the attribute directory
result = currentVnode.ops->create_dir(volume, &currentVnode,
ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, S_IRWXU | S_IRWXG | S_IRWXO,
&fAttributeDirInode);
put_vnode(volume, fDirectoryInode);
if (result != B_OK) {
TRACE_ALWAYS("failed to create attribute directory: %s\n",
strerror(result));
fAttributeDirInode = 0;
return result;
}
}
void *attrFileCookie = NULL;
if (fAttributeFileInode == 0) {
result = get_vnode(volume, fAttributeDirInode,
&currentVnode.private_node, &currentVnode.ops);
if (result != B_OK) {
TRACE_ALWAYS("failed to get attribute directory vnode: %s\n",
strerror(result));
return result;
}
// create the attribute file
result = currentVnode.ops->create(volume, &currentVnode,
nameBuffer, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP
| S_IWGRP | S_IROTH | S_IWOTH, &attrFileCookie,
&fAttributeFileInode);
put_vnode(volume, fAttributeDirInode);
if (result != B_OK) {
TRACE_ALWAYS("failed to create attribute file: %s\n",
strerror(result));
return result;
}
result = get_vnode(volume, fAttributeFileInode,
&currentVnode.private_node, &currentVnode.ops);
if (result != B_OK) {
TRACE_ALWAYS("getting attribute file vnode after create failed: %s\n",
strerror(result));
return result;
}
} else {
result = get_vnode(volume, fAttributeFileInode,
&currentVnode.private_node, &currentVnode.ops);
if (result != B_OK) {
TRACE_ALWAYS("getting attribute file vnode failed: %s\n",
strerror(result));
return result;
}
// open the attribute file
result = currentVnode.ops->open(volume, &currentVnode, O_RDWR | O_TRUNC,
&attrFileCookie);
if (result != B_OK) {
TRACE_ALWAYS("failed to open attribute file for writing: %s\n",
strerror(result));
put_vnode(volume, fAttributeFileInode);
return result;
}
}
off_t position = 0;
size_t writeLength = sizeof(attribute_file) - 1;
result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
position, fFile, &writeLength);
if (result != B_OK) {
TRACE_ALWAYS("failed to write to attribute file: %s\n",
strerror(result));
goto close_and_put;
}
for (uint32 i = 0; i < fFile->entry_count; i++) {
writeLength = fEntries[i]->EntrySize();
result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
position, fEntries[i]->Entry(), &writeLength);
if (result != B_OK) {
TRACE_ALWAYS("failed to write to attribute file: %s\n",
strerror(result));
goto close_and_put;
}
writeLength = fEntries[i]->DataSize();
result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
position, fEntries[i]->Data(), &writeLength);
if (result != B_OK) {
TRACE_ALWAYS("failed to write to attribute file: %s\n",
strerror(result));
goto close_and_put;
}
}
close_and_put:
if (currentVnode.ops->close != NULL)
currentVnode.ops->close(volume, &currentVnode, attrFileCookie);
if (currentVnode.ops->free_cookie != NULL)
currentVnode.ops->free_cookie(volume, &currentVnode, attrFileCookie);
put_vnode(volume, fAttributeFileInode);
return B_OK;
}
uint32 uint32
AttributeFile::CountAttributes() AttributeFile::CountAttributes()
{ {
@ -372,14 +606,15 @@ AttributeFile::CountAttributes()
AttributeEntry * AttributeEntry *
AttributeFile::FindAttribute(const char *name) AttributeFile::FindAttribute(const char *name, uint32 *index)
{ {
if (fFile == NULL)
return NULL;
for (uint32 i = 0; i < fFile->entry_count; i++) { for (uint32 i = 0; i < fFile->entry_count; i++) {
if (strncmp(fEntries[i]->Name(), name, fEntries[i]->NameLength()) == 0) if (strncmp(fEntries[i]->Name(), name, fEntries[i]->NameLength()) == 0) {
if (index)
*index = i;
return fEntries[i]; return fEntries[i];
}
} }
return NULL; return NULL;
@ -387,16 +622,115 @@ AttributeFile::FindAttribute(const char *name)
status_t status_t
AttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize, AttributeFile::CreateAttribute(const char *name, type_code type, int openMode,
uint32 *numEntries) AttributeEntry **_entry)
{ {
if (fFile == NULL || fAttributeDirIndex >= fFile->entry_count) { AttributeEntry *existing = FindAttribute(name);
if (existing != NULL) {
if (openMode & O_TRUNC)
existing->SetSize(0);
// attribute already exists, only allow if the attribute type is
// compatible or the attribute size is 0
if (existing->Type() != type) {
if (existing->Size() != 0)
return B_FILE_EXISTS;
existing->SetType(type);
}
if (existing->InitCheck() == B_OK) {
*_entry = existing;
return B_OK;
}
// we tried to change the existing item but failed, try to just
// remove it instead and creating a new one
RemoveAttribute(name, NULL);
}
AttributeEntry *entry = new(std::nothrow) AttributeEntry(this, name, type);
if (entry == NULL)
return B_NO_MEMORY;
status_t result = AddAttribute(entry);
if (result != B_OK) {
delete entry;
return result;
}
*_entry = entry;
return B_OK;
}
status_t
AttributeFile::OpenAttribute(const char *name, int openMode,
AttributeEntry **_entry)
{
AttributeEntry *entry = FindAttribute(name);
if (entry == NULL)
return B_ENTRY_NOT_FOUND;
if (openMode & O_TRUNC)
entry->SetSize(0);
*_entry = entry;
return B_OK;
}
status_t
AttributeFile::RemoveAttribute(const char *name, AttributeEntry **_entry)
{
uint32 index = 0;
AttributeEntry *entry = FindAttribute(name, &index);
if (entry == NULL)
return B_ENTRY_NOT_FOUND;
for (uint32 i = index + 1; i < fFile->entry_count; i++)
fEntries[i - 1] = fEntries[i];
fFile->entry_count--;
if (_entry)
*_entry = entry;
else
delete entry;
return B_OK;
}
status_t
AttributeFile::AddAttribute(AttributeEntry *entry)
{
status_t result = entry->InitCheck();
if (result != B_OK)
return result;
if (FindAttribute(entry->Name()) != NULL)
return B_FILE_EXISTS;
AttributeEntry **newEntries = (AttributeEntry **)realloc(fEntries,
(fFile->entry_count + 1) * sizeof(AttributeEntry *));
if (newEntries == NULL)
return B_NO_MEMORY;
fEntries = newEntries;
fEntries[fFile->entry_count++] = entry;
return B_OK;
}
status_t
AttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize,
uint32 *numEntries, uint32 *index)
{
if (fFile == NULL || *index >= fFile->entry_count) {
*numEntries = 0; *numEntries = 0;
return B_OK; return B_OK;
} }
return fEntries[fAttributeDirIndex++]->FillDirent(dirent, bufferSize, return fEntries[(*index)++]->FillDirent(dirent, bufferSize, numEntries);
numEntries);
} }
@ -406,22 +740,124 @@ AttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize,
AttributeEntry::AttributeEntry(AttributeFile *parent, uint8 *buffer) AttributeEntry::AttributeEntry(AttributeFile *parent, uint8 *buffer)
: fParent(parent), : fParent(parent),
fEntry(NULL), fEntry(NULL),
fData(NULL) fData(NULL),
fStatus(B_NO_INIT),
fAllocatedEntry(false),
fAllocatedData(false)
{ {
if (buffer == NULL)
return;
fEntry = (attribute_entry *)buffer; fEntry = (attribute_entry *)buffer;
fData = (uint8 *)fEntry->name + fEntry->name_length; fData = (uint8 *)fEntry->name + fEntry->name_length;
fStatus = B_OK;
}
AttributeEntry::AttributeEntry(AttributeFile *parent, const char *name,
type_code type)
: fParent(parent),
fEntry(NULL),
fData(NULL),
fStatus(B_NO_INIT),
fAllocatedEntry(false),
fAllocatedData(false)
{
fStatus = SetName(name);
if (fStatus != B_OK)
return;
fEntry->type = type;
fEntry->size = 0;
} }
AttributeEntry::~AttributeEntry() AttributeEntry::~AttributeEntry()
{ {
if (fAllocatedEntry)
free(fEntry);
if (fAllocatedData)
free(fData);
} }
size_t size_t
AttributeEntry::EntrySize() AttributeEntry::EntrySize()
{ {
return sizeof(attribute_entry) - 1 + fEntry->name_length + fEntry->size; return sizeof(attribute_entry) - 1 + fEntry->name_length;
}
status_t
AttributeEntry::SetType(type_code type)
{
fEntry->type = type;
return B_OK;
}
status_t
AttributeEntry::SetSize(size_t size)
{
if (size <= fEntry->size) {
fEntry->size = size;
return B_OK;
}
if (fAllocatedData) {
uint8 *newData = (uint8 *)realloc(fData, size);
if (newData == NULL) {
fStatus = B_NO_MEMORY;
return fStatus;
}
fData = newData;
fEntry->size = size;
return B_OK;
}
uint8 *newData = (uint8 *)malloc(size);
if (newData == NULL) {
fStatus = B_NO_MEMORY;
return fStatus;
}
memcpy(newData, fData, min_c(fEntry->size, size));
fAllocatedData = true;
fData = newData;
return B_OK;
}
status_t
AttributeEntry::SetName(const char *name)
{
size_t nameLength = strlen(name) + 1;
if (nameLength > 255) {
fStatus = B_NAME_TOO_LONG;
return fStatus;
}
if (!fAllocatedEntry || fEntry->name_length < nameLength) {
attribute_entry *newEntry = (attribute_entry *)malloc(
sizeof(attribute_entry) - 1 + nameLength);
if (newEntry == NULL) {
fStatus = B_NO_MEMORY;
return fStatus;
}
if (fEntry != NULL)
memcpy(newEntry, fEntry, sizeof(attribute_entry) - 1);
if (fAllocatedEntry)
free(fEntry);
fAllocatedEntry = true;
fEntry = newEntry;
}
fEntry->name_length = nameLength;
strlcpy(fEntry->name, name, nameLength);
return B_OK;
} }
@ -431,7 +867,7 @@ AttributeEntry::FillDirent(struct dirent *dirent, size_t bufferSize,
{ {
dirent->d_dev = dirent->d_pdev = fParent->VolumeID(); dirent->d_dev = dirent->d_pdev = fParent->VolumeID();
dirent->d_ino = (ino_t)this; dirent->d_ino = (ino_t)this;
dirent->d_pino = fParent->ParentInode(); dirent->d_pino = fParent->FileInode();
dirent->d_reclen = sizeof(struct dirent) + fEntry->name_length; dirent->d_reclen = sizeof(struct dirent) + fEntry->name_length;
if (bufferSize < dirent->d_reclen) { if (bufferSize < dirent->d_reclen) {
*numEntries = 0; *numEntries = 0;
@ -448,14 +884,25 @@ AttributeEntry::FillDirent(struct dirent *dirent, size_t bufferSize,
status_t status_t
AttributeEntry::Read(off_t position, void *buffer, size_t *length) AttributeEntry::Read(off_t position, void *buffer, size_t *length)
{ {
*length = min_c(*length, fEntry->size); *length = min_c(*length, fEntry->size - position);
if (*length <= position) { memcpy(buffer, fData + position, *length);
*length = 0; return B_OK;
return B_OK; }
status_t
AttributeEntry::Write(off_t position, const void *buffer, size_t *length)
{
size_t neededSize = position + *length;
if (neededSize > fEntry->size) {
status_t result = SetSize(neededSize);
if (result != B_OK) {
*length = 0;
return result;
}
} }
*length -= position; memcpy(fData + position, buffer, *length);
memcpy(buffer, fData + position, *length);
return B_OK; return B_OK;
} }
@ -478,6 +925,13 @@ AttributeEntry::ReadStat(struct stat *stat)
} }
status_t
AttributeEntry::WriteStat(const struct stat *stat, uint32 statMask)
{
return B_UNSUPPORTED;
}
// #pragma mark - vnode ops // #pragma mark - vnode ops
@ -860,11 +1314,20 @@ static status_t
overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
{ {
OVERLAY_CALL(open_attr_dir, cookie) OVERLAY_CALL(open_attr_dir, cookie)
AttributeFile *attributeFile = node->GetAttributeFile();
if (attributeFile == NULL)
return B_UNSUPPORTED;
*cookie = attributeFile; AttributeFile *attributeFile = NULL;
status_t result = node->GetAttributeFile(&attributeFile);
if (result != B_OK)
return result;
attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)malloc(
sizeof(attribute_dir_cookie));
if (dirCookie == NULL)
return B_NO_MEMORY;
dirCookie->file = attributeFile;
dirCookie->index = 0;
*cookie = dirCookie;
return B_OK; return B_OK;
} }
@ -881,6 +1344,7 @@ static status_t
overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
{ {
OVERLAY_CALL(free_attr_dir_cookie, cookie) OVERLAY_CALL(free_attr_dir_cookie, cookie)
free(cookie);
return B_OK; return B_OK;
} }
@ -890,8 +1354,9 @@ overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
struct dirent *buffer, size_t bufferSize, uint32 *num) struct dirent *buffer, size_t bufferSize, uint32 *num)
{ {
OVERLAY_CALL(read_attr_dir, cookie, buffer, bufferSize, num) OVERLAY_CALL(read_attr_dir, cookie, buffer, bufferSize, num)
AttributeFile *attributeFile = (AttributeFile *)cookie; attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie;
return attributeFile->ReadAttributeDir(buffer, bufferSize, num); return dirCookie->file->ReadAttributeDir(buffer, bufferSize, num,
&dirCookie->index);
} }
@ -899,8 +1364,9 @@ static status_t
overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
{ {
OVERLAY_CALL(rewind_attr_dir, cookie) OVERLAY_CALL(rewind_attr_dir, cookie)
AttributeFile *attributeFile = (AttributeFile *)cookie; attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie;
return attributeFile->RewindAttributeDir(); dirCookie->index = 0;
return B_OK;
} }
@ -909,7 +1375,14 @@ overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
uint32 type, int openMode, void **cookie) uint32 type, int openMode, void **cookie)
{ {
OVERLAY_CALL(create_attr, name, type, openMode, cookie) OVERLAY_CALL(create_attr, name, type, openMode, cookie)
return B_UNSUPPORTED;
AttributeFile *attributeFile = NULL;
status_t result = node->GetAttributeFile(&attributeFile);
if (result != B_OK)
return result;
return attributeFile->CreateAttribute(name, type, openMode,
(AttributeEntry **)cookie);
} }
@ -919,16 +1392,13 @@ overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
{ {
OVERLAY_CALL(open_attr, name, openMode, cookie) OVERLAY_CALL(open_attr, name, openMode, cookie)
AttributeFile *attributeFile = node->GetAttributeFile(); AttributeFile *attributeFile = NULL;
if (attributeFile == NULL) status_t result = node->GetAttributeFile(&attributeFile);
return B_UNSUPPORTED; if (result != B_OK)
return result;
AttributeEntry *entry = attributeFile->FindAttribute(name); return attributeFile->OpenAttribute(name, openMode,
if (entry == NULL) (AttributeEntry **)cookie);
return B_ENTRY_NOT_FOUND;
*cookie = entry;
return B_OK;
} }
@ -963,7 +1433,8 @@ overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
const void *buffer, size_t *length) const void *buffer, size_t *length)
{ {
OVERLAY_CALL(write_attr, cookie, pos, buffer, length) OVERLAY_CALL(write_attr, cookie, pos, buffer, length)
return B_UNSUPPORTED; AttributeEntry *entry = (AttributeEntry *)cookie;
return entry->Write(pos, buffer, length);
} }
@ -982,7 +1453,8 @@ overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
const struct stat *stat, int statMask) const struct stat *stat, int statMask)
{ {
OVERLAY_CALL(write_attr_stat, cookie, stat, statMask) OVERLAY_CALL(write_attr_stat, cookie, stat, statMask)
return B_UNSUPPORTED; AttributeEntry *entry = (AttributeEntry *)cookie;
return entry->WriteStat(stat, statMask);
} }
@ -991,7 +1463,41 @@ overlay_rename_attr(fs_volume *volume, fs_vnode *vnode,
const char *fromName, fs_vnode *toVnode, const char *toName) const char *fromName, fs_vnode *toVnode, const char *toName)
{ {
OVERLAY_CALL(rename_attr, fromName, toVnode, toName) OVERLAY_CALL(rename_attr, fromName, toVnode, toName)
return B_UNSUPPORTED;
AttributeFile *attributeFile = NULL;
status_t result = node->GetAttributeFile(&attributeFile);
if (result != B_OK)
return B_OK;
AttributeFile *toAttributeFile = attributeFile;
if (vnode->private_node != toVnode->private_node) {
OverlayInode *toNode = (OverlayInode *)toVnode->private_node;
result = toNode->GetAttributeFile(&toAttributeFile);
if (result != B_OK)
return result;
}
AttributeEntry *entry = NULL;
result = attributeFile->RemoveAttribute(fromName, &entry);
if (result != B_OK)
return result;
result = entry->SetName(toName);
if (result != B_OK) {
if (attributeFile->AddAttribute(entry) != B_OK)
delete entry;
return result;
}
result = toAttributeFile->AddAttribute(entry);
if (result != B_OK) {
if (entry->SetName(fromName) != B_OK
|| attributeFile->AddAttribute(entry) != B_OK)
delete entry;
return result;
}
return B_OK;
} }
@ -999,7 +1505,13 @@ static status_t
overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name) overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name)
{ {
OVERLAY_CALL(remove_attr, name) OVERLAY_CALL(remove_attr, name)
return B_UNSUPPORTED;
AttributeFile *attributeFile = NULL;
status_t result = node->GetAttributeFile(&attributeFile);
if (result != B_OK)
return result;
return attributeFile->RemoveAttribute(name, NULL);
} }