Tried to improve the attribute support under non-BeOS compatible

build platforms a bit. Generally extended attributes seem to be
supported up to a very limited size per node, thus a one-to-one
mapping isn't a good idea, but I figured, they could at least
help to recognize when and attribute directory doesn't belong to
a node (in case the original node had been removed and the a new
one created with the same node ID).
The implementation should ensure that, but I can't really test
it, since ReiserFS 3.6 under my SuSE Linux 9.2 installation
apparently doesn't support extended attributes. So it's disabled
for the time being.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16228 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2006-02-04 01:55:49 +00:00
parent 129cc3cbe1
commit 1621d9945f
3 changed files with 168 additions and 24 deletions

View File

@ -25,7 +25,6 @@ using namespace BPrivate;
static const int kVirtualDescriptorStart = 10000;
static status_t get_path(int fd, const char *name, string &path);
static status_t get_path(dev_t device, ino_t node, const char *name, string &path);
namespace BPrivate {
@ -506,8 +505,8 @@ get_path(const NodeRef *ref, const char *name, string &path)
}
// get_path
static status_t
get_path(int fd, const char *name, string &path)
status_t
BPrivate::get_path(int fd, const char *name, string &path)
{
// get the node ref for the fd, if any, and the path part is not absolute
if (fd >= 0 && !(name && name[0] == '/')) {
@ -522,10 +521,10 @@ get_path(int fd, const char *name, string &path)
if (error != B_OK)
return error;
return get_path(&ref, name, path);
return ::get_path(&ref, name, path);
} else // no descriptor or absolute path
return get_path((NodeRef*)NULL, name, path);
return ::get_path((NodeRef*)NULL, name, path);
}
// get_path
@ -1210,8 +1209,17 @@ _kern_open_attr_dir(int fd, const char *path)
}
NodeRef ref(st);
// If a path was given, get a usable path.
string realPath;
if (path) {
error = get_path(fd, path, realPath);
if (error != B_OK)
return error;
}
// open the attr dir
DIR *dir = open_attr_dir(ref);
DIR *dir = open_attr_dir(ref, (path ? realPath.c_str() : NULL),
(path ? -1 : fd));
if (!dir)
return errno;
@ -1232,8 +1240,14 @@ get_attribute_path(int fd, const char *attribute, string &attrPath,
return error;
NodeRef ref(st);
// Try to get a path. If we can't get a path, this is must be a "real"
// (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, attribute, attrPath, typePath);
return get_attribute_path(ref, (pathValid ? path.c_str() : NULL),
(pathValid ? -1 : fd), attribute, attrPath, typePath);
}
// _kern_rename_attr

View File

