11553Srgrimes/*
21553Srgrimes * Copyright 2009-2010, Haiku Inc. All rights reserved.
31553Srgrimes * Distributed under the terms of the MIT License.
41553Srgrimes *
51553Srgrimes * Authors:
61553Srgrimes *		Michael Lotz <mmlr@mlotz.ch>
71553Srgrimes */
81553Srgrimes
91553Srgrimes
101553Srgrimes#include <new>
111553Srgrimes#include <stdlib.h>
121553Srgrimes#include <string.h>
131553Srgrimes
141553Srgrimes#include <dirent.h>
151553Srgrimes
161553Srgrimes#include <util/kernel_cpp.h>
171553Srgrimes
181553Srgrimes#include <fs_info.h>
191553Srgrimes#include <fs_interface.h>
201553Srgrimes
211553Srgrimes#include <debug.h>
221553Srgrimes#include <KernelExport.h>
231553Srgrimes#include <NodeMonitor.h>
241553Srgrimes
251553Srgrimes
261553Srgrimes//#define TRACE_OVERLAY
271553Srgrimes#ifdef TRACE_OVERLAY
281553Srgrimes#	define TRACE(x...)			dprintf("attribute_overlay: " x)
291553Srgrimes#	define TRACE_VOLUME(x...)	dprintf("attribute_overlay: " x)
301553Srgrimes#	define TRACE_ALWAYS(x...)	dprintf("attribute_overlay: " x)
311553Srgrimes#else
3231492Swollman#	define TRACE(x...)			/* nothing */
331553Srgrimes#	define TRACE_VOLUME(x...)	/* nothing */
341553Srgrimes#	define TRACE_ALWAYS(x...)	dprintf("attribute_overlay: " x)
351553Srgrimes#endif
361553Srgrimes
37117599Sgad
381553Srgrimes#define ATTRIBUTE_OVERLAY_FILE_MAGIC			'attr'
3915648Sjoerg#define ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME	"_HAIKU"
401553Srgrimes
41117599Sgad
421553Srgrimes#define OVERLAY_CALL(op, params...) \
43117599Sgad	TRACE("relaying op: " #op "\n"); \
44117599Sgad	OverlayInode *node = (OverlayInode *)vnode->private_node; \
45117599Sgad	fs_vnode *superVnode = node->SuperVnode(); \
461553Srgrimes	if (superVnode->ops->op != NULL) \
471553Srgrimes		return superVnode->ops->op(volume->super_volume, superVnode, params); \
481553Srgrimes	return B_UNSUPPORTED;
491553Srgrimes
501553Srgrimes
511553Srgrimes#define OVERLAY_VOLUME_CALL(op, params...) \
521553Srgrimes	TRACE_VOLUME("relaying volume op: " #op "\n"); \
5315648Sjoerg	if (volume->super_volume->ops->op != NULL) \
541553Srgrimes		return volume->super_volume->ops->op(volume->super_volume, params);
551553Srgrimes
561553Srgrimes
57241852Seadlernamespace attribute_overlay {
581553Srgrimes
591553Srgrimesclass AttributeFile;
601553Srgrimesclass AttributeEntry;
611553Srgrimes
621553Srgrimes
631553Srgrimesstruct attribute_dir_cookie {
641553Srgrimes	AttributeFile *	file;
651553Srgrimes	uint32			index;
661553Srgrimes};
671553Srgrimes
681553Srgrimes
691553Srgrimesclass OverlayVolume {
701553Srgrimespublic:
7198152Sgad							OverlayVolume(fs_volume *volume);
7298152Sgad							~OverlayVolume();
7398152Sgad
7498152Sgad		fs_volume *			Volume() { return fVolume; }
7598152Sgad		fs_volume *			SuperVolume() { return fVolume->super_volume; }
7698152Sgad
7798152Sgadprivate:
7898152Sgad		fs_volume *			fVolume;
7998267Sgad};
8078146Sgad
81231723Skevlo
8298152Sgadclass OverlayInode {
83234244Sdelphijpublic:
8478146Sgad							OverlayInode(OverlayVolume *volume,
8578146Sgad								fs_vnode *superVnode, ino_t inodeNumber);
8698267Sgad							~OverlayInode();
8778750Sgad
881553Srgrimes		status_t			InitCheck();
891553Srgrimes
9031492Swollman		fs_volume *			Volume() { return fVolume->Volume(); }
9131492Swollman		fs_volume *			SuperVolume() { return fVolume->SuperVolume(); }
921553Srgrimes		fs_vnode *			SuperVnode() { return &fSuperVnode; }
9378750Sgad		ino_t				InodeNumber() { return fInodeNumber; }
9478750Sgad
9578750Sgad		status_t			GetAttributeFile(AttributeFile **attributeFile);
9678750Sgad		status_t			WriteAttributeFile();
9778750Sgad		status_t			RemoveAttributeFile();
9878750Sgad
9978750Sgadprivate:
10078750Sgad		OverlayVolume *		fVolume;
10178750Sgad		fs_vnode			fSuperVnode;
10298268Sgad		ino_t				fInodeNumber;
10398267Sgad		AttributeFile *		fAttributeFile;
10478750Sgad};
10578750Sgad
10678750Sgad
1071553Srgrimesclass AttributeFile {
10898267Sgadpublic:
10978750Sgad								AttributeFile(fs_volume *overlay,
1101553Srgrimes									fs_volume *volume, fs_vnode *vnode);
11178750Sgad								~AttributeFile();
11278750Sgad
11398268Sgad			status_t			InitCheck() { return fStatus; }
1141553Srgrimes
1151553Srgrimes			dev_t				VolumeID() { return fVolumeID; }
11698278Sgad			ino_t				FileInode() { return fFileInode; }
11798278Sgad
11898278Sgad			status_t			CreateEmpty();
11998278Sgad			status_t			WriteAttributeFile(fs_volume *overlay,
12098278Sgad									fs_volume *volume, fs_vnode *vnode);
12198267Sgad			status_t			RemoveAttributeFile(fs_volume *overlay,
12298278Sgad									fs_volume *volume, fs_vnode *vnode);
12398278Sgad
12498278Sgad			status_t			ReadAttributeDir(struct dirent *dirent,
12598278Sgad									size_t bufferSize, uint32 *numEntries,
12698267Sgad									uint32 *index);
12798267Sgad
1281553Srgrimes			uint32				CountAttributes();
1291553Srgrimes			AttributeEntry *	FindAttribute(const char *name,
13078750Sgad									uint32 *index = NULL);
13198268Sgad
13298268Sgad			status_t			CreateAttribute(const char *name, type_code type,
13398268Sgad									int openMode, AttributeEntry **entry);
13498268Sgad			status_t			OpenAttribute(const char *name, int openMode,
13578750Sgad									AttributeEntry **entry);
13678750Sgad			status_t			RemoveAttribute(const char *name,
13778750Sgad									AttributeEntry **entry);
13878750Sgad			status_t			AddAttribute(AttributeEntry *entry);
13978750Sgad
14078750Sgadprivate:
14178750Sgad			struct attribute_file {
14278750Sgad				uint32			magic;
14378750Sgad					// ATTRIBUTE_OVERLAY_FILE_MAGIC
14478750Sgad				uint32			entry_count;
14578750Sgad				uint8			entries[1];
14678750Sgad			} _PACKED;
14778750Sgad
14878750Sgad			status_t			fStatus;
14978750Sgad			dev_t				fVolumeID;
15078750Sgad			ino_t				fFileInode;
15178750Sgad			ino_t				fDirectoryInode;
15298267Sgad			ino_t				fAttributeDirInode;
15398267Sgad			ino_t				fAttributeFileInode;
15498267Sgad			attribute_file *	fFile;
15598267Sgad			uint32				fAttributeDirIndex;
15698267Sgad			AttributeEntry **	fEntries;
15798267Sgad};
15898267Sgad
15998267Sgad
16098268Sgadclass AttributeEntry {
16198267Sgadpublic:
16298267Sgad								AttributeEntry(AttributeFile *parent,
16398267Sgad									uint8 *buffer);
16498267Sgad								AttributeEntry(AttributeFile *parent,
16598267Sgad									const char *name, type_code type);
16698267Sgad								~AttributeEntry();
167234824Sgad
168234824Sgad			status_t			InitCheck() { return fStatus; }
169234824Sgad
170234824Sgad			uint8 *				Entry() { return (uint8 *)fEntry; }
171234824Sgad			size_t				EntrySize();
172234824Sgad			uint8 *				Data() { return fData; }
173234824Sgad			size_t				DataSize() { return fEntry->size; }
174234824Sgad
17598267Sgad			status_t			SetType(type_code type);
17698267Sgad			type_code			Type() { return fEntry->type; }
17778750Sgad
17878750Sgad			status_t			SetSize(size_t size);
17978750Sgad			uint32				Size() { return fEntry->size; }
18078750Sgad
18178750Sgad			status_t			SetName(const char *name);
18278750Sgad			const char *		Name() { return fEntry->name; }
18398268Sgad			uint8				NameLength() { return fEntry->name_length; }
18498268Sgad
18598268Sgad			status_t			FillDirent(struct dirent *dirent,
18698268Sgad									size_t bufferSize, uint32 *numEntries);
18798268Sgad
18878750Sgad			status_t			Read(off_t position, void *buffer,
18978750Sgad									size_t *length);
19098268Sgad			status_t			Write(off_t position, const void *buffer,
19198268Sgad									size_t *length);
19298268Sgad
19398268Sgad			status_t			ReadStat(struct stat *stat);
19498268Sgad			status_t			WriteStat(const struct stat *stat,
19598268Sgad									uint32 statMask);
19698268Sgad
19798268Sgadprivate:
19898268Sgad			struct attribute_entry {
19978750Sgad				type_code		type;
20078750Sgad				uint32			size;
20178750Sgad				uint8			name_length; // including 0 byte
20298268Sgad				char			name[1]; // 0 terminated, followed by data
20378750Sgad			} _PACKED;
20478146Sgad
20578146Sgad			AttributeFile *		fParent;
20631492Swollman			attribute_entry *	fEntry;
20731492Swollman			uint8 *				fData;
20878146Sgad			status_t			fStatus;
20931492Swollman			bool				fAllocatedEntry;
21078146Sgad			bool				fAllocatedData;
21131492Swollman};
21278146Sgad
21331492Swollman
21431492Swollman//	#pragma mark OverlayVolume
21531492Swollman
21631492Swollman
21731492SwollmanOverlayVolume::OverlayVolume(fs_volume *volume)
21831492Swollman	:
21931492Swollman	fVolume(volume)
22079739Sgad{
22131492Swollman}
22278146Sgad
2231553Srgrimes
22478750SgadOverlayVolume::~OverlayVolume()
2251553Srgrimes{
22678750Sgad}
22778750Sgad
22898268Sgad
22931492Swollman//	#pragma mark OverlayInode
23078146Sgad
23178146Sgad
23231492SwollmanOverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode,
23379739Sgad	ino_t inodeNumber)
23431492Swollman	:
23531492Swollman	fVolume(volume),
2361553Srgrimes	fSuperVnode(*superVnode),
23731492Swollman	fInodeNumber(inodeNumber),
23831492Swollman	fAttributeFile(NULL)
23931492Swollman{
24031492Swollman	TRACE("inode created\n");
24131492Swollman}
24231492Swollman
24331492Swollman
24478146SgadOverlayInode::~OverlayInode()
2451553Srgrimes{
24678750Sgad	TRACE("inode destroyed\n");
24778750Sgad	delete fAttributeFile;
24878750Sgad}
24978750Sgad
25078750Sgad
25199846Sgadstatus_t
25298267SgadOverlayInode::InitCheck()
25398267Sgad{
25498267Sgad	return B_OK;
25578750Sgad}
25698267Sgad
25798267Sgad
25898267Sgadstatus_t
25998267SgadOverlayInode::GetAttributeFile(AttributeFile **attributeFile)
26098267Sgad{
26198267Sgad	if (fAttributeFile == NULL) {
26298267Sgad		fAttributeFile = new(std::nothrow) AttributeFile(Volume(),
26398267Sgad			SuperVolume(), &fSuperVnode);
26498267Sgad		if (fAttributeFile == NULL) {
26598267Sgad			TRACE_ALWAYS("no memory to allocate attribute file\n");
26698267Sgad			return B_NO_MEMORY;
26798267Sgad		}
26898267Sgad	}
26998267Sgad
27098267Sgad	status_t result = fAttributeFile->InitCheck();
27198267Sgad	if (result != B_OK) {
27298267Sgad		if (result == B_ENTRY_NOT_FOUND) {
27398267Sgad			// TODO: need to check if we're able to create the file
27498267Sgad			// but at least allow virtual attributes for now
27598267Sgad		}
27698267Sgad
27798267Sgad		result = fAttributeFile->CreateEmpty();
27898267Sgad		if (result != B_OK)
27998267Sgad			return result;
2801553Srgrimes	}
2811553Srgrimes
28231492Swollman	*attributeFile = fAttributeFile;
28398152Sgad	return B_OK;
28498152Sgad}
28598152Sgad
28698152Sgad
28798152Sgadstatus_t
28898152SgadOverlayInode::WriteAttributeFile()
28998152Sgad{
29098152Sgad	if (fAttributeFile == NULL)
29198152Sgad		return B_NO_INIT;
292241852Seadler
29398152Sgad	status_t result = fAttributeFile->InitCheck();
29498152Sgad	if (result != B_OK)
295241852Seadler		return result;
29698152Sgad
29798152Sgad	return fAttributeFile->WriteAttributeFile(Volume(), SuperVolume(),
29898152Sgad		&fSuperVnode);
29998152Sgad}
30098152Sgad
30198152Sgad
30298152Sgadstatus_t
30398152SgadOverlayInode::RemoveAttributeFile()
30498152Sgad{
30598152Sgad	if (fAttributeFile == NULL)
30698152Sgad		return B_NO_INIT;
30798152Sgad
30898152Sgad	status_t result = fAttributeFile->InitCheck();
30998152Sgad	if (result != B_OK)
31098152Sgad		return result;
31198152Sgad
31298152Sgad	return fAttributeFile->RemoveAttributeFile(Volume(), SuperVolume(),
31398152Sgad		&fSuperVnode);
31498152Sgad}
31598152Sgad
31698152Sgad
31798152Sgad//	#pragma mark AttributeFile
31898152Sgad
31998152Sgad
32098152SgadAttributeFile::AttributeFile(fs_volume *overlay, fs_volume *volume,
32198152Sgad	fs_vnode *vnode)
32298152Sgad	:
32398152Sgad	fStatus(B_NO_INIT),
32498152Sgad	fVolumeID(volume->id),
32598152Sgad	fFileInode(0),
32698152Sgad	fDirectoryInode(0),
32798152Sgad	fAttributeDirInode(0),
32898152Sgad	fAttributeFileInode(0),
32998152Sgad	fFile(NULL),
33098152Sgad	fAttributeDirIndex(0),
33198152Sgad	fEntries(NULL)
33298152Sgad{
333241852Seadler	if (vnode->ops->get_vnode_name == NULL) {
33498152Sgad		TRACE_ALWAYS("cannot get vnode name, hook missing\n");
33598152Sgad		fStatus = B_UNSUPPORTED;
336241852Seadler		return;
33798152Sgad	}
33898152Sgad
33998152Sgad	char nameBuffer[B_FILE_NAME_LENGTH];
34098152Sgad	nameBuffer[sizeof(nameBuffer) - 1] = 0;
34198152Sgad	fStatus = vnode->ops->get_vnode_name(volume, vnode, nameBuffer,
34298152Sgad		sizeof(nameBuffer) - 1);
34398152Sgad	if (fStatus != B_OK) {
34498152Sgad		TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(fStatus));
34598152Sgad		return;
34698152Sgad	}
34798152Sgad
34898152Sgad	if (strcmp(nameBuffer, ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) {
34998152Sgad		// we don't want attribute overlays on the attribute dir itself
35098152Sgad		fStatus = B_UNSUPPORTED;
35198152Sgad		return;
35298152Sgad	}
35398152Sgad
35498152Sgad	struct stat stat;
35598152Sgad	if (vnode->ops->read_stat != NULL
35698152Sgad		&& vnode->ops->read_stat(volume, vnode, &stat) == B_OK) {
35798152Sgad		fFileInode = stat.st_ino;
35898152Sgad	}
35998152Sgad
36098152Sgad	// TODO: the ".." lookup is not actually valid for non-directory vnodes.
36198152Sgad	// we make use of the fact that a filesystem probably still provides the
36298152Sgad	// lookup hook and has hardcoded ".." to resolve to the parent entry. if we
36398152Sgad	// wanted to do this correctly we need some other way to relate this vnode
36498152Sgad	// to its parent directory vnode.
36598152Sgad	const char *lookup[]
36698152Sgad		= { "..", ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, nameBuffer };
36798152Sgad	int32 lookupCount = sizeof(lookup) / sizeof(lookup[0]);
36898152Sgad	fs_vnode currentVnode = *vnode;
36998152Sgad	ino_t lastInodeNumber = 0;
3701553Srgrimes
3711553Srgrimes	for (int32 i = 0; i < lookupCount; i++) {
3721553Srgrimes		if (currentVnode.ops->lookup == NULL) {
37398267Sgad			TRACE_ALWAYS("lookup not possible, lookup hook missing\n");
3741553Srgrimes			fStatus = B_UNSUPPORTED;
37598267Sgad			if (i > 0)
37627748Simp				put_vnode(volume, lastInodeNumber);
3771553Srgrimes			return;
37831492Swollman		}
3791553Srgrimes
380241852Seadler		ino_t inodeNumber;
38131492Swollman		fStatus = currentVnode.ops->lookup(volume, &currentVnode, lookup[i],
382241852Seadler			&inodeNumber);
38331492Swollman
38431492Swollman		if (i > 0)
3851553Srgrimes			put_vnode(volume, lastInodeNumber);
3861553Srgrimes
3871553Srgrimes		if (fStatus != B_OK) {
388231723Skevlo			if (fStatus != B_ENTRY_NOT_FOUND) {
3891553Srgrimes				TRACE_ALWAYS("lookup of \"%s\" failed: %s\n", lookup[i],
3901553Srgrimes					strerror(fStatus));
3911553Srgrimes			}
3921553Srgrimes			return;
39398267Sgad		}
39498267Sgad
39598267Sgad		if (i == 0)
39698267Sgad			fDirectoryInode = inodeNumber;
39798267Sgad		else if (i == 1)
39898267Sgad			fAttributeDirInode = inodeNumber;
3991553Srgrimes		else if (i == 2)
4001553Srgrimes			fAttributeFileInode = inodeNumber;
40178750Sgad
40298152Sgad		OverlayInode *overlayInode = NULL;
40398152Sgad		fStatus = get_vnode(overlay, inodeNumber, (void **)&overlayInode);
40498152Sgad		if (fStatus != B_OK) {
40598152Sgad			TRACE_ALWAYS("getting vnode failed: %s\n", strerror(fStatus));
40698152Sgad			return;
40798152Sgad		}
40898152Sgad
40998152Sgad		currentVnode = *overlayInode->SuperVnode();
41098152Sgad		lastInodeNumber = inodeNumber;
41198152Sgad	}
41298152Sgad
41398152Sgad	if (currentVnode.ops->read_stat == NULL || currentVnode.ops->open == NULL
41498152Sgad		|| currentVnode.ops->read == NULL) {
41598152Sgad		TRACE_ALWAYS("can't use attribute file, hooks missing\n");
41698152Sgad		put_vnode(volume, lastInodeNumber);
41798152Sgad		fStatus = B_UNSUPPORTED;
41898152Sgad		return;
41998152Sgad	}
42098152Sgad
42198152Sgad	fStatus = currentVnode.ops->read_stat(volume, &currentVnode, &stat);
42298152Sgad	if (fStatus != B_OK) {
42398152Sgad		TRACE_ALWAYS("failed to stat attribute file: %s\n", strerror(fStatus));
42498152Sgad		put_vnode(volume, lastInodeNumber);
42598152Sgad		return;
42698152Sgad	}
42798152Sgad
42898152Sgad	void *attrFileCookie = NULL;
42998152Sgad	fStatus = currentVnode.ops->open(volume, &currentVnode, O_RDONLY,
43098152Sgad		&attrFileCookie);
43198152Sgad	if (fStatus != B_OK) {
43298152Sgad		TRACE_ALWAYS("failed to open attribute file: %s\n", strerror(fStatus));
43398152Sgad		put_vnode(volume, lastInodeNumber);
43498152Sgad		return;
43598152Sgad	}
43698152Sgad
43798152Sgad	size_t readLength = stat.st_size;
43898152Sgad	uint8 *buffer = (uint8 *)malloc(readLength);
43998152Sgad	if (buffer == NULL) {
44098152Sgad		TRACE_ALWAYS("cannot allocate memory for read buffer\n");
44198152Sgad		put_vnode(volume, lastInodeNumber);
44298152Sgad		fStatus = B_NO_MEMORY;
44398152Sgad		return;
44498152Sgad	}
44598152Sgad
44698267Sgad	fStatus = currentVnode.ops->read(volume, &currentVnode, attrFileCookie, 0,
44798267Sgad		buffer, &readLength);
44898152Sgad	if (fStatus != B_OK) {
44998152Sgad		TRACE_ALWAYS("failed to read from file: %s\n", strerror(fStatus));
45098152Sgad		put_vnode(volume, lastInodeNumber);
45178750Sgad		return;
45278750Sgad	}
45378750Sgad
45478750Sgad	if (currentVnode.ops->close != NULL)
45578750Sgad		currentVnode.ops->close(volume, &currentVnode, attrFileCookie);
45678750Sgad	if (currentVnode.ops->free_cookie != NULL)
45778750Sgad		currentVnode.ops->free_cookie(volume, &currentVnode, attrFileCookie);
45878750Sgad
45978750Sgad	put_vnode(volume, lastInodeNumber);
46078750Sgad
46178750Sgad	fFile = (attribute_file *)buffer;
4621553Srgrimes	if (fFile->magic != ATTRIBUTE_OVERLAY_FILE_MAGIC) {
463231723Skevlo		TRACE_ALWAYS("attribute file has bad magic\n");
4641553Srgrimes		fStatus = B_BAD_VALUE;
4651553Srgrimes		return;
4661553Srgrimes	}
46787034Sgad
46887034Sgad	fEntries = (AttributeEntry **)malloc(fFile->entry_count
46978750Sgad		* sizeof(AttributeEntry *));
47078750Sgad	if (fEntries == NULL) {
47178750Sgad		TRACE_ALWAYS("no memory to allocate entry pointers\n");
47278750Sgad		fStatus = B_NO_MEMORY;
47378750Sgad		return;
47478750Sgad	}
47578750Sgad
47678750Sgad	for (uint32 i = 0; i < fFile->entry_count; i++)
47778750Sgad		fEntries[i] = NULL;
47878750Sgad
4791553Srgrimes	size_t totalSize = 0;
4801553Srgrimes	readLength -= sizeof(attribute_file) - 1;
4811553Srgrimes	for (uint32 i = 0; i < fFile->entry_count; i++) {
48284034Sgad		fEntries[i] = new(std::nothrow) AttributeEntry(this,
48384034Sgad			fFile->entries + totalSize);
48484034Sgad		if (fEntries[i] == NULL) {
48587034Sgad			TRACE_ALWAYS("no memory to allocate attribute entry\n");
48687034Sgad			fStatus = B_NO_MEMORY;
48787034Sgad			return;
48887034Sgad		}
48987034Sgad
49087034Sgad		totalSize += fEntries[i]->EntrySize() + fEntries[i]->DataSize();
49187034Sgad		if (totalSize > readLength) {
49287034Sgad			TRACE_ALWAYS("attribute entries are too large for buffer\n");
49387034Sgad			fStatus = B_BAD_VALUE;
49487034Sgad			return;
49587034Sgad		}
4961553Srgrimes	}
4971553Srgrimes}
498234244Sdelphij
4991553Srgrimes
50084034SgadAttributeFile::~AttributeFile()
50184034Sgad{
50284034Sgad	if (fFile == NULL)
5031553Srgrimes		return;
504234244Sdelphij
505234244Sdelphij	if (fEntries != NULL) {
50684034Sgad		for (uint32 i = 0; i < fFile->entry_count; i++)
50784034Sgad			delete fEntries[i];
508228990Suqs
50987034Sgad		free(fEntries);
51087034Sgad	}
51187034Sgad
51284034Sgad	free(fFile);
51384034Sgad}
51484034Sgad
51584034Sgad
51684034Sgadstatus_t
51784034SgadAttributeFile::CreateEmpty()
51884034Sgad{
51984034Sgad	if (fFile == NULL) {
52084034Sgad		fFile = (attribute_file *)malloc(sizeof(attribute_file) - 1);
52184691Sgad		if (fFile == NULL) {
52284034Sgad			TRACE_ALWAYS("failed to allocate file buffer\n");
52384034Sgad			fStatus = B_NO_MEMORY;
52484034Sgad			return fStatus;
52584034Sgad		}
52684034Sgad
52784034Sgad		fFile->entry_count = 0;
52887034Sgad		fFile->magic = ATTRIBUTE_OVERLAY_FILE_MAGIC;
52987034Sgad	}
53084034Sgad
53187034Sgad	fStatus = B_OK;
53284034Sgad	return B_OK;
53384034Sgad}
53484034Sgad
53584034Sgad
53684034Sgadstatus_t
53784034SgadAttributeFile::WriteAttributeFile(fs_volume *overlay, fs_volume *volume,
53884034Sgad	fs_vnode *vnode)
53984034Sgad{
54084034Sgad	if (fFile == NULL)
54184034Sgad		return B_NO_INIT;
54284034Sgad
54384034Sgad	char nameBuffer[B_FILE_NAME_LENGTH];
54484034Sgad	nameBuffer[sizeof(nameBuffer) - 1] = 0;
54584034Sgad	status_t result = vnode->ops->get_vnode_name(volume, vnode, nameBuffer,
54684034Sgad		sizeof(nameBuffer) - 1);
54784034Sgad	if (result != B_OK) {
54884034Sgad		TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result));
54984034Sgad		return result;
55084034Sgad	}
55184034Sgad
55284034Sgad	fs_vnode currentVnode = *vnode;
55384034Sgad	if (fDirectoryInode == 0) {
55484034Sgad		if (currentVnode.ops->lookup == NULL) {
55584034Sgad			TRACE_ALWAYS("lookup not possible, lookup hook missing\n");
55684034Sgad			return B_UNSUPPORTED;
55784034Sgad		}
55884034Sgad
55984034Sgad		// see TODO above
56084034Sgad		result = currentVnode.ops->lookup(volume, &currentVnode, "..",
56184034Sgad			&fDirectoryInode);
56284034Sgad		if (result != B_OK) {
56384034Sgad			TRACE_ALWAYS("lookup of parent directory failed: %s\n",
56484034Sgad				strerror(result));
56587034Sgad			return B_UNSUPPORTED;
56684034Sgad		}
56784034Sgad
56884034Sgad		put_vnode(volume, fDirectoryInode);
56984034Sgad	}
57084034Sgad
57184034Sgad	OverlayInode *overlayInode = NULL;
57284034Sgad	if (fAttributeDirInode == 0) {
57384034Sgad		result = get_vnode(overlay, fDirectoryInode, (void **)&overlayInode);
574228990Suqs		if (result != B_OK) {
57584034Sgad			TRACE_ALWAYS("failed to get directory vnode: %s\n",
57684034Sgad				strerror(result));
57784034Sgad			return result;
57884034Sgad		}
57984034Sgad
58084034Sgad		currentVnode = *overlayInode->SuperVnode();
58184034Sgad
58284034Sgad		// create the attribute directory
58384034Sgad		result = currentVnode.ops->create_dir(volume, &currentVnode,
58484034Sgad			ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, S_IRWXU | S_IRWXG | S_IRWXO);
585228990Suqs
586228990Suqs		if (result == B_OK) {
58784034Sgad			result = currentVnode.ops->lookup(volume, &currentVnode,
58884034Sgad				ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, &fAttributeDirInode);
58984034Sgad
59084034Sgad			// lookup() got us a reference we don't need -- put it
59184034Sgad			if (result == B_OK)
59284034Sgad				put_vnode(volume, fAttributeDirInode);
59384034Sgad		}
59484034Sgad
59584034Sgad		put_vnode(volume, fDirectoryInode);
59684034Sgad
59784034Sgad		if (result != B_OK) {
59884034Sgad			TRACE_ALWAYS("failed to create attribute directory: %s\n",
59984034Sgad				strerror(result));
60084034Sgad			fAttributeDirInode = 0;
60184034Sgad			return result;
60284034Sgad		}
60384034Sgad	}
60484034Sgad
60584034Sgad	void *attrFileCookie = NULL;
60684034Sgad	if (fAttributeFileInode == 0) {
60784034Sgad		result = get_vnode(overlay, fAttributeDirInode, (void **)&overlayInode);
60884034Sgad		if (result != B_OK) {
60984034Sgad			TRACE_ALWAYS("failed to get attribute directory vnode: %s\n",
6101553Srgrimes				strerror(result));
6111553Srgrimes			return result;
6121553Srgrimes		}
61331492Swollman
61431492Swollman		currentVnode = *overlayInode->SuperVnode();
6151553Srgrimes
6161553Srgrimes		// create the attribute file
61778750Sgad		result = currentVnode.ops->create(volume, &currentVnode,
61831492Swollman			nameBuffer, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP
61998279Sgad			| S_IWGRP | S_IROTH | S_IWOTH, &attrFileCookie,
6201553Srgrimes			&fAttributeFileInode);
62178750Sgad
62278750Sgad		put_vnode(volume, fAttributeDirInode);
62378750Sgad
62478750Sgad		if (result != B_OK) {
62578750Sgad			TRACE_ALWAYS("failed to create attribute file: %s\n",
62678750Sgad				strerror(result));
62778750Sgad			return result;
62878750Sgad		}
62978750Sgad
63078750Sgad		result = get_vnode(overlay, fAttributeFileInode,
63178750Sgad			(void **)&overlayInode);
63278750Sgad		if (result != B_OK) {
63398268Sgad			TRACE_ALWAYS("getting attribute file vnode after create failed: "
63478750Sgad				"%s\n", strerror(result));
63578750Sgad			return result;
63678750Sgad		}
63778750Sgad
63884034Sgad		currentVnode = *overlayInode->SuperVnode();
63978750Sgad	} else {
64078750Sgad		result = get_vnode(overlay, fAttributeFileInode,
64178750Sgad			(void **)&overlayInode);
64278750Sgad		if (result != B_OK) {
64378750Sgad			TRACE_ALWAYS("getting attribute file vnode failed: %s\n",
64478750Sgad				strerror(result));
64578750Sgad			return result;
64678750Sgad		}
64778750Sgad
64878750Sgad		currentVnode = *overlayInode->SuperVnode();
64978750Sgad
65098279Sgad		// open the attribute file
65178750Sgad		result = currentVnode.ops->open(volume, &currentVnode, O_RDWR | O_TRUNC,
65278750Sgad			&attrFileCookie);
65378750Sgad		if (result != B_OK) {
65478750Sgad			TRACE_ALWAYS("failed to open attribute file for writing: %s\n",
65598279Sgad				strerror(result));
65678750Sgad			put_vnode(volume, fAttributeFileInode);
65778750Sgad			return result;
65878750Sgad		}
65978750Sgad	}
66078750Sgad
66178750Sgad	off_t position = 0;
66278750Sgad	size_t writeLength = sizeof(attribute_file) - 1;
66378750Sgad	result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
66478750Sgad		position, fFile, &writeLength);
6651553Srgrimes	if (result != B_OK) {
66678750Sgad		TRACE_ALWAYS("failed to write to attribute file: %s\n",
66778750Sgad			strerror(result));
6681553Srgrimes		goto close_and_put;
66978750Sgad	}
6701553Srgrimes
67178750Sgad	for (uint32 i = 0; i < fFile->entry_count; i++) {
67278750Sgad		writeLength = fEntries[i]->EntrySize();
67378750Sgad		result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
67478750Sgad			position, fEntries[i]->Entry(), &writeLength);
67578750Sgad		if (result != B_OK) {
67678750Sgad			TRACE_ALWAYS("failed to write to attribute file: %s\n",
67731492Swollman				strerror(result));
67831492Swollman			goto close_and_put;
67931492Swollman		}
68031492Swollman
68131492Swollman		writeLength = fEntries[i]->DataSize();
68231492Swollman		result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
6831553Srgrimes			position, fEntries[i]->Data(), &writeLength);
68478750Sgad		if (result != B_OK) {
6851553Srgrimes			TRACE_ALWAYS("failed to write to attribute file: %s\n",
68678750Sgad				strerror(result));
687241852Seadler			goto close_and_put;
68831492Swollman		}
689241852Seadler	}
6901553Srgrimes
69178750Sgadclose_and_put:
69278750Sgad	if (currentVnode.ops->close != NULL)
69378750Sgad		currentVnode.ops->close(volume, &currentVnode, attrFileCookie);
69478750Sgad	if (currentVnode.ops->free_cookie != NULL)
6951553Srgrimes		currentVnode.ops->free_cookie(volume, &currentVnode, attrFileCookie);
6961553Srgrimes
6971553Srgrimes	put_vnode(volume, fAttributeFileInode);
69878750Sgad	return B_OK;
69978750Sgad}
70078750Sgad
70178750Sgad
70278750Sgadstatus_t
70378750SgadAttributeFile::RemoveAttributeFile(fs_volume *overlay, fs_volume *volume,
70478750Sgad	fs_vnode *vnode)
7051553Srgrimes{
7061553Srgrimes	bool hasAttributeFile = fAttributeFileInode != 0;
70778750Sgad	ino_t attributeDirInode = fAttributeDirInode;
70878750Sgad
70984034Sgad	// invalidate all of our cached inode numbers
71084034Sgad	fDirectoryInode = 0;
71184034Sgad	fAttributeDirInode = 0;
71284034Sgad	fAttributeFileInode = 0;
71384034Sgad
71484034Sgad	if (!hasAttributeFile) {
71584034Sgad		// there is no backing file at all yet
71684034Sgad		return B_OK;
71784034Sgad	}
7181553Srgrimes
7191553Srgrimes	char nameBuffer[B_FILE_NAME_LENGTH];
7201553Srgrimes	nameBuffer[sizeof(nameBuffer) - 1] = 0;
72178750Sgad	status_t result = vnode->ops->get_vnode_name(volume, vnode, nameBuffer,
7221553Srgrimes		sizeof(nameBuffer) - 1);
72378750Sgad	if (result != B_OK) {
72478750Sgad		TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result));
72578750Sgad		return result;
72678750Sgad	}
72778750Sgad
72878750Sgad	OverlayInode *overlayInode = NULL;
72978750Sgad	result = get_vnode(overlay, attributeDirInode, (void **)&overlayInode);
73078750Sgad	if (result != B_OK) {
73178750Sgad		TRACE_ALWAYS("getting attribute directory vnode failed: %s\n",
73278750Sgad			strerror(result));
7331553Srgrimes		return result;
7341553Srgrimes	}
7351553Srgrimes
7361553Srgrimes	fs_vnode attributeDir = *overlayInode->SuperVnode();
7371553Srgrimes	if (attributeDir.ops->unlink == NULL) {
7381553Srgrimes		TRACE_ALWAYS("cannot remove attribute file, unlink hook missing\n");
7391553Srgrimes		put_vnode(volume, attributeDirInode);
7401553Srgrimes		return B_UNSUPPORTED;
7411553Srgrimes	}
74278750Sgad
7431553Srgrimes	result = attributeDir.ops->unlink(volume, &attributeDir, nameBuffer);
74478750Sgad	if (result != B_OK) {
74578750Sgad		TRACE_ALWAYS("failed to unlink attribute file: %s\n", strerror(result));
74678750Sgad		put_vnode(volume, attributeDirInode);
74778750Sgad		return result;
74878750Sgad	}
7491553Srgrimes
7501553Srgrimes	put_vnode(volume, attributeDirInode);
7511553Srgrimes	return B_OK;
75287034Sgad}
75387034Sgad
7541553Srgrimes
75578750Sgaduint32
75678750SgadAttributeFile::CountAttributes()
75778750Sgad{
75878750Sgad	if (fFile == NULL)
75978750Sgad		return 0;
76078750Sgad
76178750Sgad	return fFile->entry_count;
76278750Sgad}
76378750Sgad
76478750Sgad
7651553SrgrimesAttributeEntry *
7661553SrgrimesAttributeFile::FindAttribute(const char *name, uint32 *index)
7671553Srgrimes{
7681553Srgrimes	for (uint32 i = 0; i < fFile->entry_count; i++) {
76978750Sgad		if (strcmp(fEntries[i]->Name(), name) == 0) {
77078750Sgad			if (index)
77178750Sgad				*index = i;
77278750Sgad
77378750Sgad			return fEntries[i];
77478750Sgad		}
77578750Sgad	}
77678750Sgad
77778750Sgad	return NULL;
77878750Sgad}
77978750Sgad
78078750Sgad
78178750Sgadstatus_t
78278750SgadAttributeFile::CreateAttribute(const char *name, type_code type, int openMode,
78378750Sgad	AttributeEntry **_entry)
78427618Simp{
7851553Srgrimes	AttributeEntry *existing = FindAttribute(name);
78678146Sgad	if (existing != NULL) {
7871553Srgrimes		if ((openMode & O_TRUNC) != 0)
78878750Sgad			existing->SetSize(0);
78978750Sgad
79078750Sgad		// attribute already exists, only allow if the attribute type is
79178750Sgad		// compatible or the attribute size is 0
79278750Sgad		if (existing->Type() != type) {
79378750Sgad			if (existing->Size() != 0)
79478750Sgad				return B_FILE_EXISTS;
79578750Sgad			existing->SetType(type);
79678750Sgad		}
79778750Sgad
79878750Sgad		if (existing->InitCheck() == B_OK) {
799241852Seadler			*_entry = existing;
80078750Sgad			return B_OK;
801241852Seadler		}
80278750Sgad
80378750Sgad		// we tried to change the existing item but failed, try to just
80478750Sgad		// remove it instead and creating a new one
80578750Sgad		RemoveAttribute(name, NULL);
80678750Sgad	}
80778750Sgad
80878750Sgad	AttributeEntry *entry = new(std::nothrow) AttributeEntry(this, name, type);
80978750Sgad	if (entry == NULL)
81084034Sgad		return B_NO_MEMORY;
81178750Sgad
81278750Sgad	status_t result = AddAttribute(entry);
81378750Sgad	if (result != B_OK) {
81478750Sgad		delete entry;
81578750Sgad		return result;
81678750Sgad	}
81778750Sgad
81878750Sgad	*_entry = entry;
81978750Sgad	return B_OK;
82078750Sgad}
82178750Sgad
82278750Sgad
823241852Seadlerstatus_t
82478750SgadAttributeFile::OpenAttribute(const char *name, int openMode,
825241852Seadler	AttributeEntry **_entry)
82678750Sgad{
82778750Sgad	AttributeEntry *entry = FindAttribute(name);
82878750Sgad	if (entry == NULL)
82978750Sgad		return B_ENTRY_NOT_FOUND;
83078750Sgad
83178750Sgad	if (openMode & O_TRUNC)
83278750Sgad		entry->SetSize(0);
83378750Sgad
83478750Sgad	*_entry = entry;
83578750Sgad	return B_OK;
83678750Sgad}
83778750Sgad
83878750Sgad
83978750Sgadstatus_t
84078750SgadAttributeFile::RemoveAttribute(const char *name, AttributeEntry **_entry)
84178750Sgad{
84278750Sgad	uint32 index = 0;
84378750Sgad	AttributeEntry *entry = FindAttribute(name, &index);
84478750Sgad	if (entry == NULL)
845241852Seadler		return B_ENTRY_NOT_FOUND;
84678750Sgad
847241852Seadler	for (uint32 i = index + 1; i < fFile->entry_count; i++)
84878750Sgad		fEntries[i - 1] = fEntries[i];
84978750Sgad	fFile->entry_count--;
85078750Sgad
85178750Sgad	if (_entry)
85278750Sgad		*_entry = entry;
85378750Sgad	else
85478750Sgad		delete entry;
85578750Sgad
85678750Sgad	notify_attribute_changed(fVolumeID, fFileInode, name, B_ATTR_REMOVED);
85778750Sgad	return B_OK;
85878750Sgad}
85978750Sgad
86078750Sgad
86178750Sgadstatus_t
86278750SgadAttributeFile::AddAttribute(AttributeEntry *entry)
86378750Sgad{
86478750Sgad	status_t result = entry->InitCheck();
86578750Sgad	if (result != B_OK)
86678750Sgad		return result;
86778750Sgad
86878750Sgad	if (FindAttribute(entry->Name()) != NULL)
86978750Sgad		return B_FILE_EXISTS;
8701553Srgrimes
8711553Srgrimes	AttributeEntry **newEntries = (AttributeEntry **)realloc(fEntries,
8721553Srgrimes		(fFile->entry_count + 1) * sizeof(AttributeEntry *));
87398152Sgad	if (newEntries == NULL)
87498152Sgad		return B_NO_MEMORY;
87598152Sgad
87698152Sgad	fEntries = newEntries;
87798152Sgad	fEntries[fFile->entry_count++] = entry;
87898152Sgad
87998152Sgad	notify_attribute_changed(fVolumeID, fFileInode, entry->Name(),
88098152Sgad		B_ATTR_CREATED);
88198152Sgad
88298152Sgad	return B_OK;
88398152Sgad}
88498152Sgad
88598152Sgad
88698152Sgadstatus_t
88798152SgadAttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize,
8881553Srgrimes	uint32 *numEntries, uint32 *index)
8891553Srgrimes{
8901553Srgrimes	if (fFile == NULL || *index >= fFile->entry_count) {
89198152Sgad		*numEntries = 0;
89298152Sgad		return B_OK;
89398152Sgad	}
89498152Sgad
89598152Sgad	return fEntries[(*index)++]->FillDirent(dirent, bufferSize, numEntries);
89698152Sgad}
89798152Sgad
89898152Sgad
89998152Sgad//	#pragma mark AttributeEntry
90098152Sgad
90198152Sgad
90298152SgadAttributeEntry::AttributeEntry(AttributeFile *parent, uint8 *buffer)
9031553Srgrimes	:
90498278Sgad	fParent(parent),
90598278Sgad	fEntry(NULL),
90698278Sgad	fData(NULL),
90798278Sgad	fStatus(B_NO_INIT),
90898278Sgad	fAllocatedEntry(false),
90998278Sgad	fAllocatedData(false)
91098278Sgad{
91198278Sgad	if (buffer == NULL)
91298278Sgad		return;
91398278Sgad
91498278Sgad	fEntry = (attribute_entry *)buffer;
91598278Sgad	fData = (uint8 *)fEntry->name + fEntry->name_length;
91698278Sgad	fStatus = B_OK;
91798278Sgad}
91898278Sgad
91998278Sgad
92098278SgadAttributeEntry::AttributeEntry(AttributeFile *parent, const char *name,
92198278Sgad	type_code type)
92298278Sgad	:
92398278Sgad	fParent(parent),
92498278Sgad	fEntry(NULL),
92598278Sgad	fData(NULL),
92698278Sgad	fStatus(B_NO_INIT),
92798278Sgad	fAllocatedEntry(false),
92898278Sgad	fAllocatedData(false)
92998278Sgad{
93098278Sgad	fStatus = SetName(name);
93198278Sgad	if (fStatus != B_OK)
93298278Sgad		return;
93398278Sgad
93498278Sgad	fEntry->type = type;
93598278Sgad	fEntry->size = 0;
93698278Sgad}
93798278Sgad
93898278Sgad
93998278SgadAttributeEntry::~AttributeEntry()
94098278Sgad{
94198278Sgad	if (fAllocatedEntry)
94298278Sgad		free(fEntry);
94398278Sgad	if (fAllocatedData)
94498278Sgad		free(fData);
94598278Sgad}
94698278Sgad
94798278Sgad
94898278Sgadsize_t
94998278SgadAttributeEntry::EntrySize()
95098278Sgad{
95198278Sgad	return sizeof(attribute_entry) - 1 + fEntry->name_length;
95298278Sgad}
95398278Sgad
95498278Sgad
95598278Sgadstatus_t
95698278SgadAttributeEntry::SetType(type_code type)
9571553Srgrimes{
9581553Srgrimes	fEntry->type = type;
9591553Srgrimes	return B_OK;
96078146Sgad}
9611553Srgrimes
9621553Srgrimes
9631553Srgrimesstatus_t
9641553SrgrimesAttributeEntry::SetSize(size_t size)
9651553Srgrimes{
9661553Srgrimes	if (size <= fEntry->size) {
9671553Srgrimes		fEntry->size = size;
9681553Srgrimes		return B_OK;
96998152Sgad	}
97098152Sgad
97198152Sgad	if (fAllocatedData) {
97298152Sgad		uint8 *newData = (uint8 *)realloc(fData, size);
97398152Sgad		if (newData == NULL) {
97498152Sgad			fStatus = B_NO_MEMORY;
97598152Sgad			return fStatus;
97698152Sgad		}
97798152Sgad
97898152Sgad		fData = newData;
97998152Sgad		fEntry->size = size;
98098152Sgad		return B_OK;
98198152Sgad	}
98298152Sgad
98398152Sgad	uint8 *newData = (uint8 *)malloc(size);
98498152Sgad	if (newData == NULL) {
98598152Sgad		fStatus = B_NO_MEMORY;
98698152Sgad		return fStatus;
987241852Seadler	}
98898152Sgad
989241852Seadler	memcpy(newData, fData, min_c(fEntry->size, size));
99098152Sgad	fEntry->size = size;
99198152Sgad	fAllocatedData = true;
99298152Sgad	fData = newData;
99398152Sgad	return B_OK;
99498152Sgad}
99598152Sgad
99698152Sgad
99798267Sgadstatus_t
99898267SgadAttributeEntry::SetName(const char *name)
99998267Sgad{
100098267Sgad	size_t nameLength = strlen(name) + 1;
100198267Sgad	if (nameLength > 255) {
100298267Sgad		fStatus = B_NAME_TOO_LONG;
100398267Sgad		return fStatus;
100498267Sgad	}
100598267Sgad
100698267Sgad	if (!fAllocatedEntry || fEntry->name_length < nameLength) {
100798267Sgad		attribute_entry *newEntry = (attribute_entry *)malloc(
100898267Sgad			sizeof(attribute_entry) - 1 + nameLength);
100998267Sgad		if (newEntry == NULL) {
101098267Sgad			fStatus = B_NO_MEMORY;
101198267Sgad			return fStatus;
101298267Sgad		}
1013234826Sgad
1014234826Sgad		if (fEntry != NULL)
101598267Sgad			memcpy(newEntry, fEntry, sizeof(attribute_entry) - 1);
101698267Sgad		if (fAllocatedEntry)
101798267Sgad			free(fEntry);
101898267Sgad
101998267Sgad		fAllocatedEntry = true;
102098267Sgad		fEntry = newEntry;
1021234826Sgad	}
1022234826Sgad
1023234826Sgad	fEntry->name_length = nameLength;
1024234826Sgad	strlcpy(fEntry->name, name, nameLength);
1025234826Sgad	return B_OK;
1026234826Sgad}
1027234826Sgad
1028234826Sgad
1029234826Sgadstatus_t
1030234826SgadAttributeEntry::FillDirent(struct dirent *dirent, size_t bufferSize,
1031234826Sgad	uint32 *numEntries)
1032234826Sgad{
1033234826Sgad	dirent->d_dev = dirent->d_pdev = fParent->VolumeID();
1034234826Sgad	dirent->d_ino = (ino_t)this;
1035234826Sgad	dirent->d_pino = fParent->FileInode();
1036234826Sgad	dirent->d_reclen = sizeof(struct dirent) + fEntry->name_length;
103798267Sgad	if (bufferSize < dirent->d_reclen) {
103898267Sgad		*numEntries = 0;
103998267Sgad		return B_BAD_VALUE;
10401553Srgrimes	}
10411553Srgrimes
10421553Srgrimes	strncpy(dirent->d_name, fEntry->name, fEntry->name_length);
104398152Sgad	dirent->d_name[fEntry->name_length - 1] = 0;
104498152Sgad	*numEntries = 1;
104598152Sgad	return B_OK;
104698152Sgad}
104798152Sgad
104898152Sgad
104998152Sgadstatus_t
105098152SgadAttributeEntry::Read(off_t position, void *buffer, size_t *length)
105198152Sgad{
105298152Sgad	*length = min_c(*length, fEntry->size - position);
1053241852Seadler	memcpy(buffer, fData + position, *length);
105498152Sgad	return B_OK;
1055241852Seadler}
105698152Sgad
105798152Sgad
105898152Sgadstatus_t
105998152SgadAttributeEntry::Write(off_t position, const void *buffer, size_t *length)
1060241852Seadler{
106198152Sgad	size_t neededSize = position + *length;
106298152Sgad	if (neededSize > fEntry->size) {
106398152Sgad		status_t result = SetSize(neededSize);
106431492Swollman		if (result != B_OK) {
10651553Srgrimes			*length = 0;
10661553Srgrimes			return result;
106778146Sgad		}
10681553Srgrimes	}
10691553Srgrimes
10701553Srgrimes	memcpy(fData + position, buffer, *length);
10711553Srgrimes	notify_attribute_changed(fParent->VolumeID(), fParent->FileInode(),
10721553Srgrimes		fEntry->name, B_ATTR_CHANGED);
107331492Swollman	return B_OK;
10741553Srgrimes}
107531492Swollman
107631492Swollman
107731492Swollmanstatus_t
10781553SrgrimesAttributeEntry::ReadStat(struct stat *stat)
107931492Swollman{
108031492Swollman	stat->st_dev = fParent->VolumeID();
10811553Srgrimes	stat->st_ino = (ino_t)this;
108231492Swollman	stat->st_nlink = 1;
108331492Swollman	stat->st_blksize = 512;
10841553Srgrimes	stat->st_uid = 1;
10851553Srgrimes	stat->st_gid = 1;
10861553Srgrimes	stat->st_size = fEntry->size;
10871553Srgrimes	stat->st_mode = S_ATTR | 0x0777;
108831492Swollman	stat->st_type = fEntry->type;
10891553Srgrimes	stat->st_atime = stat->st_mtime = stat->st_crtime = time(NULL);
10901553Srgrimes	stat->st_blocks = (fEntry->size + stat->st_blksize - 1) / stat->st_blksize;
10911553Srgrimes	return B_OK;
10921553Srgrimes}
10931553Srgrimes
10941553Srgrimes
10951553Srgrimesstatus_t
10961553SrgrimesAttributeEntry::WriteStat(const struct stat *stat, uint32 statMask)
10971553Srgrimes{
10981553Srgrimes	return B_UNSUPPORTED;
109931492Swollman}
11001553Srgrimes
11011553Srgrimes
11021553Srgrimes//	#pragma mark - vnode ops
11031553Srgrimes
110431492Swollman
11051553Srgrimesstatic status_t
11061553Srgrimesoverlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
110719202Simp{
11081553Srgrimes	OverlayInode *node = (OverlayInode *)vnode->private_node;
11091553Srgrimes	fs_vnode *superVnode = node->SuperVnode();
11101553Srgrimes
111125789Sbrian	status_t result = B_OK;
111231492Swollman	if (superVnode->ops->put_vnode != NULL) {
111331492Swollman		result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
11141553Srgrimes			reenter);
111525789Sbrian	}
111625789Sbrian
111725789Sbrian	delete node;
111825789Sbrian	return result;
111925789Sbrian}
112025789Sbrian
11211553Srgrimes
11221553Srgrimesstatic status_t
11231553Srgrimesoverlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
11241553Srgrimes{
11251553Srgrimes	OverlayInode *node = (OverlayInode *)vnode->private_node;
11261553Srgrimes	fs_vnode *superVnode = node->SuperVnode();
11271553Srgrimes
11281553Srgrimes	status_t result = B_OK;
11291553Srgrimes	if (superVnode->ops->remove_vnode != NULL) {
113098152Sgad		result = superVnode->ops->remove_vnode(volume->super_volume, superVnode,
113198152Sgad			reenter);
113298152Sgad	}
113398152Sgad
113498152Sgad	delete node;
113598152Sgad	return result;
113698152Sgad}
113798152Sgad
113898152Sgad
113998152Sgadstatic status_t
114098267Sgadoverlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode,
114198267Sgad	fs_volume *superVolume, fs_vnode *_superVnode)
114298152Sgad{
114398152Sgad	if (volume == superVolume) {
114468401Sgad		*_superVnode = *vnode;
11451553Srgrimes		return B_OK;
11461553Srgrimes	}
11471553Srgrimes
11481553Srgrimes	OverlayInode *node = (OverlayInode *)vnode->private_node;
11491553Srgrimes	fs_vnode *superVnode = node->SuperVnode();
11501553Srgrimes
11511553Srgrimes	if (superVnode->ops->get_super_vnode != NULL) {
115278146Sgad		return superVnode->ops->get_super_vnode(volume->super_volume,
11531553Srgrimes			superVnode, superVolume, _superVnode);
11541553Srgrimes	}
11551553Srgrimes
115678146Sgad	*_superVnode = *superVnode;
115731492Swollman	return B_OK;
11581553Srgrimes}
11591553Srgrimes
116095258Sdes
11611553Srgrimesstatic status_t
11621553Srgrimesoverlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id)
11631553Srgrimes{
11641553Srgrimes	OVERLAY_CALL(lookup, name, id)
116531492Swollman}
116631492Swollman
116778146Sgad
116878146Sgadstatic status_t
116931492Swollmanoverlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer,
117079739Sgad	size_t bufferSize)
117131492Swollman{
117231492Swollman	OVERLAY_CALL(get_vnode_name, buffer, bufferSize)
11731553Srgrimes}
117431492Swollman
117531492Swollman
117631492Swollmanstatic bool
117731492Swollmanoverlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie)
117831492Swollman{
117931492Swollman	TRACE("relaying op: can_page\n");
118031492Swollman	OverlayInode *node = (OverlayInode *)vnode->private_node;
11811553Srgrimes	fs_vnode *superVnode = node->SuperVnode();
1182241852Seadler
118331492Swollman	if (superVnode->ops->can_page != NULL) {
118431492Swollman		return superVnode->ops->can_page(volume->super_volume, superVnode,
118527618Simp			cookie);
11861553Srgrimes	}
1187241852Seadler
118831492Swollman	return false;
11891553Srgrimes}
11901553Srgrimes
11911553Srgrimes
119268401Sgadstatic status_t
11931553Srgrimesoverlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
11941553Srgrimes	const iovec *vecs, size_t count, size_t *numBytes)
11951553Srgrimes{
11961553Srgrimes	OVERLAY_CALL(read_pages, cookie, pos, vecs, count, numBytes)
11971553Srgrimes}
11981553Srgrimes
11991553Srgrimes
12001553Srgrimesstatic status_t
12011553Srgrimesoverlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
12021553Srgrimes	const iovec *vecs, size_t count, size_t *numBytes)
12031553Srgrimes{
12041553Srgrimes	OVERLAY_CALL(write_pages, cookie, pos, vecs, count, numBytes)
12051553Srgrimes}
12061553Srgrimes
12071553Srgrimes
12081553Srgrimesstatic status_t
12091553Srgrimesoverlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
12101553Srgrimes	io_request *request)
1211241852Seadler{
121231492Swollman	OVERLAY_CALL(io, cookie, request)
121331492Swollman}
12141553Srgrimes
121527618Simp
1216241852Seadlerstatic status_t
121727618Simpoverlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
121827618Simp	io_request *request)
12191553Srgrimes{
12201553Srgrimes	OVERLAY_CALL(cancel_io, cookie, request)
12211553Srgrimes}
12221553Srgrimes
12231553Srgrimes
122478146Sgadstatic status_t
12251553Srgrimesoverlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset,
12261553Srgrimes	size_t size, struct file_io_vec *vecs, size_t *count)
122727618Simp{
12281553Srgrimes	OVERLAY_CALL(get_file_map, offset, size, vecs, count)
12291553Srgrimes}
12301553Srgrimes
1231241852Seadler
123278146Sgadstatic status_t
1233241852Seadleroverlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op,
123427618Simp	void *buffer, size_t length)
12351553Srgrimes{
12361553Srgrimes	OVERLAY_CALL(ioctl, cookie, op, buffer, length)
12371553Srgrimes}
12381553Srgrimes
12391553Srgrimes
12401553Srgrimesstatic status_t
12411553Srgrimesoverlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie,
124278146Sgad	int flags)
12431553Srgrimes{
124468401Sgad	OVERLAY_CALL(set_flags, cookie, flags)
12451553Srgrimes}
12461553Srgrimes
12471553Srgrimes
12481553Srgrimesstatic status_t
12491553Srgrimesoverlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
12501553Srgrimes	selectsync *sync)
125127748Simp{
125227748Simp	OVERLAY_CALL(select, cookie, event, sync)
12531553Srgrimes}
125427635Simp
12551553Srgrimes
12561553Srgrimesstatic status_t
12571553Srgrimesoverlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
12581553Srgrimes	selectsync *sync)
12591553Srgrimes{
12601553Srgrimes	OVERLAY_CALL(deselect, cookie, event, sync)
12611553Srgrimes}
12621553Srgrimes
12631553Srgrimes
12641553Srgrimesstatic status_t
12651553Srgrimesoverlay_fsync(fs_volume *volume, fs_vnode *vnode)
12661553Srgrimes{
12671553Srgrimes	OverlayInode *node = (OverlayInode *)vnode->private_node;
12681553Srgrimes	fs_vnode *superVnode = node->SuperVnode();
12691553Srgrimes
12701553Srgrimes	if (superVnode->ops->fsync != NULL)
127168401Sgad		return superVnode->ops->fsync(volume->super_volume, superVnode);
12721553Srgrimes
12731553Srgrimes	return B_OK;
12741553Srgrimes}
12751553Srgrimes
12761553Srgrimes
12771553Srgrimesstatic status_t
12781553Srgrimesoverlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer,
12791553Srgrimes	size_t *bufferSize)
128068401Sgad{
12811553Srgrimes	OVERLAY_CALL(read_symlink, buffer, bufferSize)
12821553Srgrimes}
12831553Srgrimes
12841553Srgrimes
12851553Srgrimesstatic status_t
12861553Srgrimesoverlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name,
12871553Srgrimes	const char *path, int mode)
12881553Srgrimes{
12891553Srgrimes	OVERLAY_CALL(create_symlink, name, path, mode)
1290241852Seadler}
129168401Sgad
1292241852Seadler
129327618Simpstatic status_t
12941553Srgrimesoverlay_link(fs_volume *volume, fs_vnode *vnode, const char *name,
12951553Srgrimes	fs_vnode *target)
12961553Srgrimes{
12971553Srgrimes	OverlayInode *targetNode = (OverlayInode *)target->private_node;
12981553Srgrimes	OVERLAY_CALL(link, name, targetNode->SuperVnode())
12991553Srgrimes}
13001553Srgrimes
13011553Srgrimes
130268401Sgadstatic status_t
13031553Srgrimesoverlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name)
13041553Srgrimes{
13051553Srgrimes	OVERLAY_CALL(unlink, name)
13061553Srgrimes}
13071553Srgrimes
13081553Srgrimes
13091553Srgrimesstatic status_t
131098152Sgadoverlay_rename(fs_volume *volume, fs_vnode *vnode,
131198152Sgad	const char *fromName, fs_vnode *toDir, const char *toName)
131298152Sgad{
131398152Sgad	OverlayInode *toDirNode = (OverlayInode *)toDir->private_node;
131498152Sgad	OVERLAY_CALL(rename, fromName, toDirNode->SuperVnode(), toName)
131598152Sgad}
131698152Sgad
131798152Sgad
131898152Sgadstatic status_t
131998152Sgadoverlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
132098152Sgad{
132198152Sgad	OVERLAY_CALL(access, mode)
132298152Sgad}
1323241852Seadler
132498152Sgad
1325241852Seadlerstatic status_t
132698152Sgadoverlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat)
132798152Sgad{
132898152Sgad	OVERLAY_CALL(read_stat, stat)
132998152Sgad}
133098152Sgad
1331
1332static status_t
1333overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat,
1334	uint32 statMask)
1335{
1336	OVERLAY_CALL(write_stat, stat, statMask)
1337}
1338
1339
1340static status_t
1341overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name,
1342	int openMode, int perms, void **cookie, ino_t *newVnodeID)
1343{
1344	OVERLAY_CALL(create, name, openMode, perms, cookie, newVnodeID)
1345}
1346
1347
1348static status_t
1349overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie)
1350{
1351	OVERLAY_CALL(open, openMode, cookie)
1352}
1353
1354
1355static status_t
1356overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie)
1357{
1358	OVERLAY_CALL(close, cookie)
1359}
1360
1361
1362static status_t
1363overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1364{
1365	OVERLAY_CALL(free_cookie, cookie)
1366}
1367
1368
1369static status_t
1370overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1371	void *buffer, size_t *length)
1372{
1373	OVERLAY_CALL(read, cookie, pos, buffer, length)
1374}
1375
1376
1377static status_t
1378overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1379	const void *buffer, size_t *length)
1380{
1381	OVERLAY_CALL(write, cookie, pos, buffer, length)
1382}
1383
1384
1385static status_t
1386overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name,
1387	int perms)
1388{
1389	OVERLAY_CALL(create_dir, name, perms)
1390}
1391
1392
1393static status_t
1394overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name)
1395{
1396	OVERLAY_CALL(remove_dir, name)
1397}
1398
1399
1400static status_t
1401overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
1402{
1403	OVERLAY_CALL(open_dir, cookie)
1404}
1405
1406
1407static status_t
1408overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1409{
1410	OVERLAY_CALL(close_dir, cookie)
1411}
1412
1413
1414static status_t
1415overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1416{
1417	OVERLAY_CALL(free_dir_cookie, cookie)
1418}
1419
1420
1421static status_t
1422overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
1423	struct dirent *buffer, size_t bufferSize, uint32 *num)
1424{
1425	TRACE("relaying op: read_dir\n");
1426	OverlayInode *node = (OverlayInode *)vnode->private_node;
1427	fs_vnode *superVnode = node->SuperVnode();
1428	if (superVnode->ops->read_dir != NULL) {
1429		status_t result = superVnode->ops->read_dir(volume->super_volume,
1430			superVnode, cookie, buffer, bufferSize, num);
1431
1432		// TODO: handle multiple records
1433		if (result == B_OK && *num == 1 && strcmp(buffer->d_name,
1434			ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) {
1435			// skip over the attribute directory
1436			return superVnode->ops->read_dir(volume->super_volume, superVnode,
1437				cookie, buffer, bufferSize, num);
1438		}
1439
1440		return result;
1441	}
1442
1443	return B_UNSUPPORTED;
1444}
1445
1446
1447static status_t
1448overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1449{
1450	OVERLAY_CALL(rewind_dir, cookie)
1451}
1452
1453
1454static status_t
1455overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
1456{
1457	OverlayInode *node = (OverlayInode *)vnode->private_node;
1458	AttributeFile *attributeFile = NULL;
1459	status_t result = node->GetAttributeFile(&attributeFile);
1460	if (result != B_OK)
1461		return result;
1462
1463	attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)malloc(
1464		sizeof(attribute_dir_cookie));
1465	if (dirCookie == NULL)
1466		return B_NO_MEMORY;
1467
1468	dirCookie->file = attributeFile;
1469	dirCookie->index = 0;
1470	*cookie = dirCookie;
1471	return B_OK;
1472}
1473
1474
1475static status_t
1476overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1477{
1478	return B_OK;
1479}
1480
1481
1482static status_t
1483overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1484{
1485	free(cookie);
1486	return B_OK;
1487}
1488
1489
1490static status_t
1491overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
1492	struct dirent *buffer, size_t bufferSize, uint32 *num)
1493{
1494	attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie;
1495	return dirCookie->file->ReadAttributeDir(buffer, bufferSize, num,
1496		&dirCookie->index);
1497}
1498
1499
1500static status_t
1501overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1502{
1503	attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie;
1504	dirCookie->index = 0;
1505	return B_OK;
1506}
1507
1508
1509static status_t
1510overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
1511	uint32 type, int openMode, void **cookie)
1512{
1513	OverlayInode *node = (OverlayInode *)vnode->private_node;
1514	AttributeFile *attributeFile = NULL;
1515	status_t result = node->GetAttributeFile(&attributeFile);
1516	if (result != B_OK)
1517		return result;
1518
1519	return attributeFile->CreateAttribute(name, type, openMode,
1520		(AttributeEntry **)cookie);
1521}
1522
1523
1524static status_t
1525overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
1526	int openMode, void **cookie)
1527{
1528	OverlayInode *node = (OverlayInode *)vnode->private_node;
1529	AttributeFile *attributeFile = NULL;
1530	status_t result = node->GetAttributeFile(&attributeFile);
1531	if (result != B_OK)
1532		return result;
1533
1534	return attributeFile->OpenAttribute(name, openMode,
1535		(AttributeEntry **)cookie);
1536}
1537
1538
1539static status_t
1540overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie)
1541{
1542	return B_OK;
1543}
1544
1545
1546static status_t
1547overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1548{
1549	return B_OK;
1550}
1551
1552
1553static status_t
1554overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1555	void *buffer, size_t *length)
1556{
1557	return ((AttributeEntry *)cookie)->Read(pos, buffer, length);
1558}
1559
1560
1561static status_t
1562overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1563	const void *buffer, size_t *length)
1564{
1565	return ((AttributeEntry *)cookie)->Write(pos, buffer, length);
1566}
1567
1568
1569static status_t
1570overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
1571	struct stat *stat)
1572{
1573	return ((AttributeEntry *)cookie)->ReadStat(stat);
1574}
1575
1576
1577static status_t
1578overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
1579	const struct stat *stat, int statMask)
1580{
1581	return ((AttributeEntry *)cookie)->WriteStat(stat, statMask);
1582}
1583
1584
1585static status_t
1586overlay_rename_attr(fs_volume *volume, fs_vnode *vnode,
1587	const char *fromName, fs_vnode *toVnode, const char *toName)
1588{
1589	OverlayInode *node = (OverlayInode *)vnode->private_node;
1590	AttributeFile *attributeFile = NULL;
1591	status_t result = node->GetAttributeFile(&attributeFile);
1592	if (result != B_OK)
1593		return B_OK;
1594
1595	AttributeFile *toAttributeFile = attributeFile;
1596	if (vnode->private_node != toVnode->private_node) {
1597		OverlayInode *toNode = (OverlayInode *)toVnode->private_node;
1598		result = toNode->GetAttributeFile(&toAttributeFile);
1599		if (result != B_OK)
1600			return result;
1601	}
1602
1603	AttributeEntry *entry = NULL;
1604	result = attributeFile->RemoveAttribute(fromName, &entry);
1605	if (result != B_OK)
1606		return result;
1607
1608	result = entry->SetName(toName);
1609	if (result != B_OK) {
1610		if (attributeFile->AddAttribute(entry) != B_OK)
1611			delete entry;
1612		return result;
1613	}
1614
1615	result = toAttributeFile->AddAttribute(entry);
1616	if (result != B_OK) {
1617		if (entry->SetName(fromName) != B_OK
1618			|| attributeFile->AddAttribute(entry) != B_OK)
1619			delete entry;
1620		return result;
1621	}
1622
1623	return B_OK;
1624}
1625
1626
1627static status_t
1628overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name)
1629{
1630	OverlayInode *node = (OverlayInode *)vnode->private_node;
1631	AttributeFile *attributeFile = NULL;
1632	status_t result = node->GetAttributeFile(&attributeFile);
1633	if (result != B_OK)
1634		return result;
1635
1636	return attributeFile->RemoveAttribute(name, NULL);
1637}
1638
1639
1640static status_t
1641overlay_create_special_node(fs_volume *volume, fs_vnode *vnode,
1642	const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags,
1643	fs_vnode *_superVnode, ino_t *nodeID)
1644{
1645	OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode,
1646		nodeID)
1647}
1648
1649
1650static fs_vnode_ops sOverlayVnodeOps = {
1651	&overlay_lookup,
1652	&overlay_get_vnode_name,
1653
1654	&overlay_put_vnode,
1655	&overlay_remove_vnode,
1656
1657	&overlay_can_page,
1658	&overlay_read_pages,
1659	&overlay_write_pages,
1660
1661	&overlay_io,
1662	&overlay_cancel_io,
1663
1664	&overlay_get_file_map,
1665
1666	/* common */
1667	&overlay_ioctl,
1668	&overlay_set_flags,
1669	&overlay_select,
1670	&overlay_deselect,
1671	&overlay_fsync,
1672
1673	&overlay_read_symlink,
1674	&overlay_create_symlink,
1675	&overlay_link,
1676	&overlay_unlink,
1677	&overlay_rename,
1678
1679	&overlay_access,
1680	&overlay_read_stat,
1681	&overlay_write_stat,
1682	NULL,	// fs_preallocate
1683
1684	/* file */
1685	&overlay_create,
1686	&overlay_open,
1687	&overlay_close,
1688	&overlay_free_cookie,
1689	&overlay_read,
1690	&overlay_write,
1691
1692	/* directory */
1693	&overlay_create_dir,
1694	&overlay_remove_dir,
1695	&overlay_open_dir,
1696	&overlay_close_dir,
1697	&overlay_free_dir_cookie,
1698	&overlay_read_dir,
1699	&overlay_rewind_dir,
1700
1701	/* attribute directory operations */
1702	&overlay_open_attr_dir,
1703	&overlay_close_attr_dir,
1704	&overlay_free_attr_dir_cookie,
1705	&overlay_read_attr_dir,
1706	&overlay_rewind_attr_dir,
1707
1708	/* attribute operations */
1709	&overlay_create_attr,
1710	&overlay_open_attr,
1711	&overlay_close_attr,
1712	&overlay_free_attr_cookie,
1713	&overlay_read_attr,
1714	&overlay_write_attr,
1715
1716	&overlay_read_attr_stat,
1717	&overlay_write_attr_stat,
1718	&overlay_rename_attr,
1719	&overlay_remove_attr,
1720
1721	/* support for node and FS layers */
1722	&overlay_create_special_node,
1723	&overlay_get_super_vnode
1724};
1725
1726
1727//	#pragma mark - volume ops
1728
1729
1730static status_t
1731overlay_unmount(fs_volume *volume)
1732{
1733	TRACE_VOLUME("relaying volume op: unmount\n");
1734	if (volume->super_volume != NULL
1735		&& volume->super_volume->ops != NULL
1736		&& volume->super_volume->ops->unmount != NULL)
1737		volume->super_volume->ops->unmount(volume->super_volume);
1738
1739	delete (OverlayVolume *)volume->private_volume;
1740	return B_OK;
1741}
1742
1743
1744static status_t
1745overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
1746{
1747	TRACE_VOLUME("relaying volume op: read_fs_info\n");
1748	status_t result = B_UNSUPPORTED;
1749	if (volume->super_volume->ops->read_fs_info != NULL) {
1750		result = volume->super_volume->ops->read_fs_info(volume->super_volume,
1751			info);
1752		if (result != B_OK)
1753			return result;
1754
1755		info->flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR /*| B_FS_HAS_QUERY*/;
1756		return B_OK;
1757	}
1758
1759	return B_UNSUPPORTED;
1760}
1761
1762
1763static status_t
1764overlay_write_fs_info(fs_volume *volume, const struct fs_info *info,
1765	uint32 mask)
1766{
1767	OVERLAY_VOLUME_CALL(write_fs_info, info, mask)
1768	return B_UNSUPPORTED;
1769}
1770
1771
1772static status_t
1773overlay_sync(fs_volume *volume)
1774{
1775	TRACE_VOLUME("relaying volume op: sync\n");
1776	if (volume->super_volume->ops->sync != NULL)
1777		return volume->super_volume->ops->sync(volume->super_volume);
1778	return B_UNSUPPORTED;
1779}
1780
1781
1782static status_t
1783overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type,
1784	uint32 *_flags, bool reenter)
1785{
1786	TRACE_VOLUME("relaying volume op: get_vnode\n");
1787	if (volume->super_volume->ops->get_vnode != NULL) {
1788		status_t status = volume->super_volume->ops->get_vnode(
1789			volume->super_volume, id, vnode, _type, _flags, reenter);
1790		if (status != B_OK)
1791			return status;
1792
1793		OverlayInode *node = new(std::nothrow) OverlayInode(
1794			(OverlayVolume *)volume->private_volume, vnode, id);
1795		if (node == NULL) {
1796			vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
1797			return B_NO_MEMORY;
1798		}
1799
1800		status = node->InitCheck();
1801		if (status != B_OK) {
1802			vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
1803			delete node;
1804			return status;
1805		}
1806
1807		vnode->private_node = node;
1808		vnode->ops = &sOverlayVnodeOps;
1809		return B_OK;
1810	}
1811
1812	return B_UNSUPPORTED;
1813}
1814
1815
1816static status_t
1817overlay_open_index_dir(fs_volume *volume, void **cookie)
1818{
1819	OVERLAY_VOLUME_CALL(open_index_dir, cookie)
1820	return B_UNSUPPORTED;
1821}
1822
1823
1824static status_t
1825overlay_close_index_dir(fs_volume *volume, void *cookie)
1826{
1827	OVERLAY_VOLUME_CALL(close_index_dir, cookie)
1828	return B_UNSUPPORTED;
1829}
1830
1831
1832static status_t
1833overlay_free_index_dir_cookie(fs_volume *volume, void *cookie)
1834{
1835	OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie)
1836	return B_UNSUPPORTED;
1837}
1838
1839
1840static status_t
1841overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer,
1842	size_t bufferSize, uint32 *_num)
1843{
1844	OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num)
1845	return B_UNSUPPORTED;
1846}
1847
1848
1849static status_t
1850overlay_rewind_index_dir(fs_volume *volume, void *cookie)
1851{
1852	OVERLAY_VOLUME_CALL(rewind_index_dir, cookie)
1853	return B_UNSUPPORTED;
1854}
1855
1856
1857static status_t
1858overlay_create_index(fs_volume *volume, const char *name, uint32 type,
1859	uint32 flags)
1860{
1861	OVERLAY_VOLUME_CALL(create_index, name, type, flags)
1862	return B_UNSUPPORTED;
1863}
1864
1865
1866static status_t
1867overlay_remove_index(fs_volume *volume, const char *name)
1868{
1869	OVERLAY_VOLUME_CALL(remove_index, name)
1870	return B_UNSUPPORTED;
1871}
1872
1873
1874static status_t
1875overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat)
1876{
1877	OVERLAY_VOLUME_CALL(read_index_stat, name, stat)
1878	return B_UNSUPPORTED;
1879}
1880
1881
1882static status_t
1883overlay_open_query(fs_volume *volume, const char *query, uint32 flags,
1884	port_id port, uint32 token, void **_cookie)
1885{
1886	OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie)
1887	return B_UNSUPPORTED;
1888}
1889
1890
1891static status_t
1892overlay_close_query(fs_volume *volume, void *cookie)
1893{
1894	OVERLAY_VOLUME_CALL(close_query, cookie)
1895	return B_UNSUPPORTED;
1896}
1897
1898
1899static status_t
1900overlay_free_query_cookie(fs_volume *volume, void *cookie)
1901{
1902	OVERLAY_VOLUME_CALL(free_query_cookie, cookie)
1903	return B_UNSUPPORTED;
1904}
1905
1906
1907static status_t
1908overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer,
1909	size_t bufferSize, uint32 *_num)
1910{
1911	OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num)
1912	return B_UNSUPPORTED;
1913}
1914
1915
1916static status_t
1917overlay_rewind_query(fs_volume *volume, void *cookie)
1918{
1919	OVERLAY_VOLUME_CALL(rewind_query, cookie)
1920	return B_UNSUPPORTED;
1921}
1922
1923
1924static status_t
1925overlay_all_layers_mounted(fs_volume *volume)
1926{
1927	return B_OK;
1928}
1929
1930
1931static status_t
1932overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode)
1933{
1934	OverlayInode *node = new(std::nothrow) OverlayInode(
1935		(OverlayVolume *)volume->private_volume, vnode, id);
1936	if (node == NULL)
1937		return B_NO_MEMORY;
1938
1939	status_t status = node->InitCheck();
1940	if (status != B_OK) {
1941		delete node;
1942		return status;
1943	}
1944
1945	vnode->private_node = node;
1946	vnode->ops = &sOverlayVnodeOps;
1947	return B_OK;
1948}
1949
1950
1951static status_t
1952overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode)
1953{
1954	delete (OverlayInode *)vnode->private_node;
1955	return B_OK;
1956}
1957
1958
1959static fs_volume_ops sOverlayVolumeOps = {
1960	&overlay_unmount,
1961
1962	&overlay_read_fs_info,
1963	&overlay_write_fs_info,
1964	&overlay_sync,
1965
1966	&overlay_get_vnode,
1967	&overlay_open_index_dir,
1968	&overlay_close_index_dir,
1969	&overlay_free_index_dir_cookie,
1970	&overlay_read_index_dir,
1971	&overlay_rewind_index_dir,
1972
1973	&overlay_create_index,
1974	&overlay_remove_index,
1975	&overlay_read_index_stat,
1976
1977	&overlay_open_query,
1978	&overlay_close_query,
1979	&overlay_free_query_cookie,
1980	&overlay_read_query,
1981	&overlay_rewind_query,
1982
1983	&overlay_all_layers_mounted,
1984	&overlay_create_sub_vnode,
1985	&overlay_delete_sub_vnode
1986};
1987
1988
1989//	#pragma mark - filesystem module
1990
1991
1992static status_t
1993overlay_mount(fs_volume *volume, const char *device, uint32 flags,
1994	const char *args, ino_t *rootID)
1995{
1996	TRACE_VOLUME("mounting attribute overlay\n");
1997	volume->private_volume = new(std::nothrow) OverlayVolume(volume);
1998	if (volume->private_volume == NULL)
1999		return B_NO_MEMORY;
2000
2001	volume->ops = &sOverlayVolumeOps;
2002	return B_OK;
2003}
2004
2005
2006static status_t
2007overlay_std_ops(int32 op, ...)
2008{
2009	switch (op) {
2010		case B_MODULE_INIT:
2011		case B_MODULE_UNINIT:
2012			return B_OK;
2013		default:
2014			return B_ERROR;
2015	}
2016}
2017
2018
2019static file_system_module_info sOverlayFileSystem = {
2020	{
2021		"file_systems/attribute_overlay" B_CURRENT_FS_API_VERSION,
2022		0,
2023		overlay_std_ops,
2024	},
2025
2026	"attribute_overlay",				// short_name
2027	"Attribute Overlay File System",	// pretty_name
2028	0,									// DDM flags
2029
2030	// scanning
2031	NULL, // identify_partition
2032	NULL, // scan_partition
2033	NULL, // free_identify_partition_cookie
2034	NULL, // free_partition_content_cookie
2035
2036	// general operations
2037	&overlay_mount,
2038
2039	// capability querying
2040	NULL, // get_supported_operations
2041
2042	NULL, // validate_resize
2043	NULL, // validate_move
2044	NULL, // validate_set_content_name
2045	NULL, // validate_set_content_parameters
2046	NULL, // validate_initialize
2047
2048	// shadow partition modification
2049	NULL, // shadow_changed
2050
2051	// writing
2052	NULL, // defragment
2053	NULL, // repair
2054	NULL, // resize
2055	NULL, // move
2056	NULL, // set_content_name
2057	NULL, // set_content_parameters
2058	NULL // initialize
2059};
2060
2061}	// namespace attribute_overlay
2062
2063using namespace attribute_overlay;
2064
2065module_info *modules[] = {
2066	(module_info *)&sOverlayFileSystem,
2067	NULL,
2068};
2069