Open/close attribute support for xattrs backend

For the xattr/BSD (untyped) attribute backend implement fs_fopen_attr()
and fs_close_attr(). A new AttributeDescriptor is created. It is
currently used in write_pos() only.
This commit is contained in:
Ingo Weinhold
2011-11-25 06:17:32 +01:00
parent b19dacd077
commit d9516a06cc
5 changed files with 305 additions and 87 deletions
+62 -49
View File
@@ -130,17 +130,17 @@ normalize_dir_path(string path, NodeRef ref, string &normalizedPath)
status_t error = find_dir_entry(path.c_str(), ref, name, true) ;
if (error != B_OK)
return error;
// recurse to get the parent dir path, if found
error = normalize_dir_path(path, parentRef, normalizedPath);
if (error != 0)
return error;
// construct the normalizedPath
// construct the normalizedPath
if (normalizedPath.length() > 1) // don't append "/", if parent is root
normalizedPath += '/';
normalizedPath += name;
return 0;
}
@@ -152,7 +152,7 @@ normalize_dir_path(const char *path, string &normalizedPath)
struct stat st;
if (stat(path, &st) < 0)
return errno;
return normalize_dir_path(path, NodeRef(st), normalizedPath);
}
@@ -162,7 +162,7 @@ normalize_entry_path(const char *path, string &normalizedPath)
{
const char *dirPath = NULL;
const char *leafName = NULL;
string dirPathString;
if (const char *lastSlash = strrchr(path, '/')) {
// found a slash: decompose into dir path and leaf name
@@ -184,7 +184,7 @@ normalize_entry_path(const char *path, string &normalizedPath)
// catch special case: no leaf, or leaf is a directory
if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0)
return normalize_dir_path(path, normalizedPath);
// normalize the dir path
status_t error = normalize_dir_path(dirPath, normalizedPath);
if (error != B_OK)
@@ -222,7 +222,7 @@ get_path(const NodeRef *ref, const char *name, string &path)
DirPathMap::iterator it = sDirPathMap.find(*ref);
if (it == sDirPathMap.end())
return B_ENTRY_NOT_FOUND;
path = it->second;
// stat the path to check, if it is still valid
@@ -250,7 +250,7 @@ get_path(const NodeRef *ref, const char *name, string &path)
path += '/';
path += name;
}
return B_OK;
}
@@ -272,7 +272,7 @@ BPrivate::get_path(int fd, const char *name, string &path)
return error;
return ::get_path(&ref, name, path);
} else // no descriptor or absolute path
return ::get_path((NodeRef*)NULL, name, path);
}
@@ -284,7 +284,7 @@ get_path(dev_t device, ino_t directory, const char *name, string &path)
NodeRef ref;
ref.device = device;
ref.node = directory;
return get_path(&ref, name, path);
}
@@ -315,7 +315,7 @@ _kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf,
// copy it back to the user buffer
if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength)
return B_BUFFER_OVERFLOW;
return B_OK;
}
@@ -334,8 +334,8 @@ _kern_create_dir(int fd, const char *path, int perms)
// mkdir
if (mkdir(realPath.c_str(), perms) < 0)
return errno;
return errno;
return B_OK;
}
@@ -352,8 +352,8 @@ _kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name,
// mkdir
if (mkdir(realPath.c_str(), perms) < 0)
return errno;
return errno;
return B_OK;
}
@@ -382,7 +382,7 @@ open_dir(const char *path)
NodeRef ref(st);
add_dir_path(path, ref);
// create descriptor
// create descriptor
DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref);
return add_descriptor(descriptor);
}
@@ -443,7 +443,7 @@ _kern_open_parent_dir(int fd, char *name, size_t nameLength)
return B_BUFFER_OVERFLOW;
// open the parent directory
return open_dir(realPath.c_str());
}
@@ -455,7 +455,7 @@ _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
if (maxCount <= 0)
return B_BAD_VALUE;
// get the descriptor
// get the descriptor
DirectoryDescriptor *descriptor
= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
if (!descriptor)
@@ -484,7 +484,7 @@ _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
status_t
_kern_rewind_dir(int fd)
{
// get the descriptor
// get the descriptor
DirectoryDescriptor *descriptor
= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
if (!descriptor)
@@ -523,7 +523,7 @@ open_file(const char *path, int openMode, int perms)
status_t error = normalize_entry_path(path, normalizedPath);
if (error != B_OK)
return error;
descriptor = new SymlinkDescriptor(normalizedPath.c_str());
} else {
// open the file
@@ -534,11 +534,11 @@ open_file(const char *path, int openMode, int perms)
descriptor = new FileDescriptor(newFD);
}
// cache path, if this is a directory
if (exists && S_ISDIR(st.st_mode))
add_dir_path(path, NodeRef(st));
return add_descriptor(descriptor);
}
@@ -603,7 +603,7 @@ _kern_read(int fd, off_t pos, void *buffer, size_t bufferSize)
if (result < 0)
return errno;
}
// read
ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer,
bufferSize);
@@ -629,7 +629,7 @@ _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize)
if (result < 0)
return errno;
}
// read
ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer,
bufferSize);
@@ -706,10 +706,10 @@ _kern_read_stat(int fd, const char *path, bool traverseLink,
Descriptor *descriptor = get_descriptor(fd);
if (!descriptor)
return B_FILE_ERROR;
return descriptor->GetStat(traverseLink, st);
}
return B_OK;
}
@@ -734,7 +734,7 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
return errno;
isSymlink = S_ISLNK(tmpStat.st_mode);
} else {
Descriptor *descriptor = get_descriptor(fd);
if (!descriptor)
@@ -743,17 +743,17 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
if (FileDescriptor *fileFD
= dynamic_cast<FileDescriptor*>(descriptor)) {
realFD = fileFD->fd;
} else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) {
error = get_path(fd, NULL, realPath);
if (error != B_OK)
return error;
} else if (SymlinkDescriptor *linkFD
= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
realPath = linkFD->path;
isSymlink = true;
} else
return B_FILE_ERROR;
}
@@ -762,23 +762,23 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
// available functions traverse symlinks.
if (isSymlink && !traverseLink)
return B_ERROR;
if (realFD >= 0) {
if (statMask & B_STAT_MODE) {
if (fchmod(realFD, st->st_mode) < 0)
return errno;
}
if (statMask & B_STAT_UID) {
if (fchown(realFD, st->st_uid, (gid_t)-1) < 0)
return errno;
}
if (statMask & B_STAT_GID) {
if (fchown(realFD, (uid_t)-1, st->st_gid) < 0)
return errno;
}
if (statMask & B_STAT_SIZE) {
if (ftruncate(realFD, st->st_size) < 0)
return errno;
@@ -790,25 +790,25 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) {
return B_ERROR;
}
return 0;
} else {
if (statMask & B_STAT_MODE) {
if (chmod(realPath.c_str(), st->st_mode) < 0)
return errno;
}
if (statMask & B_STAT_UID) {
if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0)
return errno;
}
if (statMask & B_STAT_GID) {
if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0)
return errno;
}
if (statMask & B_STAT_SIZE) {
if (truncate(realPath.c_str(), st->st_size) < 0)
return errno;
@@ -822,18 +822,18 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
if (stat(realPath.c_str(), &oldStat) < 0)
return errno;
}
utimbuf buffer;
buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime;
buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime;
if (utime(realPath.c_str(), &buffer) < 0)
return errno;
}
// not supported
// not supported
if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME))
return B_ERROR;
}
}
return B_OK;
}
@@ -878,7 +878,7 @@ _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
if (*_bufferSize > 0) {
if ((size_t)bytesRead == *_bufferSize)
bytesRead--;
buffer[bytesRead] = '\0';
}
@@ -918,7 +918,7 @@ _kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath)
error = get_path(newDir, newPath, realNewPath);
if (error != B_OK)
return error;
// rename
if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0)
return errno;
@@ -954,7 +954,7 @@ read_pos(int fd, off_t pos, void *buffer, size_t bufferSize)
off_t result = lseek(fd, pos, SEEK_SET);
if (result < 0)
return errno;
// read
ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize);
if (bytesRead < 0) {
@@ -969,12 +969,25 @@ read_pos(int fd, off_t pos, void *buffer, size_t bufferSize)
ssize_t
write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize)
{
// If this is an attribute descriptor, let it do the job.
AttributeDescriptor* descriptor
= dynamic_cast<AttributeDescriptor*>(get_descriptor(fd));
if (descriptor != NULL) {
status_t error = descriptor->Write(pos, buffer, bufferSize);
if (error != B_OK) {
errno = error;
return -1;
}
return 0;
}
// seek
off_t result = lseek(fd, pos, SEEK_SET);
if (result < 0)
return errno;
// read
// write
ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize);
if (bytesWritten < 0) {
errno = bytesWritten;
@@ -992,7 +1005,7 @@ readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count)
off_t result = lseek(fd, pos, SEEK_SET);
if (result < 0)
return errno;
// read
ssize_t bytesRead = haiku_host_platform_readv(fd, vec, count);
if (bytesRead < 0) {
@@ -1011,7 +1024,7 @@ writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count)
off_t result = lseek(fd, pos, SEEK_SET);
if (result < 0)
return errno;
// read
ssize_t bytesWritten = haiku_host_platform_writev(fd, vec, count);
if (bytesWritten < 0) {
+27 -27
View File
@@ -33,7 +33,7 @@ init_attribute_dir_base_dir()
if (initialized)
return initError;
// stat the dir
struct stat st;
initError = B_OK;
@@ -44,7 +44,7 @@ init_attribute_dir_base_dir()
"directory base directory exists, but is no directory!\n");
initError = B_FILE_ERROR;
}
} else {
// doesn't exist yet: create it
if (mkdir(sAttributeDirBasePath, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
@@ -68,7 +68,7 @@ escape_attr_name(const char *name)
escapedName += "__";
else
escapedName += *name;
name++;
}
@@ -84,7 +84,7 @@ deescape_attr_name(const char *name)
return "___";
}
name++;
string deescapedName;
while (*name != '\0') {
if (*name == '_') {
@@ -100,11 +100,11 @@ deescape_attr_name(const char *name)
}
} else
deescapedName += *name;
name++;
}
return deescapedName;
return deescapedName;
}
// get_attribute_dir_path
@@ -179,7 +179,7 @@ get_attribute_path(NodeRef ref, const char *path, int fd,
errno = error;
return -1;
}
// construct the attribute path
attrPath = get_attribute_dir_path(ref) + '/';
string attrName(escape_attr_name(attribute));
@@ -206,7 +206,7 @@ get_attribute_path_virtual_fd(int fd, const char *attribute, string &attrPath,
// (i.e. system) file descriptor, which is just as well.
string path;
bool pathValid = (get_path(fd, NULL, path) == B_OK);
// get the attribute path
return get_attribute_path(ref, (pathValid ? path.c_str() : NULL),
(pathValid ? -1 : fd), attribute, attrPath, typePath);
@@ -269,7 +269,7 @@ fs_fopen_attr_dir(int fd)
// (i.e. system) file descriptor, which is just as well.
string path;
bool pathValid = (get_path(fd, NULL, path) == B_OK);
// get the attribute path
return open_attr_dir(NodeRef(st), (pathValid ? path.c_str() : NULL),
(pathValid ? -1 : fd));
@@ -292,8 +292,8 @@ fs_read_attr_dir(DIR *dir)
entry = readdir(dir);
if (!entry)
return NULL;
// ignore administrative entries; the
// ignore administrative entries; the
if (entry->d_name[0] == '_') {
string attrName = deescape_attr_name(entry->d_name);
strcpy(entry->d_name, attrName.c_str());
@@ -309,15 +309,15 @@ fs_rewind_attr_dir(DIR *dir)
rewinddir(dir);
}
// fs_open_attr
// fs_fopen_attr
int
fs_open_attr(int fd, const char *attribute, uint32 type, int openMode)
fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode)
{
if (!attribute) {
errno = B_BAD_VALUE;
return -1;
}
// get the attribute path
string attrPath;
string typePath;
@@ -344,7 +344,7 @@ fs_open_attr(int fd, const char *attribute, uint32 type, int openMode)
// write the type into the file
if (write(typeFD, &type, sizeof(type)) < 0)
error = errno;
close(typeFD);
} else
@@ -355,10 +355,10 @@ fs_open_attr(int fd, const char *attribute, uint32 type, int openMode)
if (typeFD > 0) {
unlink(typePath.c_str());
}
close(attrFD);
unlink(attrPath.c_str());
errno = error;
return -1;
}
@@ -395,7 +395,7 @@ fs_read_attr(int fd, const char *attribute, uint32 type, off_t pos,
errno = error;
return -1;
}
return bytesRead;
}
@@ -421,7 +421,7 @@ fs_write_attr(int fd, const char *attribute, uint32 type, off_t pos,
errno = error;
return -1;
}
return bytesWritten;
}
@@ -433,7 +433,7 @@ fs_remove_attr(int fd, const char *attribute)
errno = B_BAD_VALUE;
return -1;
}
// get the attribute path
string attrPath;
string typePath;
@@ -446,9 +446,9 @@ fs_remove_attr(int fd, const char *attribute)
// remove the attribute
if (unlink(attrPath.c_str()) < 0)
return -1;
unlink(typePath.c_str());
return B_OK;
}
@@ -474,7 +474,7 @@ fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo)
struct stat st;
if (lstat(attrPath.c_str(), &st) < 0)
return -1;
attrInfo->size = st.st_size;
// now open the attribute type file and read the attribute's type
@@ -496,7 +496,7 @@ fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo)
return -1;
}
return 0;
return 0;
}
@@ -524,14 +524,14 @@ _kern_open_attr_dir(int fd, const char *path)
if (error != B_OK)
return error;
}
// open the attr dir
DIR *dir = open_attr_dir(ref, (path ? realPath.c_str() : NULL),
(path ? -1 : fd));
if (!dir)
return errno;
// create descriptor
// create descriptor
AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref);
return add_descriptor(descriptor);
}
@@ -571,7 +571,7 @@ _kern_rename_attr(int fromFile, const char *fromName, int toFile,
return error;
}
return B_OK;
}
+36 -8
View File
@@ -452,22 +452,50 @@ fs_rewind_attr_dir(DIR *dir)
attrDir->RewindDir();
}
// fs_open_attr
// fs_fopen_attr
int
fs_open_attr(int fd, const char *attribute, uint32 type, int openMode)
fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode)
{
// not supported ATM
errno = B_BAD_VALUE;
return -1;
if (fd < 0) {
errno = B_BAD_VALUE;
return -1;
}
AttributeDescriptor* descriptor = new(std::nothrow) AttributeDescriptor(fd,
attribute, type, openMode);
if (descriptor == NULL) {
errno = B_NO_MEMORY;
return -1;
}
status_t error = descriptor->Init();
if (error != B_OK) {
delete descriptor;
errno = error;
return -1;
}
int attributeFD = add_descriptor(descriptor);
if (attributeFD < 0) {
delete descriptor;
errno = B_NO_MEMORY;
return -1;
}
return attributeFD;
}
// fs_close_attr
int
fs_close_attr(int fd)
{
// not supported ATM
errno = B_BAD_VALUE;
return -1;
status_t error = delete_descriptor(fd);
if (error != 0) {
errno = error;
return -1;
}
return 0;
}
// fs_read_attr
+147
View File
@@ -11,7 +11,9 @@
#include <map>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fs_attr.h>
@@ -250,6 +252,151 @@ SymlinkDescriptor::GetPath(string& path) const
}
// #pragma mark - AttributeDescriptor
AttributeDescriptor::AttributeDescriptor(int fileFD, const char* attribute,
uint32 type, int openMode)
:
fFileFD(dup(fileFD)),
fType(type),
fOpenMode(openMode),
fData(NULL),
fDataSize(0)
{
strlcpy(fAttribute, attribute, sizeof(fAttribute));
}
AttributeDescriptor::~AttributeDescriptor()
{
Close();
}
status_t
AttributeDescriptor::Init()
{
if (fFileFD < 0)
return B_IO_ERROR;
// stat the attribute
attr_info info;
if (fs_stat_attr(fFileFD, fAttribute, &info) < 0) {
if (errno == B_ENTRY_NOT_FOUND) {
if ((fOpenMode & O_CREAT) == 0)
return errno;
// create the attribute
if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0)
return errno;
return B_OK;
}
return errno;
}
if ((fOpenMode & O_TRUNC) == 0) {
// truncate the attribute
if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0)
return errno;
return B_OK;
}
// we have to read in the attribute data
if (info.size == 0)
return B_OK;
fData = (uint8*)malloc(info.size);
if (fData == NULL)
return B_NO_MEMORY;
fDataSize = info.size;
ssize_t bytesRead = fs_read_attr(fFileFD, fAttribute, fType, 0, fData,
fDataSize);
if (bytesRead < 0)
return errno;
if ((size_t)bytesRead != fDataSize)
return B_IO_ERROR;
return B_OK;
}
status_t
AttributeDescriptor::Write(off_t offset, const void* buffer, size_t bufferSize)
{
if (offset < 0)
return B_BAD_VALUE;
if ((fOpenMode & O_ACCMODE) != O_WRONLY
&& (fOpenMode & O_ACCMODE) != O_RDWR) {
return B_NOT_ALLOWED;
}
// we may need to resize the buffer
size_t minSize = (size_t)offset + bufferSize;
if (minSize > fDataSize) {
uint8* data = (uint8*)realloc(fData, minSize);
if (data == NULL)
return B_NO_MEMORY;
if ((size_t)offset > fDataSize)
memset(data + offset, 0, offset - fDataSize);
fData = data;
fDataSize = minSize;
}
// copy the data and write all of it
if (bufferSize == 0)
return B_OK;
memcpy((uint8*)fData + offset, buffer, bufferSize);
ssize_t bytesWritten = fs_write_attr(fFileFD, fAttribute, fType, 0,
fData, fDataSize);
if (bytesWritten < 0)
return errno;
if ((size_t)bytesWritten != fDataSize)
return B_IO_ERROR;
return B_OK;
}
status_t
AttributeDescriptor::Close()
{
if (fFileFD < 0)
return B_BAD_VALUE;
close(fFileFD);
fFileFD = -1;
free(fData);
fData = NULL;
fDataSize = 0;
return B_OK;
}
status_t
AttributeDescriptor::Dup(Descriptor*& clone)
{
return B_NOT_SUPPORTED;
}
status_t
AttributeDescriptor::GetStat(bool traverseLink, struct stat* st)
{
return B_NOT_SUPPORTED;
}
// #pragma mark - AttrDirDescriptor
+33 -3
View File
@@ -5,6 +5,7 @@
#include <string>
#include <StorageDefs.h>
#include <SupportDefs.h>
#include "NodeRef.h"
@@ -35,7 +36,7 @@ struct Descriptor {
struct FileDescriptor : Descriptor {
FileDescriptor(int fd);
virtual ~FileDescriptor();
virtual status_t Close();
virtual status_t Dup(Descriptor *&clone);
virtual status_t GetStat(bool traverseLink, struct stat *st);
@@ -50,7 +51,7 @@ struct DirectoryDescriptor : Descriptor {
DirectoryDescriptor(DIR *dir, const NodeRef &ref);
virtual ~DirectoryDescriptor();
virtual status_t Close();
virtual status_t Dup(Descriptor *&clone);
virtual status_t GetStat(bool traverseLink, struct stat *st);
@@ -71,12 +72,41 @@ struct SymlinkDescriptor : Descriptor {
virtual status_t GetPath(string& path) const;
};
// AttributeDescriptor
struct AttributeDescriptor : Descriptor {
AttributeDescriptor(int fileFD,
const char* attribute, uint32 type,
int openMode);
virtual ~AttributeDescriptor();
status_t Init();
status_t Write(off_t offset, const void* buffer,
size_t bufferSize);
int FileFD() const { return fFileFD; }
const char* Attribute() const { return fAttribute; }
uint32 Type() const { return fType; }
int OpenMode() const { return fOpenMode; }
virtual status_t Close();
virtual status_t Dup(Descriptor*& clone);
virtual status_t GetStat(bool traverseLink, struct stat* st);
private:
int fFileFD;
char fAttribute[B_ATTR_NAME_LENGTH];
uint32 fType;
int fOpenMode;
uint8* fData;
size_t fDataSize;
};
// AttrDirDescriptor
struct AttrDirDescriptor : DirectoryDescriptor {
AttrDirDescriptor(DIR *dir, const NodeRef &ref);
virtual ~AttrDirDescriptor();
virtual status_t Close();
virtual status_t Dup(Descriptor *&clone);
virtual status_t GetStat(bool traverseLink, struct stat *st);