* 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:
parent
5076aaf050
commit
3b5507a987
@ -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, ¤tVnode.private_node,
|
fStatus = get_vnode(volume, inodeNumber, ¤tVnode.private_node,
|
||||||
¤tVnode.ops);
|
¤tVnode.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,
|
||||||
|
¤tVnode.private_node, ¤tVnode.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, ¤tVnode,
|
||||||
|
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,
|
||||||
|
¤tVnode.private_node, ¤tVnode.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, ¤tVnode,
|
||||||
|
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,
|
||||||
|
¤tVnode.private_node, ¤tVnode.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,
|
||||||
|
¤tVnode.private_node, ¤tVnode.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, ¤tVnode, 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, ¤tVnode, 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, ¤tVnode, 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, ¤tVnode, 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, ¤tVnode, attrFileCookie);
|
||||||
|
if (currentVnode.ops->free_cookie != NULL)
|
||||||
|
currentVnode.ops->free_cookie(volume, ¤tVnode, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user