* Copyright 2017, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#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 {
#include "LocalFD.h"
}
extern "C" DIR *
_haiku_build_fs_open_attr_dir(const char *path)
{
return fs_open_attr_dir(path);
}
extern "C" DIR*
_haiku_build_fs_lopen_attr_dir(const char *path)
{
return fs_lopen_attr_dir(path);
}
extern "C" DIR*
_haiku_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());
}
}
extern "C" int
_haiku_build_fs_close_attr_dir(DIR *dir)
{
return fs_close_attr_dir(dir);
}
extern "C" struct dirent *
_haiku_build_fs_read_attr_dir(DIR *dir)
{
return fs_read_attr_dir(dir);
}
extern "C" void
_haiku_build_fs_rewind_attr_dir(DIR *dir)
{
return fs_rewind_attr_dir(dir);
}
extern "C" int
_haiku_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);
}
}
extern "C" int
_haiku_build_fs_close_attr(int fd)
{
return fs_close_attr(fd);
}
extern "C" ssize_t
_haiku_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) {
if (errno == ENOATTR || errno == ENODATA)
errno = B_ENTRY_NOT_FOUND;
return -1;
}
return bytesRead;
}
extern "C" ssize_t
_haiku_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;
}
extern "C" int
_haiku_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;
}
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) {
if (errno == ENOATTR || errno == ENODATA)
errno = B_ENTRY_NOT_FOUND;
return -1;
}
return 0;
}
extern "C" int
_haiku_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;
}
#ifndef BUILDING_FS_SHELL
int
_kern_open_attr_dir(int fd, const char *path)
{
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) {
string realPath;
status_t error = get_path(fd, path, realPath);
if (error != B_OK)
return error;
dir = _haiku_build_fs_open_attr_dir(realPath.c_str());
} else
dir = _haiku_build_fs_fopen_attr_dir(fd);
if (!dir)
return errno;
AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref);
return add_descriptor(descriptor);
}
status_t
_kern_rename_attr(int fromFile, const char *fromName, int toFile,
const char *toName)
{
return B_BAD_VALUE;
}
status_t
_kern_remove_attr(int fd, const char *name)
{
if (!name)
return B_BAD_VALUE;
if (_haiku_build_fs_remove_attr(fd, name) < 0)
return errno;
return B_OK;
}
#endif