libroot_build: Full passthrough to system attributes.

As it turns out, using the xattr emulation layer plus "libgnu"
causes some strange mixups at package build time, and so packages
built with it were winding up with no attributes at all.

So I've just bitten the bullet and written a full passthrough layer
to the system attributes. Verified using a full build of haiku.hpkg
this time ... after a lot of painful debugging of symlink mixups.

Hopefully I am finally rid of this plague...
This commit is contained in:
Augustin Cavalier 2017-12-30 14:15:29 -05:00
parent 7d93e79a04
commit 03544bf000
6 changed files with 382 additions and 60 deletions

View File

@ -23,6 +23,7 @@ extern "C" {
/* Since libroot_build is also used on Haiku and linked against the real
* libroot which also has the fs*attr functions, these must be shadowed. */
#ifndef BUILDING_FS_ATTR_HAIKU
#define fs_read_attr build_fs_read_attr
#define fs_write_attr build_fs_write_attr
#define fs_remove_attr build_fs_remove_attr
@ -35,6 +36,7 @@ extern "C" {
#define fs_close_attr_dir build_fs_close_attr_dir
#define fs_read_attr_dir build_fs_read_attr_dir
#define fs_rewind_attr_dir build_fs_rewind_attr_dir
#endif
extern ssize_t fs_read_attr(int fd, const char *attribute, uint32 type,

View File

@ -78,15 +78,10 @@ local librootSources =
USES_BE_API on [ FGristFiles $(librootSources:S=$(SUFOBJ)) ] = true ;
local extraLibs ;
if $(HOST_PLATFORM) = haiku_host {
extraLibs = gnu ;
}
BuildPlatformSharedLibrary libroot_build.so :
$(librootSources)
:
$(HOST_LIBSUPC++) $(HOST_LIBSTDC++) $(extraLibs)
$(HOST_LIBSUPC++) $(HOST_LIBSTDC++)
;
# TODO: This doesn't work with the function remapping.

View File

@ -0,0 +1,59 @@
/*
* Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
// no header guards: must be included at appropriate part of .cpp
class LocalFD {
public:
LocalFD()
{
}
~LocalFD()
{
}
status_t Init(int fd)
{
#ifndef BUILDING_FS_SHELL
Descriptor* descriptor = get_descriptor(fd);
if (descriptor && !descriptor->IsSystemFD()) {
// we need to get a path
fFD = -1;
return descriptor->GetPath(fPath);
}
#endif
fFD = fd;
fPath = "";
return B_OK;
}
int FD() const
{
return fFD;
}
const char* Path() const
{
return (fFD < 0 ? fPath.c_str() : NULL);
}
bool IsSymlink() const
{
struct stat st;
int result;
if (Path())
result = lstat(Path(), &st);
else
result = fstat(fFD, &st);
return (result == 0 && S_ISLNK(st.st_mode));
}
private:
string fPath;
int fFD;
};

View File

@ -1,5 +1,9 @@
#ifdef HAIKU_HOST_USE_XATTR
# include "fs_attr_untyped.cpp"
# ifdef HAIKU_HOST_PLATFORM_HAIKU
# include "fs_attr_haiku.cpp"
# else
# include "fs_attr_untyped.cpp"
# endif
#else
# include "fs_attr_generic.cpp"
#endif

View File

@ -0,0 +1,313 @@
/*
* Copyright 2017, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*! Shim over the host Haiku fs_attr API */
#define BUILDING_FS_ATTR_HAIKU
// so build fs_attr.h will not shadow the fs*attr functions
#ifdef BUILDING_FS_SHELL
# include "compat.h"
# define B_OK 0
# define B_BAD_VALUE EINVAL
# define B_FILE_ERROR EBADF
# define B_ERROR EINVAL
# define B_ENTRY_NOT_FOUND ENOENT
# define B_NO_MEMORY ENOMEM
#else
# include <syscalls.h>
# include "fs_impl.h"
# include "fs_descriptors.h"
#endif
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <map>
#include <string>
#include <fs_attr.h>
namespace BPrivate {}
using namespace BPrivate;
namespace {
// LocalFD
#include "LocalFD.h"
} // unnamed namspace
// # pragma mark - Public API
// fs_open_attr_dir
extern "C" DIR *
build_fs_open_attr_dir(const char *path)
{
return fs_open_attr_dir(path);
}
// fs_fopen_attr_dir
extern "C" DIR* fs_lopen_attr_dir(const char *path);
extern "C" DIR*
build_fs_fopen_attr_dir(int fd)
{
LocalFD localFD;
status_t error = localFD.Init(fd);
if (error != B_OK) {
errno = error;
return NULL;
}
if (localFD.FD() < 0) {
return fs_lopen_attr_dir(localFD.Path());
} else {
return fs_fopen_attr_dir(localFD.FD());
}
}
// fs_close_attr_dir
extern "C" int
build_fs_close_attr_dir(DIR *dir)
{
return fs_close_attr_dir(dir);
}
// fs_read_attr_dir
extern "C" struct dirent *
build_fs_read_attr_dir(DIR *dir)
{
return fs_read_attr_dir(dir);
}
// fs_rewind_attr_dir
extern "C" void
build_fs_rewind_attr_dir(DIR *dir)
{
return fs_rewind_attr_dir(dir);
}
// fs_fopen_attr
extern "C" int
build_fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode)
{
if (fd < 0) {
errno = B_BAD_VALUE;
return -1;
}
LocalFD localFD;
status_t error = localFD.Init(fd);
if (error != B_OK) {
errno = error;
return -1;
}
if (localFD.FD() < 0) {
return fs_open_attr(localFD.Path(), attribute, type,
openMode | O_NOTRAVERSE);
} else {
return fs_fopen_attr(localFD.FD(), attribute, type, openMode);
}
}
// fs_close_attr
extern "C" int
build_fs_close_attr(int fd)
{
return fs_close_attr(fd);
}
// fs_read_attr
extern "C" ssize_t
build_fs_read_attr(int fd, const char* attribute, uint32 type, off_t pos,
void *buffer, size_t readBytes)
{
LocalFD localFD;
status_t error = localFD.Init(fd);
if (error != B_OK) {
errno = error;
return -1;
}
ssize_t bytesRead;
if (localFD.FD() < 0) {
int fd = open(localFD.Path(), O_RDONLY | O_NOTRAVERSE);
bytesRead = fs_read_attr(fd, attribute, type,
pos, buffer, readBytes);
close(fd);
} else {
bytesRead = fs_read_attr(localFD.FD(), attribute, type,
pos, buffer, readBytes);
}
if (bytesRead < 0) {
// Make sure, the error code is B_ENTRY_NOT_FOUND, if the attribute
// doesn't exist.
if (errno == ENOATTR || errno == ENODATA)
errno = B_ENTRY_NOT_FOUND;
return -1;
}
return bytesRead;
}
// fs_write_attr
extern "C" ssize_t
build_fs_write_attr(int fd, const char* attribute, uint32 type, off_t pos,
const void *buffer, size_t writeBytes)
{
LocalFD localFD;
status_t error = localFD.Init(fd);
if (error != B_OK) {
errno = error;
return -1;
}
ssize_t written;
if (localFD.FD() < 0) {
int fd = open(localFD.Path(), O_NOTRAVERSE | O_WRONLY);
written = fs_write_attr(fd, attribute, type,
pos, buffer, writeBytes);
close(fd);
} else {
written = fs_write_attr(localFD.FD(), attribute, type,
pos, buffer, writeBytes);
}
return written;
}
// fs_remove_attr
extern "C" int
build_fs_remove_attr(int fd, const char* attribute)
{
LocalFD localFD;
status_t error = localFD.Init(fd);
if (error != B_OK) {
errno = error;
return -1;
}
// remove attribute
int result;
if (localFD.FD() < 0) {
int fd = open(localFD.Path(), O_NOTRAVERSE | O_WRONLY);
result = fs_remove_attr(fd, attribute);
close(fd);
} else {
result = fs_remove_attr(localFD.FD(), attribute);
}
if (result < 0) {
// Make sure, the error code is B_ENTRY_NOT_FOUND, if the attribute
// doesn't exist.
if (errno == ENOATTR || errno == ENODATA)
errno = B_ENTRY_NOT_FOUND;
return -1;
}
return 0;
}
// fs_stat_attr
extern "C" int
build_fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo)
{
if (!attribute || !attrInfo) {
errno = B_BAD_VALUE;
return -1;
}
LocalFD localFD;
status_t error = localFD.Init(fd);
if (error != B_OK) {
errno = error;
return -1;
}
int result;
if (localFD.FD() < 0) {
int fd = open(localFD.Path(), O_NOTRAVERSE | O_RDONLY);
result = fs_stat_attr(fd, attribute, attrInfo);
close(fd);
} else {
result = fs_stat_attr(localFD.FD(), attribute, attrInfo);
}
return result;
}
// #pragma mark - Private Syscalls
#ifndef BUILDING_FS_SHELL
// _kern_open_attr_dir
int
_kern_open_attr_dir(int fd, const char *path)
{
// get node ref for the node
struct stat st;
status_t error = _kern_read_stat(fd, path, false, &st,
sizeof(struct stat));
if (error != B_OK) {
errno = error;
return -1;
}
NodeRef ref(st);
DIR* dir;
if (path) {
// If a path was given, get a usable path.
string realPath;
status_t error = get_path(fd, path, realPath);
if (error != B_OK)
return error;
dir = build_fs_open_attr_dir(realPath.c_str());
} else
dir = build_fs_fopen_attr_dir(fd);
if (!dir)
return errno;
// create descriptor
AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref);
return add_descriptor(descriptor);
}
// _kern_rename_attr
status_t
_kern_rename_attr(int fromFile, const char *fromName, int toFile,
const char *toName)
{
// not supported ATM
return B_BAD_VALUE;
}
// _kern_remove_attr
status_t
_kern_remove_attr(int fd, const char *name)
{
if (!name)
return B_BAD_VALUE;
if (build_fs_remove_attr(fd, name) < 0)
return errno;
return B_OK;
}
#endif // ! BUILDING_FS_SHELL