@ -9,6 +9,11 @@
# include <syscalls.h>
#endif
// Defined, if the host platform has extended attribute support.
// Unfortunately I don't seem to have extended attribute support under
// SuSE Linux 9.2 (kernel 2.6.8-...) with ReiserFS 3.6.
//#define HAS_EXTENDED_ATTRIBUTE_SUPPORT 1
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@ -23,6 +28,12 @@
#include "fs_attr_impl.h"
#ifdef HAS_EXTENDED_ATTRIBUTE_SUPPORT
#include <sys/xattr.h>
static const char *kAttributeDirMarkAttributeName = "_has_haiku_attr_dir";
#endif
using namespace std;
using namespace BPrivate;
@ -122,9 +133,90 @@ get_attribute_dir_path(NodeRef ref)
return attrDirPath;
}
// has_attribute_dir_mark
static bool
has_attribute_dir_mark(const char *path, int fd)
{
#ifdef HAS_EXTENDED_ATTRIBUTE_SUPPORT
uint8 value;
if (path) {
return (lgetxattr(path, kAttributeDirMarkAttributeName, &value, 1)
> 0);
} else {
return (fgetxattr(fd, kAttributeDirMarkAttributeName, &value, 1)
> 0);
}
#else // !HAS_EXTENDED_ATTRIBUTE_SUPPORT
// No extended attribute support. We can't mark the file and thus
// have to handle it as marked.
return true;
#endif
}
// set_attribute_dir_mark
static status_t
set_attribute_dir_mark(const char *path, int fd)
{
#ifdef HAS_EXTENDED_ATTRIBUTE_SUPPORT
uint8 value = 1;
if (path) {
if (lsetxattr(path, kAttributeDirMarkAttributeName, &value, 1, 0)
< 0) {
fprintf(stderr, "set_attribute_dir_mark(): lsetxattr() "
"failed on \"%s\"\n", path);
return errno;
}
} else {
if (fsetxattr(fd, kAttributeDirMarkAttributeName, &value, 1, 0)
< 0) {
fprintf(stderr, "set_attribute_dir_mark(): fsetxattr() "
"failed on FD \"%d\"\n", fd);
return errno;
}
}
#endif
return B_OK;
}
// empty_attribute_dir
static status_t
empty_attribute_dir(const char *path)
{
DIR *dir = opendir(path);
if (!dir)
return errno;
while (dirent *entry = readdir(dir)) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
string entryPath(path);
entryPath += '/';
entryPath += entry->d_name;
// We assume the attribute dir contains files only (we only create
// files) and thus use unlink().
if (unlink(entryPath.c_str()) < 0) {
status_t error = errno;
closedir(dir);
return error;
}
}
closedir(dir);
return B_OK;
}
// ensure_attribute_dir_exists
static status_t
ensure_attribute_dir_exists(NodeRef ref)
ensure_attribute_dir_exists(NodeRef ref, const char *path, int fd)
{
// init the base directory here
status_t error = init_attribute_dir_base_dir();
@ -138,25 +230,45 @@ ensure_attribute_dir_exists(NodeRef ref)
if (!S_ISDIR(st.st_mode)) {
// the attribute dir is no directory
fprintf(stderr, "ensure_attribute_dir_exists(): Attribute "
"directory for node %lld exists, but is no directory!\n");
"directory for node %lld exists, but is no directory!\n",
ref.node);
return B_FILE_ERROR;
}
return B_OK;
// already exists: Check whether the file is marked. If not, this
// is a stale attribute directory from a deleted node that had the
// same node ID as this one.
if (has_attribute_dir_mark(path, fd))
return B_OK;
// empty the attribute dir
error = empty_attribute_dir(attrDirPath.c_str());
if (error != B_OK) {
fprintf(stderr, "ensure_attribute_dir_exists(): Attribute "
"directory for node %lld exists, the node has no mark, and "
"emptying the attribute directory failed\n",
ref.node);
return error;
}
// mark the file
return set_attribute_dir_mark(path, fd);
}
// doesn't exist yet: create it
if (mkdir(attrDirPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) < 0)
return errno;
return B_OK;
// mark the file
return set_attribute_dir_mark(path, fd);
}
// open_attr_dir
DIR *
BPrivate::open_attr_dir(NodeRef ref)
BPrivate::open_attr_dir(NodeRef ref, const char *path, int fd)
{
// make sure the directory exists
status_t error = ensure_attribute_dir_exists(ref);
status_t error = ensure_attribute_dir_exists(ref, path, fd);
if (error != B_OK) {
errno = error;
return NULL;
@ -169,14 +281,14 @@ BPrivate::open_attr_dir(NodeRef ref)
// get_attribute_path
status_t
BPrivate::get_attribute_path(NodeRef ref, const char *attribute,
string &attrPath, string &typePath)
BPrivate::get_attribute_path(NodeRef ref, const char *path, int fd,
const char *attribute, string &attrPath, string &typePath)
{
if (!attribute || strlen(attribute) == 0)
return B_BAD_VALUE;
// make sure the attribute dir for the node exits
status_t error = ensure_attribute_dir_exists(ref);
status_t error = ensure_attribute_dir_exists(ref, path, fd);
if (error != B_OK) {
errno = error;
return -1;
@ -202,7 +314,7 @@ get_attribute_path(int fd, const char *attribute, string &attrPath,
return errno;
NodeRef ref(st);
return get_attribute_path(ref, attribute, attrPath, typePath);
return get_attribute_path(ref, NULL, fd, attribute, attrPath, typePath);
}
// fs_open_attr_dir
@ -213,7 +325,7 @@ fs_open_attr_dir(const char *path)
if (lstat(path, &st))
return NULL;
return open_attr_dir(NodeRef(st));
return open_attr_dir(NodeRef(st), path, -1);
}
// fs_fopen_attr_dir
@ -227,6 +339,8 @@ fs_fopen_attr_dir(int fd)
if (fstat(fd, &st) < 0)
return NULL;
return open_attr_dir(NodeRef(st), NULL, fd);
#else
status_t error = _kern_read_stat(fd, NULL, false, &st,
@ -236,9 +350,16 @@ fs_fopen_attr_dir(int fd)
return NULL;
}
#endif
// Try to get a path. If we can't get a path, this is must be a "real"
// (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));
return open_attr_dir(NodeRef(st));
#endif
}
// fs_close_attr_dir

View File

@ -9,10 +9,19 @@
namespace BPrivate {
DIR *open_attr_dir(NodeRef ref);
// defined in fs_attr.cpp
status_t get_attribute_path(NodeRef ref, const char *attribute,
std::string &attrPath, std::string &typePath);
// Note: Only one of path or fd can be supplied.
DIR *open_attr_dir(NodeRef ref, const char *path, int fd);
// Note: Only one of path or fd can be supplied.
status_t get_attribute_path(NodeRef ref, const char *path, int fd,
const char *attribute, std::string &attrPath, std::string &typePath);
// defined in fs.cpp
status_t get_path(int fd, const char *name, std::string &path);
} // namespace BPrivate