1b360cc7fSIngo Weinhold/*
2b360cc7fSIngo Weinhold * Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3b360cc7fSIngo Weinhold * Distributed under the terms of the MIT License.
4b360cc7fSIngo Weinhold */
5b360cc7fSIngo Weinhold
6b360cc7fSIngo Weinhold/*!	Emulation BeOS-style attributes by mapping them to untyped attributes of
7b360cc7fSIngo Weinhold	the host platform (xattr on Linux, extattr on FreeBSD).
8b360cc7fSIngo Weinhold*/
9b360cc7fSIngo Weinhold
104f4e5272SIngo Weinhold
114f4e5272SIngo Weinhold#ifdef BUILDING_FS_SHELL
124f4e5272SIngo Weinhold#	include "compat.h"
134f4e5272SIngo Weinhold#	define B_OK					0
144f4e5272SIngo Weinhold#	define B_BAD_VALUE			EINVAL
154f4e5272SIngo Weinhold#	define B_FILE_ERROR			EBADF
164f4e5272SIngo Weinhold#	define B_ERROR				EINVAL
174f4e5272SIngo Weinhold#	define B_ENTRY_NOT_FOUND	ENOENT
184f4e5272SIngo Weinhold#	define B_NO_MEMORY			ENOMEM
194f4e5272SIngo Weinhold#else
204f4e5272SIngo Weinhold#	include <BeOSBuildCompatibility.h>
214f4e5272SIngo Weinhold#	include <syscalls.h>
224f4e5272SIngo Weinhold
234f4e5272SIngo Weinhold#	include "fs_impl.h"
244f4e5272SIngo Weinhold#	include "fs_descriptors.h"
254f4e5272SIngo Weinhold#endif
264f4e5272SIngo Weinhold
274f4e5272SIngo Weinhold#include <dirent.h>
284f4e5272SIngo Weinhold#include <errno.h>
294f4e5272SIngo Weinhold#include <fcntl.h>
304f4e5272SIngo Weinhold#include <stdio.h>
314f4e5272SIngo Weinhold#include <stdlib.h>
324f4e5272SIngo Weinhold#include <unistd.h>
334f4e5272SIngo Weinhold#include <sys/stat.h>
344f4e5272SIngo Weinhold
354f4e5272SIngo Weinhold#include <map>
364f4e5272SIngo Weinhold#include <string>
374f4e5272SIngo Weinhold
384f4e5272SIngo Weinhold#include <fs_attr.h>
394f4e5272SIngo Weinhold
40b360cc7fSIngo Weinhold
41b360cc7fSIngo Weinhold// Include the interface to the host platform attributes support.
4203544bf0SAugustin Cavalier#if defined(HAIKU_HOST_PLATFORM_LINUX)
43b360cc7fSIngo Weinhold#	include "fs_attr_xattr.h"
44b360cc7fSIngo Weinhold#elif defined(HAIKU_HOST_PLATFORM_FREEBSD)
45b360cc7fSIngo Weinhold#	include "fs_attr_extattr.h"
46b1c06fc6SIngo Weinhold#elif defined(HAIKU_HOST_PLATFORM_DARWIN)
47b1c06fc6SIngo Weinhold#	include "fs_attr_bsdxattr.h"
48b360cc7fSIngo Weinhold#else
49b360cc7fSIngo Weinhold#	error No attribute support for this host platform!
50b360cc7fSIngo Weinhold#endif
51b360cc7fSIngo Weinhold
52b360cc7fSIngo Weinhold
534f4e5272SIngo Weinholdnamespace BPrivate {}
544f4e5272SIngo Weinholdusing namespace BPrivate;
554f4e5272SIngo Weinholdusing std::map;
564f4e5272SIngo Weinholdusing std::string;
574f4e5272SIngo Weinhold
584f4e5272SIngo Weinhold// the maximum length of an attribute listing we support
59452edf50SIngo Weinholdstatic const size_t kMaxAttributeListingLength = 10240;
604f4e5272SIngo Weinhold
614f4e5272SIngo Weinhold// the maximum attribute length we support
62452edf50SIngo Weinholdstatic const size_t kMaxAttributeLength = 10240 * 4;
634f4e5272SIngo Weinhold
644f4e5272SIngo Weinhold
65011e7a3dSIngo Weinhold// mangle_attribute_name
66011e7a3dSIngo Weinholdstatic string
67011e7a3dSIngo Weinholdmangle_attribute_name(const char* name)
68011e7a3dSIngo Weinhold{
69011e7a3dSIngo Weinhold	// prepend our xattr namespace and translate:
70011e7a3dSIngo Weinhold	// '/' -> "%\"
71011e7a3dSIngo Weinhold	// '%' -> "%%"
72011e7a3dSIngo Weinhold
73011e7a3dSIngo Weinhold	string mangledName = kAttributeNamespace;
74011e7a3dSIngo Weinhold	for (int i = 0; name[i] != '\0'; i++) {
75011e7a3dSIngo Weinhold		char c = name[i];
76011e7a3dSIngo Weinhold		switch (c) {
77011e7a3dSIngo Weinhold			case '/':
78011e7a3dSIngo Weinhold				mangledName += "%\\";
79011e7a3dSIngo Weinhold				break;
80011e7a3dSIngo Weinhold			case '%':
81011e7a3dSIngo Weinhold				mangledName += "%%";
82011e7a3dSIngo Weinhold				break;
83011e7a3dSIngo Weinhold			default:
84011e7a3dSIngo Weinhold				mangledName += c;
85011e7a3dSIngo Weinhold				break;
86011e7a3dSIngo Weinhold		}
87011e7a3dSIngo Weinhold	}
88011e7a3dSIngo Weinhold	return mangledName;
89011e7a3dSIngo Weinhold}
90011e7a3dSIngo Weinhold
91011e7a3dSIngo Weinhold
92011e7a3dSIngo Weinhold// demangle_attribute_name
93011e7a3dSIngo Weinholdstatic bool
94011e7a3dSIngo Weinholddemangle_attribute_name(const char* name, string& demangledName)
95011e7a3dSIngo Weinhold{
96011e7a3dSIngo Weinhold	// chop of our xattr namespace and translate:
97011e7a3dSIngo Weinhold	// "%\" -> '/'
98011e7a3dSIngo Weinhold	// "%%" -> '%'
99011e7a3dSIngo Weinhold
100011e7a3dSIngo Weinhold	if (strncmp(name, kAttributeNamespace, kAttributeNamespaceLen) != 0)
101011e7a3dSIngo Weinhold		return false;
102011e7a3dSIngo Weinhold
103011e7a3dSIngo Weinhold	name += kAttributeNamespaceLen;
104011e7a3dSIngo Weinhold
105011e7a3dSIngo Weinhold	demangledName = "";
106011e7a3dSIngo Weinhold
107011e7a3dSIngo Weinhold	for (int i = 0; name[i] != '\0'; i++) {
108011e7a3dSIngo Weinhold		char c = name[i];
109011e7a3dSIngo Weinhold		if (c == '%') {
110011e7a3dSIngo Weinhold			c = name[++i];
111011e7a3dSIngo Weinhold			if (c == '%')
112011e7a3dSIngo Weinhold				demangledName += c;
113011e7a3dSIngo Weinhold			else if (c == '\\')
114011e7a3dSIngo Weinhold				demangledName += '/';
115011e7a3dSIngo Weinhold			else
116011e7a3dSIngo Weinhold				return false;
117011e7a3dSIngo Weinhold		} else
118011e7a3dSIngo Weinhold			demangledName += c;
119011e7a3dSIngo Weinhold	}
120011e7a3dSIngo Weinhold
121011e7a3dSIngo Weinhold	return true;
122011e7a3dSIngo Weinhold}
123011e7a3dSIngo Weinhold
1244f4e5272SIngo Weinhold
1254f4e5272SIngo Weinholdnamespace {
1264f4e5272SIngo Weinhold
1274f4e5272SIngo Weinholdclass AttributeDirectory;
1284f4e5272SIngo Weinhold
1294f4e5272SIngo Weinholdtypedef map<DIR*, AttributeDirectory*> AttrDirMap;
1304f4e5272SIngo Weinholdstatic AttrDirMap sAttributeDirectories;
1314f4e5272SIngo Weinhold
1324f4e5272SIngo Weinhold// LongDirent
1334f4e5272SIngo Weinholdstruct LongDirent : dirent {
1344f4e5272SIngo Weinhold	char name[B_FILE_NAME_LENGTH];
1354f4e5272SIngo Weinhold};
1364f4e5272SIngo Weinhold
1374f4e5272SIngo Weinhold// AttributeHeader
1384f4e5272SIngo Weinholdstruct AttributeHeader {
1394f4e5272SIngo Weinhold	uint32	type;
1404f4e5272SIngo Weinhold};
1414f4e5272SIngo Weinhold
1424f4e5272SIngo Weinhold// AttributeDirectory
1434f4e5272SIngo Weinholdclass AttributeDirectory {
1444f4e5272SIngo Weinholdpublic:
1454f4e5272SIngo Weinhold	AttributeDirectory()
1464f4e5272SIngo Weinhold		: fFileFD(-1),
1474f4e5272SIngo Weinhold		  fFakeDir(NULL),
1484f4e5272SIngo Weinhold		  fListing(NULL),
1494f4e5272SIngo Weinhold		  fListingLength(-1),
1504f4e5272SIngo Weinhold		  fListingIndex(0)
1514f4e5272SIngo Weinhold	{
1524f4e5272SIngo Weinhold	}
1534f4e5272SIngo Weinhold
1544f4e5272SIngo Weinhold	~AttributeDirectory()
1554f4e5272SIngo Weinhold	{
1564f4e5272SIngo Weinhold		if (fFileFD >= 0)
1574f4e5272SIngo Weinhold			close(fFileFD);
1584f4e5272SIngo Weinhold
1594f4e5272SIngo Weinhold		if (fFakeDir) {
1604f4e5272SIngo Weinhold			AttrDirMap::iterator it = sAttributeDirectories.find(fFakeDir);
1614f4e5272SIngo Weinhold			if (it != sAttributeDirectories.end())
1624f4e5272SIngo Weinhold				sAttributeDirectories.erase(it);
1634f4e5272SIngo Weinhold
1644f4e5272SIngo Weinhold			closedir(fFakeDir);
1654f4e5272SIngo Weinhold		}
1664f4e5272SIngo Weinhold
1674f4e5272SIngo Weinhold		free(fListing);
1684f4e5272SIngo Weinhold	}
1694f4e5272SIngo Weinhold
1704f4e5272SIngo Weinhold	static AttributeDirectory* Get(DIR* dir)
1714f4e5272SIngo Weinhold	{
1724f4e5272SIngo Weinhold		AttrDirMap::iterator it = sAttributeDirectories.find(dir);
1734f4e5272SIngo Weinhold		if (it == sAttributeDirectories.end())
1744f4e5272SIngo Weinhold			return NULL;
1754f4e5272SIngo Weinhold		return it->second;
1764f4e5272SIngo Weinhold	}
1774f4e5272SIngo Weinhold
1784f4e5272SIngo Weinhold	status_t Init(const char* path, int fileFD)
1794f4e5272SIngo Weinhold	{
1804f4e5272SIngo Weinhold		// open a fake DIR
1814f4e5272SIngo Weinhold		if (!fFakeDir) {
1824f4e5272SIngo Weinhold			fFakeDir = opendir(".");
1834f4e5272SIngo Weinhold			if (!fFakeDir)
1844f4e5272SIngo Weinhold				return B_ERROR;
1854f4e5272SIngo Weinhold
1864f4e5272SIngo Weinhold			sAttributeDirectories[fFakeDir] = this;
1874f4e5272SIngo Weinhold		}
1884f4e5272SIngo Weinhold
1894291baf0SIngo Weinhold		string tempPath;
1904291baf0SIngo Weinhold		if (!path) {
1914291baf0SIngo Weinhold			// We've got no path. If the file descriptor is one of our own and
1924291baf0SIngo Weinhold			// not a system FD, we need to get a path for it.
1934291baf0SIngo Weinhold			Descriptor*	descriptor = get_descriptor(fileFD);
1944291baf0SIngo Weinhold			if (descriptor && !descriptor->IsSystemFD()) {
195540d4f7bSIngo Weinhold				status_t error = descriptor->GetPath(tempPath);
196540d4f7bSIngo Weinhold				if (error != B_OK)
197540d4f7bSIngo Weinhold					return error;
198540d4f7bSIngo Weinhold				path = tempPath.c_str();
199540d4f7bSIngo Weinhold				fileFD = -1;
2004291baf0SIngo Weinhold			}
2014291baf0SIngo Weinhold		}
2024291baf0SIngo Weinhold
2034f4e5272SIngo Weinhold		if (path) {
2044f4e5272SIngo Weinhold			// A path was given -- check, if it's a symlink. If so we need to
2054f4e5272SIngo Weinhold			// keep the path, otherwise we open a FD.
2064f4e5272SIngo Weinhold			struct stat st;
2074f4e5272SIngo Weinhold			if (lstat(path, &st))
2084f4e5272SIngo Weinhold				return B_ENTRY_NOT_FOUND;
2094f4e5272SIngo Weinhold
2104f4e5272SIngo Weinhold			if (S_ISLNK(st.st_mode)) {
2114f4e5272SIngo Weinhold				fFileFD = -1;
2124f4e5272SIngo Weinhold				fPath = path;
2134f4e5272SIngo Weinhold			} else {
2144f4e5272SIngo Weinhold				fFileFD = open(path, O_RDONLY);
2154f4e5272SIngo Weinhold				if (fFileFD < 0)
2164f4e5272SIngo Weinhold					return errno;
2174f4e5272SIngo Weinhold				fPath = "";
2184f4e5272SIngo Weinhold			}
2194f4e5272SIngo Weinhold		} else {
2204f4e5272SIngo Weinhold			// FD was given -- dup it.
2214f4e5272SIngo Weinhold			fFileFD = dup(fileFD);
2224f4e5272SIngo Weinhold			if (fFileFD < 0)
2234f4e5272SIngo Weinhold				return errno;
2244f4e5272SIngo Weinhold			fPath = "";
2254f4e5272SIngo Weinhold		}
2264f4e5272SIngo Weinhold
2274f4e5272SIngo Weinhold		fListingLength = -1;
2284f4e5272SIngo Weinhold		fListingIndex = 0;
2294f4e5272SIngo Weinhold
2304f4e5272SIngo Weinhold		return B_OK;
2314f4e5272SIngo Weinhold	}
2324f4e5272SIngo Weinhold
2334f4e5272SIngo Weinhold	DIR* FakeDir() const	{ return fFakeDir; }
2344f4e5272SIngo Weinhold
2354f4e5272SIngo Weinhold	status_t ReadDir(struct dirent** _entry)
2364f4e5272SIngo Weinhold	{
2374f4e5272SIngo Weinhold		// make sure we have a current listing
2384f4e5272SIngo Weinhold		status_t error = _CheckListing();
2394f4e5272SIngo Weinhold		if (error != B_OK)
2404f4e5272SIngo Weinhold			return error;
2414f4e5272SIngo Weinhold
2424f4e5272SIngo Weinhold		// keep going until we find an entry or hit the end of dir
2434f4e5272SIngo Weinhold		while (fListingIndex < fListingLength) {
2444f4e5272SIngo Weinhold			// get next entry name
2454f4e5272SIngo Weinhold			const char* name = fListing + fListingIndex;
2464f4e5272SIngo Weinhold			int nameLen = strlen(name);
2474f4e5272SIngo Weinhold			fListingIndex += nameLen + 1;
2484f4e5272SIngo Weinhold
2494f4e5272SIngo Weinhold			// check the attribute namespace
250011e7a3dSIngo Weinhold			string demangledName;
251011e7a3dSIngo Weinhold			if (!demangle_attribute_name(name, demangledName))
2524f4e5272SIngo Weinhold				continue;
253011e7a3dSIngo Weinhold			name = demangledName.c_str();
254011e7a3dSIngo Weinhold			nameLen = demangledName.length();
2554f4e5272SIngo Weinhold
2564f4e5272SIngo Weinhold			if (nameLen == 0) {
2574f4e5272SIngo Weinhold				// Uh, weird attribute.
2584f4e5272SIngo Weinhold				return B_ERROR;
2594f4e5272SIngo Weinhold			}
2604f4e5272SIngo Weinhold
2614f4e5272SIngo Weinhold			// prepare the dirent
2624f4e5272SIngo Weinhold			strcpy(fDirent.d_name, name);
2634f4e5272SIngo Weinhold			fDirent.d_ino = 0;
2644f4e5272SIngo Weinhold// TODO: We need the node ID!
2654f4e5272SIngo Weinhold
2664f4e5272SIngo Weinhold			*_entry = &fDirent;
2674f4e5272SIngo Weinhold			return B_OK;
2684f4e5272SIngo Weinhold		}
2694f4e5272SIngo Weinhold
2704f4e5272SIngo Weinhold		// end of dir
2714f4e5272SIngo Weinhold		*_entry = NULL;
2724f4e5272SIngo Weinhold		return B_OK;
2734f4e5272SIngo Weinhold	}
2744f4e5272SIngo Weinhold
2754f4e5272SIngo Weinhold	void RewindDir()
2764f4e5272SIngo Weinhold	{
2774f4e5272SIngo Weinhold		fListingIndex = 0;
2784f4e5272SIngo Weinhold	}
2794f4e5272SIngo Weinhold
2804f4e5272SIngo Weinholdprivate:
2814f4e5272SIngo Weinhold	status_t _CheckListing()
2824f4e5272SIngo Weinhold	{
2834f4e5272SIngo Weinhold		if (fListing && fListingLength >= 0)
2844f4e5272SIngo Weinhold			return B_OK;
2854f4e5272SIngo Weinhold
2864f4e5272SIngo Weinhold		char listing[kMaxAttributeListingLength];
2874f4e5272SIngo Weinhold
2884f4e5272SIngo Weinhold		// get the listing
289b360cc7fSIngo Weinhold		ssize_t length = list_attributes(fFileFD, fPath.c_str(), listing,
290b360cc7fSIngo Weinhold			kMaxAttributeListingLength);
2914f4e5272SIngo Weinhold		if (length < 0)
2924f4e5272SIngo Weinhold			return errno;
2934f4e5272SIngo Weinhold
2944f4e5272SIngo Weinhold		// clone the on-stack listing
2954f4e5272SIngo Weinhold		char* newListing = (char*)realloc(fListing, length);
2964f4e5272SIngo Weinhold		if (!newListing)
2974f4e5272SIngo Weinhold			return B_NO_MEMORY;
2984f4e5272SIngo Weinhold		memcpy(newListing, listing, length);
2994f4e5272SIngo Weinhold
3004f4e5272SIngo Weinhold		fListing = newListing;
3014f4e5272SIngo Weinhold		fListingLength = length;
3024f4e5272SIngo Weinhold		fListingIndex = 0;
3034f4e5272SIngo Weinhold
3044f4e5272SIngo Weinhold		return B_OK;
3054f4e5272SIngo Weinhold	}
3064f4e5272SIngo Weinhold
3074f4e5272SIngo Weinholdprivate:
3084f4e5272SIngo Weinhold	int			fFileFD;
3094f4e5272SIngo Weinhold	string		fPath;
3104f4e5272SIngo Weinhold	DIR*		fFakeDir;
3114f4e5272SIngo Weinhold	LongDirent	fDirent;
3124f4e5272SIngo Weinhold	char*		fListing;
3134f4e5272SIngo Weinhold	int			fListingLength;
3144f4e5272SIngo Weinhold	int			fListingIndex;
3154f4e5272SIngo Weinhold};
3164f4e5272SIngo Weinhold
3174f4e5272SIngo Weinhold// LocalFD
31803544bf0SAugustin Cavalier#include "LocalFD.h"
3194f4e5272SIngo Weinhold
3204f4e5272SIngo Weinhold}	// unnamed namspace
3214f4e5272SIngo Weinhold
3224f4e5272SIngo Weinhold
3234f4e5272SIngo Weinhold// # pragma mark - Public API
3244f4e5272SIngo Weinhold
3254f4e5272SIngo Weinhold
3264f4e5272SIngo Weinhold// fs_open_attr_dir
3274f4e5272SIngo WeinholdDIR *
3284f4e5272SIngo Weinholdfs_open_attr_dir(const char *path)
3294f4e5272SIngo Weinhold{
3304f4e5272SIngo Weinhold	AttributeDirectory* attrDir = new AttributeDirectory;
3314f4e5272SIngo Weinhold
3324f4e5272SIngo Weinhold	status_t error = attrDir->Init(path, -1);
3334f4e5272SIngo Weinhold	if (error != B_OK) {
3344f4e5272SIngo Weinhold		errno = error;
3354f4e5272SIngo Weinhold		delete attrDir;
3364f4e5272SIngo Weinhold		return NULL;
3374f4e5272SIngo Weinhold	}
3384f4e5272SIngo Weinhold
3394f4e5272SIngo Weinhold	return attrDir->FakeDir();
3404f4e5272SIngo Weinhold}
3414f4e5272SIngo Weinhold
3424f4e5272SIngo Weinhold// fs_fopen_attr_dir
3434f4e5272SIngo WeinholdDIR *
3444f4e5272SIngo Weinholdfs_fopen_attr_dir(int fd)
3454f4e5272SIngo Weinhold{
3464f4e5272SIngo Weinhold	AttributeDirectory* attrDir = new AttributeDirectory;
3474f4e5272SIngo Weinhold
3484f4e5272SIngo Weinhold	status_t error = attrDir->Init(NULL, fd);
3494f4e5272SIngo Weinhold	if (error != B_OK) {
3504f4e5272SIngo Weinhold		errno = error;
3514f4e5272SIngo Weinhold		delete attrDir;
3524f4e5272SIngo Weinhold		return NULL;
3534f4e5272SIngo Weinhold	}
3544f4e5272SIngo Weinhold
3554f4e5272SIngo Weinhold	return attrDir->FakeDir();
3564f4e5272SIngo Weinhold}
3574f4e5272SIngo Weinhold
3584f4e5272SIngo Weinhold// fs_close_attr_dir
3594f4e5272SIngo Weinholdint
3604f4e5272SIngo Weinholdfs_close_attr_dir(DIR *dir)
3614f4e5272SIngo Weinhold{
3624f4e5272SIngo Weinhold	AttributeDirectory* attrDir = AttributeDirectory::Get(dir);
3634f4e5272SIngo Weinhold	if (!attrDir) {
3644f4e5272SIngo Weinhold		errno = B_BAD_VALUE;
3654f4e5272SIngo Weinhold		return -1;
3664f4e5272SIngo Weinhold	}
3674f4e5272SIngo Weinhold
3684f4e5272SIngo Weinhold	delete attrDir;
3694f4e5272SIngo Weinhold	return 0;
3704f4e5272SIngo Weinhold}
3714f4e5272SIngo Weinhold
3724f4e5272SIngo Weinhold// fs_read_attr_dir
3734f4e5272SIngo Weinholdstruct dirent *
3744f4e5272SIngo Weinholdfs_read_attr_dir(DIR *dir)
3754f4e5272SIngo Weinhold{
3764f4e5272SIngo Weinhold	// get attr dir
3774f4e5272SIngo Weinhold	AttributeDirectory* attrDir = AttributeDirectory::Get(dir);
3784f4e5272SIngo Weinhold	if (!attrDir) {
3794f4e5272SIngo Weinhold		errno = B_BAD_VALUE;
3804f4e5272SIngo Weinhold		return NULL;
3814f4e5272SIngo Weinhold	}
3824f4e5272SIngo Weinhold
3834f4e5272SIngo Weinhold	// read attr dir
3844f4e5272SIngo Weinhold	dirent* entry = NULL;
3854f4e5272SIngo Weinhold	status_t error = attrDir->ReadDir(&entry);
3864f4e5272SIngo Weinhold	if (error != B_OK) {
3874f4e5272SIngo Weinhold		errno = error;
3884f4e5272SIngo Weinhold		return NULL;
3894f4e5272SIngo Weinhold	}
3904f4e5272SIngo Weinhold
3914f4e5272SIngo Weinhold	return entry;
3924f4e5272SIngo Weinhold}
3934f4e5272SIngo Weinhold
3944f4e5272SIngo Weinhold// fs_rewind_attr_dir
3954f4e5272SIngo Weinholdvoid
3964f4e5272SIngo Weinholdfs_rewind_attr_dir(DIR *dir)
3974f4e5272SIngo Weinhold{
3984f4e5272SIngo Weinhold	// get attr dir
3994f4e5272SIngo Weinhold	AttributeDirectory* attrDir = AttributeDirectory::Get(dir);
4004f4e5272SIngo Weinhold	if (attrDir)
4014f4e5272SIngo Weinhold		attrDir->RewindDir();
4024f4e5272SIngo Weinhold}
4034f4e5272SIngo Weinhold
404e781b1b5SIngo Weinhold// fs_fopen_attr
4054f4e5272SIngo Weinholdint
406e781b1b5SIngo Weinholdfs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode)
4074f4e5272SIngo Weinhold{
408e781b1b5SIngo Weinhold	if (fd < 0) {
409e781b1b5SIngo Weinhold		errno = B_BAD_VALUE;
410e781b1b5SIngo Weinhold		return -1;
411e781b1b5SIngo Weinhold	}
412e781b1b5SIngo Weinhold
413e781b1b5SIngo Weinhold	AttributeDescriptor* descriptor = new(std::nothrow) AttributeDescriptor(fd,
414e781b1b5SIngo Weinhold		attribute, type, openMode);
415e781b1b5SIngo Weinhold	if (descriptor == NULL) {
416e781b1b5SIngo Weinhold		errno = B_NO_MEMORY;
417e781b1b5SIngo Weinhold		return -1;
418e781b1b5SIngo Weinhold	}
419e781b1b5SIngo Weinhold
420e781b1b5SIngo Weinhold	status_t error = descriptor->Init();
421e781b1b5SIngo Weinhold	if (error != B_OK) {
422e781b1b5SIngo Weinhold		delete descriptor;
423e781b1b5SIngo Weinhold		errno = error;
424e781b1b5SIngo Weinhold		return -1;
425e781b1b5SIngo Weinhold	}
426e781b1b5SIngo Weinhold
427e781b1b5SIngo Weinhold	int attributeFD = add_descriptor(descriptor);
428e781b1b5SIngo Weinhold	if (attributeFD < 0) {
429e781b1b5SIngo Weinhold		delete descriptor;
430e781b1b5SIngo Weinhold		errno = B_NO_MEMORY;
431e781b1b5SIngo Weinhold		return -1;
432e781b1b5SIngo Weinhold	}
433e781b1b5SIngo Weinhold
434e781b1b5SIngo Weinhold	return attributeFD;
4354f4e5272SIngo Weinhold}
4364f4e5272SIngo Weinhold
4374f4e5272SIngo Weinhold// fs_close_attr
4384f4e5272SIngo Weinholdint
4394f4e5272SIngo Weinholdfs_close_attr(int fd)
4404f4e5272SIngo Weinhold{
441e781b1b5SIngo Weinhold	status_t error = delete_descriptor(fd);
442e781b1b5SIngo Weinhold	if (error != 0) {
443e781b1b5SIngo Weinhold		errno = error;
444e781b1b5SIngo Weinhold		return -1;
445e781b1b5SIngo Weinhold	}
446e781b1b5SIngo Weinhold
447e781b1b5SIngo Weinhold	return 0;
4484f4e5272SIngo Weinhold}
4494f4e5272SIngo Weinhold
4504f4e5272SIngo Weinhold// fs_read_attr
4514f4e5272SIngo Weinholdssize_t
4524f4e5272SIngo Weinholdfs_read_attr(int fd, const char *_attribute, uint32 type, off_t pos,
4534f4e5272SIngo Weinhold	void *buffer, size_t readBytes)
4544f4e5272SIngo Weinhold{
4554f4e5272SIngo Weinhold	// check params
4564f4e5272SIngo Weinhold	if (pos < 0 || pos + readBytes > kMaxAttributeLength
4574f4e5272SIngo Weinhold		|| !_attribute || !buffer) {
4584f4e5272SIngo Weinhold		errno = B_BAD_VALUE;
4594f4e5272SIngo Weinhold		return -1;
4604f4e5272SIngo Weinhold	}
4614f4e5272SIngo Weinhold
4624f4e5272SIngo Weinhold	// resolve FD
4634f4e5272SIngo Weinhold	LocalFD localFD;
4644f4e5272SIngo Weinhold	status_t error = localFD.Init(fd);
4654f4e5272SIngo Weinhold	if (error != B_OK) {
4664f4e5272SIngo Weinhold		errno = error;
4674f4e5272SIngo Weinhold		return -1;
4684f4e5272SIngo Weinhold	}
4694f4e5272SIngo Weinhold
470011e7a3dSIngo Weinhold	// mangle the attribute name
471011e7a3dSIngo Weinhold	string attribute = mangle_attribute_name(_attribute);
4724f4e5272SIngo Weinhold
4734f4e5272SIngo Weinhold	// read the attribute
4744f4e5272SIngo Weinhold	char attributeBuffer[sizeof(AttributeHeader) + kMaxAttributeLength];
4755d3de03bSIngo Weinhold	ssize_t bytesRead = sizeof(attributeBuffer);
4764f4e5272SIngo Weinhold	if (localFD.Path()) {
477b360cc7fSIngo Weinhold		bytesRead = get_attribute(-1, localFD.Path(), attribute.c_str(),
4784f4e5272SIngo Weinhold			attributeBuffer, bytesRead);
4794f4e5272SIngo Weinhold	} else {
480b360cc7fSIngo Weinhold		bytesRead = get_attribute(localFD.FD(), NULL, attribute.c_str(),
481b360cc7fSIngo Weinhold			attributeBuffer, bytesRead);
4824f4e5272SIngo Weinhold	}
4834f4e5272SIngo Weinhold	if (bytesRead < 0) {
4844f4e5272SIngo Weinhold		// Make sure, the error code is B_ENTRY_NOT_FOUND, if the attribute
4854f4e5272SIngo Weinhold		// doesn't exist.
4864f4e5272SIngo Weinhold		if (errno == ENOATTR || errno == ENODATA)
4874f4e5272SIngo Weinhold			errno = B_ENTRY_NOT_FOUND;
4884f4e5272SIngo Weinhold		return -1;
4894f4e5272SIngo Weinhold	}
4904f4e5272SIngo Weinhold
4914f4e5272SIngo Weinhold	// check length for sanity
4924f4e5272SIngo Weinhold	if ((size_t)bytesRead < sizeof(AttributeHeader)) {
4934f4e5272SIngo Weinhold		fprintf(stderr, "fs_read_attr(): attribute \"%s\" is shorter than the "
4944f4e5272SIngo Weinhold			"AttributeHeader!\n", attribute.c_str());
4954f4e5272SIngo Weinhold		errno = B_ERROR;
4964f4e5272SIngo Weinhold		return -1;
4974f4e5272SIngo Weinhold	}
4984f4e5272SIngo Weinhold
4994f4e5272SIngo Weinhold	// copy the result into the provided buffer
5005d3de03bSIngo Weinhold	bytesRead -= sizeof(AttributeHeader) + pos;
5015d3de03bSIngo Weinhold	if (bytesRead < 0) {
5025d3de03bSIngo Weinhold		// that means pos > <attribute size>
5035d3de03bSIngo Weinhold		errno = B_BAD_VALUE;
5045d3de03bSIngo Weinhold		return -1;
5055d3de03bSIngo Weinhold	}
5065d3de03bSIngo Weinhold
5075d3de03bSIngo Weinhold	if (bytesRead > 0) {
5085d3de03bSIngo Weinhold		if ((size_t)bytesRead > readBytes)
5095d3de03bSIngo Weinhold			bytesRead = readBytes;
5104f4e5272SIngo Weinhold		memcpy(buffer, attributeBuffer + sizeof(AttributeHeader) + pos,
5115d3de03bSIngo Weinhold			bytesRead);
5125d3de03bSIngo Weinhold	}
5134f4e5272SIngo Weinhold
5144f4e5272SIngo Weinhold	return bytesRead;
5154f4e5272SIngo Weinhold}
5164f4e5272SIngo Weinhold
5174f4e5272SIngo Weinhold// fs_write_attr
5184f4e5272SIngo Weinholdssize_t
5194f4e5272SIngo Weinholdfs_write_attr(int fd, const char *_attribute, uint32 type, off_t pos,
5204f4e5272SIngo Weinhold	const void *buffer, size_t writeBytes)
5214f4e5272SIngo Weinhold{
5224f4e5272SIngo Weinhold	// check params
5234f4e5272SIngo Weinhold	if (pos < 0 || pos + writeBytes > kMaxAttributeLength
52455a34b69SIngo Weinhold		|| _attribute == NULL || (writeBytes > 0 && buffer == NULL)) {
5254f4e5272SIngo Weinhold		errno = B_BAD_VALUE;
5264f4e5272SIngo Weinhold		return -1;
5274f4e5272SIngo Weinhold	}
5284f4e5272SIngo Weinhold
5294f4e5272SIngo Weinhold	// resolve FD
5304f4e5272SIngo Weinhold	LocalFD localFD;
5314f4e5272SIngo Weinhold	status_t error = localFD.Init(fd);
5324f4e5272SIngo Weinhold	if (error != B_OK) {
5334f4e5272SIngo Weinhold		errno = error;
5344f4e5272SIngo Weinhold		return -1;
5354f4e5272SIngo Weinhold	}
5364f4e5272SIngo Weinhold
537011e7a3dSIngo Weinhold	// mangle the attribute name
538011e7a3dSIngo Weinhold	string attribute = mangle_attribute_name(_attribute);
5394f4e5272SIngo Weinhold
5404f4e5272SIngo Weinhold	// prepare an attribute buffer
5414f4e5272SIngo Weinhold	char attributeBuffer[sizeof(AttributeHeader) + kMaxAttributeLength];
5424f4e5272SIngo Weinhold	AttributeHeader* header = (AttributeHeader*)attributeBuffer;
5434f4e5272SIngo Weinhold	header->type = type;
5444f4e5272SIngo Weinhold	memset(attributeBuffer + sizeof(AttributeHeader), 0, pos);
54555a34b69SIngo Weinhold	if (writeBytes > 0) {
54655a34b69SIngo Weinhold		memcpy(attributeBuffer + sizeof(AttributeHeader) + pos, buffer,
54755a34b69SIngo Weinhold			writeBytes);
54855a34b69SIngo Weinhold	}
5494f4e5272SIngo Weinhold
5504f4e5272SIngo Weinhold	// write the attribute
5514f4e5272SIngo Weinhold	ssize_t toWrite = sizeof(AttributeHeader) + pos + writeBytes;
5524f4e5272SIngo Weinhold	int result;
5534f4e5272SIngo Weinhold	if (localFD.Path()) {
554b360cc7fSIngo Weinhold		result = set_attribute(-1, localFD.Path(), attribute.c_str(),
555b360cc7fSIngo Weinhold			attributeBuffer, toWrite);
5564f4e5272SIngo Weinhold	} else {
557b360cc7fSIngo Weinhold		result = set_attribute(localFD.FD(), NULL, attribute.c_str(),
558b360cc7fSIngo Weinhold			attributeBuffer, toWrite);
5594f4e5272SIngo Weinhold	}
560540d4f7bSIngo Weinhold	if (result < 0) {
561b360cc7fSIngo Weinhold		// Setting user attributes on symlinks is not allowed (xattr). So, if
562b360cc7fSIngo Weinhold		// this is a symlink and we're only supposed to write a "BEOS:TYPE"
563b360cc7fSIngo Weinhold		// attribute we silently pretend to have succeeded.
564540d4f7bSIngo Weinhold		if (localFD.IsSymlink() && strcmp(_attribute, "BEOS:TYPE") == 0)
565540d4f7bSIngo Weinhold			return writeBytes;
5664f4e5272SIngo Weinhold		return -1;
567540d4f7bSIngo Weinhold	}
5684f4e5272SIngo Weinhold
5694f4e5272SIngo Weinhold	return writeBytes;
5704f4e5272SIngo Weinhold}
5714f4e5272SIngo Weinhold
5724f4e5272SIngo Weinhold// fs_remove_attr
5734f4e5272SIngo Weinholdint
5744f4e5272SIngo Weinholdfs_remove_attr(int fd, const char *_attribute)
5754f4e5272SIngo Weinhold{
5764f4e5272SIngo Weinhold	// check params
5774f4e5272SIngo Weinhold	if (!_attribute) {
5784f4e5272SIngo Weinhold		errno = B_BAD_VALUE;
5794f4e5272SIngo Weinhold		return -1;
5804f4e5272SIngo Weinhold	}
5814f4e5272SIngo Weinhold
5824f4e5272SIngo Weinhold	// resolve FD
5834f4e5272SIngo Weinhold	LocalFD localFD;
5844f4e5272SIngo Weinhold	status_t error = localFD.Init(fd);
5854f4e5272SIngo Weinhold	if (error != B_OK) {
5864f4e5272SIngo Weinhold		errno = error;
5874f4e5272SIngo Weinhold		return -1;
5884f4e5272SIngo Weinhold	}
5894f4e5272SIngo Weinhold
590011e7a3dSIngo Weinhold	// mangle the attribute name
591011e7a3dSIngo Weinhold	string attribute = mangle_attribute_name(_attribute);
5924f4e5272SIngo Weinhold
5934f4e5272SIngo Weinhold	// remove attribute
5944f4e5272SIngo Weinhold	int result;
5954f4e5272SIngo Weinhold	if (localFD.Path())
596b360cc7fSIngo Weinhold		result = remove_attribute(-1, localFD.Path(), attribute.c_str());
5974f4e5272SIngo Weinhold	else
598b360cc7fSIngo Weinhold		result = remove_attribute(localFD.FD(), NULL, attribute.c_str());
5994f4e5272SIngo Weinhold
6004f4e5272SIngo Weinhold	if (result < 0) {
6014f4e5272SIngo Weinhold		// Make sure, the error code is B_ENTRY_NOT_FOUND, if the attribute
6024f4e5272SIngo Weinhold		// doesn't exist.
6034f4e5272SIngo Weinhold		if (errno == ENOATTR || errno == ENODATA)
6044f4e5272SIngo Weinhold			errno = B_ENTRY_NOT_FOUND;
6054f4e5272SIngo Weinhold		return -1;
6064f4e5272SIngo Weinhold	}
6074f4e5272SIngo Weinhold	return 0;
6084f4e5272SIngo Weinhold}
6094f4e5272SIngo Weinhold
6104f4e5272SIngo Weinhold// fs_stat_attr
6114f4e5272SIngo Weinholdint
6124f4e5272SIngo Weinholdfs_stat_attr(int fd, const char *_attribute, struct attr_info *attrInfo)
6134f4e5272SIngo Weinhold{
6144f4e5272SIngo Weinhold	if (!_attribute || !attrInfo) {
6154f4e5272SIngo Weinhold		errno = B_BAD_VALUE;
6164f4e5272SIngo Weinhold		return -1;
6174f4e5272SIngo Weinhold	}
6184f4e5272SIngo Weinhold
6194f4e5272SIngo Weinhold	// resolve FD
6204f4e5272SIngo Weinhold	LocalFD localFD;
6214f4e5272SIngo Weinhold	status_t error = localFD.Init(fd);
6224f4e5272SIngo Weinhold	if (error != B_OK) {
6234f4e5272SIngo Weinhold		errno = error;
6244f4e5272SIngo Weinhold		return -1;
6254f4e5272SIngo Weinhold	}
6264f4e5272SIngo Weinhold
627011e7a3dSIngo Weinhold	// mangle the attribute name
628011e7a3dSIngo Weinhold	string attribute = mangle_attribute_name(_attribute);
6294f4e5272SIngo Weinhold
6304f4e5272SIngo Weinhold	// read the attribute
6314f4e5272SIngo Weinhold	char attributeBuffer[sizeof(AttributeHeader) + kMaxAttributeLength];
6324f4e5272SIngo Weinhold	ssize_t bytesRead = sizeof(AttributeHeader) + kMaxAttributeLength;
6334f4e5272SIngo Weinhold	if (localFD.Path()) {
634b360cc7fSIngo Weinhold		bytesRead = get_attribute(-1, localFD.Path(), attribute.c_str(),
6354f4e5272SIngo Weinhold			attributeBuffer, bytesRead);
6364f4e5272SIngo Weinhold	} else {
637b360cc7fSIngo Weinhold		bytesRead = get_attribute(localFD.FD(), NULL, attribute.c_str(),
638b360cc7fSIngo Weinhold			attributeBuffer, bytesRead);
6394f4e5272SIngo Weinhold	}
6404f4e5272SIngo Weinhold	if (bytesRead < 0) {
6414f4e5272SIngo Weinhold		// Make sure, the error code is B_ENTRY_NOT_FOUND, if the attribute
6424f4e5272SIngo Weinhold		// doesn't exist.
6434f4e5272SIngo Weinhold		if (errno == ENOATTR || errno == ENODATA)
6444f4e5272SIngo Weinhold			errno = B_ENTRY_NOT_FOUND;
6454f4e5272SIngo Weinhold		return -1;
6464f4e5272SIngo Weinhold	}
6474f4e5272SIngo Weinhold
6484f4e5272SIngo Weinhold	// check length for sanity
6494f4e5272SIngo Weinhold	if ((size_t)bytesRead < sizeof(AttributeHeader)) {
6504f4e5272SIngo Weinhold		fprintf(stderr, "fs_stat_attr(): attribute \"%s\" is shorter than the "
6514f4e5272SIngo Weinhold			"AttributeHeader!\n", attribute.c_str());
6524f4e5272SIngo Weinhold		errno = B_ERROR;
6534f4e5272SIngo Weinhold		return -1;
6544f4e5272SIngo Weinhold	}
6554f4e5272SIngo Weinhold
6564f4e5272SIngo Weinhold	attrInfo->size = bytesRead - sizeof(AttributeHeader);
6574f4e5272SIngo Weinhold	attrInfo->type = ((AttributeHeader*)attributeBuffer)->type;
6584f4e5272SIngo Weinhold
6594f4e5272SIngo Weinhold	return 0;
6604f4e5272SIngo Weinhold}
6614f4e5272SIngo Weinhold
6624f4e5272SIngo Weinhold
6634f4e5272SIngo Weinhold// #pragma mark - Private Syscalls
6644f4e5272SIngo Weinhold
6654f4e5272SIngo Weinhold
6664f4e5272SIngo Weinhold#ifndef BUILDING_FS_SHELL
6674f4e5272SIngo Weinhold
6684f4e5272SIngo Weinhold// _kern_open_attr_dir
6694f4e5272SIngo Weinholdint
6704f4e5272SIngo Weinhold_kern_open_attr_dir(int fd, const char *path)
6714f4e5272SIngo Weinhold{
6724f4e5272SIngo Weinhold	// get node ref for the node
6734f4e5272SIngo Weinhold	struct stat st;
6744f4e5272SIngo Weinhold	status_t error = _kern_read_stat(fd, path, false, &st,
6754f4e5272SIngo Weinhold		sizeof(struct stat));
6764f4e5272SIngo Weinhold	if (error != B_OK) {
6774f4e5272SIngo Weinhold		errno = error;
6784f4e5272SIngo Weinhold		return -1;
6794f4e5272SIngo Weinhold	}
6804f4e5272SIngo Weinhold	NodeRef ref(st);
6814f4e5272SIngo Weinhold
6824f4e5272SIngo Weinhold	DIR* dir;
6834f4e5272SIngo Weinhold	if (path) {
6844f4e5272SIngo Weinhold		// If a path was given, get a usable path.
6854f4e5272SIngo Weinhold		string realPath;
6864f4e5272SIngo Weinhold		status_t error = get_path(fd, path, realPath);
6874f4e5272SIngo Weinhold		if (error != B_OK)
6884f4e5272SIngo Weinhold			return error;
6894f4e5272SIngo Weinhold
6904f4e5272SIngo Weinhold		dir = fs_open_attr_dir(realPath.c_str());
6914f4e5272SIngo Weinhold	} else
6924f4e5272SIngo Weinhold		dir = fs_fopen_attr_dir(fd);
6934f4e5272SIngo Weinhold
6944f4e5272SIngo Weinhold	if (!dir)
6954f4e5272SIngo Weinhold		return errno;
696b360cc7fSIngo Weinhold
697b360cc7fSIngo Weinhold	// create descriptor
6984f4e5272SIngo Weinhold	AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref);
6994f4e5272SIngo Weinhold	return add_descriptor(descriptor);
7004f4e5272SIngo Weinhold}
7014f4e5272SIngo Weinhold
7024f4e5272SIngo Weinhold// _kern_rename_attr
7034f4e5272SIngo Weinholdstatus_t
7044f4e5272SIngo Weinhold_kern_rename_attr(int fromFile, const char *fromName, int toFile,
7054f4e5272SIngo Weinhold	const char *toName)
7064f4e5272SIngo Weinhold{
7074f4e5272SIngo Weinhold	// not supported ATM
7084f4e5272SIngo Weinhold	return B_BAD_VALUE;
7094f4e5272SIngo Weinhold}
7104f4e5272SIngo Weinhold
7114f4e5272SIngo Weinhold// _kern_remove_attr
7124f4e5272SIngo Weinholdstatus_t
7134f4e5272SIngo Weinhold_kern_remove_attr(int fd, const char *name)
7144f4e5272SIngo Weinhold{
7154f4e5272SIngo Weinhold	if (!name)
7164f4e5272SIngo Weinhold		return B_BAD_VALUE;
7174f4e5272SIngo Weinhold
7184f4e5272SIngo Weinhold	if (fs_remove_attr(fd, name) < 0)
7194f4e5272SIngo Weinhold		return errno;
7204f4e5272SIngo Weinhold	return B_OK;
7214f4e5272SIngo Weinhold}
7224f4e5272SIngo Weinhold
7234f4e5272SIngo Weinhold#endif	// ! BUILDING_FS_SHELL