View File

@ -39,7 +39,7 @@
// Include the interface to the host platform attributes support.
#if defined(HAIKU_HOST_PLATFORM_LINUX) || defined(HAIKU_HOST_PLATFORM_HAIKU)
#if defined(HAIKU_HOST_PLATFORM_LINUX)
# include "fs_attr_xattr.h"
#elif defined(HAIKU_HOST_PLATFORM_FREEBSD)
# include "fs_attr_extattr.h"
@ -315,58 +315,7 @@ private:
};
// LocalFD
class LocalFD {
public:
LocalFD()
{
}
~LocalFD()
{
}
status_t Init(int fd)
{
#ifndef BUILDING_FS_SHELL
Descriptor* descriptor = get_descriptor(fd);
if (descriptor && !descriptor->IsSystemFD()) {
// we need to get a path
fFD = -1;
return descriptor->GetPath(fPath);
}
#endif
fFD = fd;
fPath = "";
return B_OK;
}
int FD() const
{
return fFD;
}
const char* Path() const
{
return (fFD < 0 ? fPath.c_str() : NULL);
}
bool IsSymlink() const
{
struct stat st;
int result;
if (Path())
result = lstat(Path(), &st);
else
result = fstat(fFD, &st);
return (result == 0 && S_ISLNK(st.st_mode));
}
private:
string fPath;
int fFD;
};
#include "LocalFD.h"
} // unnamed namspace