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:
@@ -25,7 +25,6 @@ using namespace BPrivate;
|
|||||||
|
|
||||||
static const int kVirtualDescriptorStart = 10000;
|
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);
|
static status_t get_path(dev_t device, ino_t node, const char *name, string &path);
|
||||||
|
|
||||||
namespace BPrivate {
|
namespace BPrivate {
|
||||||
@@ -506,8 +505,8 @@ get_path(const NodeRef *ref, const char *name, string &path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get_path
|
// get_path
|
||||||
static status_t
|
status_t
|
||||||
get_path(int fd, const char *name, string &path)
|
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
|
// get the node ref for the fd, if any, and the path part is not absolute
|
||||||
if (fd >= 0 && !(name && name[0] == '/')) {
|
if (fd >= 0 && !(name && name[0] == '/')) {
|
||||||
@@ -522,10 +521,10 @@ get_path(int fd, const char *name, string &path)
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return get_path(&ref, name, path);
|
return ::get_path(&ref, name, path);
|
||||||
|
|
||||||
} else // no descriptor or absolute path
|
} else // no descriptor or absolute path
|
||||||
return get_path((NodeRef*)NULL, name, path);
|
return ::get_path((NodeRef*)NULL, name, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get_path
|
// get_path
|
||||||
@@ -1210,8 +1209,17 @@ _kern_open_attr_dir(int fd, const char *path)
|
|||||||
}
|
}
|
||||||
NodeRef ref(st);
|
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
|
// 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)
|
if (!dir)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
@@ -1232,8 +1240,14 @@ get_attribute_path(int fd, const char *attribute, string &attrPath,
|
|||||||
return error;
|
return error;
|
||||||
NodeRef ref(st);
|
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
|
// 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
|
// _kern_rename_attr
|
||||||
|
|||||||
+135
-14
@@ -9,6 +9,11 @@
|
|||||||
# include <syscalls.h>
|
# include <syscalls.h>
|
||||||
#endif
|
#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 <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -23,6 +28,12 @@
|
|||||||
|
|
||||||
#include "fs_attr_impl.h"
|
#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 std;
|
||||||
using namespace BPrivate;
|
using namespace BPrivate;
|
||||||
|
|
||||||
@@ -122,9 +133,90 @@ get_attribute_dir_path(NodeRef ref)
|
|||||||
return attrDirPath;
|
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
|
// ensure_attribute_dir_exists
|
||||||
static status_t
|
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
|
// init the base directory here
|
||||||
status_t error = init_attribute_dir_base_dir();
|
status_t error = init_attribute_dir_base_dir();
|
||||||
@@ -138,25 +230,45 @@ ensure_attribute_dir_exists(NodeRef ref)
|
|||||||
if (!S_ISDIR(st.st_mode)) {
|
if (!S_ISDIR(st.st_mode)) {
|
||||||
// the attribute dir is no directory
|
// the attribute dir is no directory
|
||||||
fprintf(stderr, "ensure_attribute_dir_exists(): Attribute "
|
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_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
|
// doesn't exist yet: create it
|
||||||
if (mkdir(attrDirPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) < 0)
|
if (mkdir(attrDirPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
return B_OK;
|
|
||||||
|
// mark the file
|
||||||
|
return set_attribute_dir_mark(path, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// open_attr_dir
|
// open_attr_dir
|
||||||
DIR *
|
DIR *
|
||||||
BPrivate::open_attr_dir(NodeRef ref)
|
BPrivate::open_attr_dir(NodeRef ref, const char *path, int fd)
|
||||||
{
|
{
|
||||||
// make sure the directory exists
|
// 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) {
|
if (error != B_OK) {
|
||||||
errno = error;
|
errno = error;
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -169,14 +281,14 @@ BPrivate::open_attr_dir(NodeRef ref)
|
|||||||
|
|
||||||
// get_attribute_path
|
// get_attribute_path
|
||||||
status_t
|
status_t
|
||||||
BPrivate::get_attribute_path(NodeRef ref, const char *attribute,
|
BPrivate::get_attribute_path(NodeRef ref, const char *path, int fd,
|
||||||
string &attrPath, string &typePath)
|
const char *attribute, string &attrPath, string &typePath)
|
||||||
{
|
{
|
||||||
if (!attribute || strlen(attribute) == 0)
|
if (!attribute || strlen(attribute) == 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
// make sure the attribute dir for the node exits
|
// 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) {
|
if (error != B_OK) {
|
||||||
errno = error;
|
errno = error;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -202,7 +314,7 @@ get_attribute_path(int fd, const char *attribute, string &attrPath,
|
|||||||
return errno;
|
return errno;
|
||||||
NodeRef ref(st);
|
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
|
// fs_open_attr_dir
|
||||||
@@ -213,7 +325,7 @@ fs_open_attr_dir(const char *path)
|
|||||||
if (lstat(path, &st))
|
if (lstat(path, &st))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return open_attr_dir(NodeRef(st));
|
return open_attr_dir(NodeRef(st), path, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fs_fopen_attr_dir
|
// fs_fopen_attr_dir
|
||||||
@@ -227,6 +339,8 @@ fs_fopen_attr_dir(int fd)
|
|||||||
if (fstat(fd, &st) < 0)
|
if (fstat(fd, &st) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
return open_attr_dir(NodeRef(st), NULL, fd);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
status_t error = _kern_read_stat(fd, NULL, false, &st,
|
status_t error = _kern_read_stat(fd, NULL, false, &st,
|
||||||
@@ -236,9 +350,16 @@ fs_fopen_attr_dir(int fd)
|
|||||||
return NULL;
|
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
|
// fs_close_attr_dir
|
||||||
|
|||||||
@@ -9,10 +9,19 @@
|
|||||||
|
|
||||||
namespace BPrivate {
|
namespace BPrivate {
|
||||||
|
|
||||||
DIR *open_attr_dir(NodeRef ref);
|
// defined in fs_attr.cpp
|
||||||
|
|
||||||
status_t get_attribute_path(NodeRef ref, const char *attribute,
|
// Note: Only one of path or fd can be supplied.
|
||||||
std::string &attrPath, std::string &typePath);
|
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
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user