1/*
2 * Copyright 2009-2016, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Lotz <mmlr@mlotz.ch>
7 */
8
9
10#include <new>
11#include <stdlib.h>
12#include <string.h>
13
14#include <dirent.h>
15
16#include <util/kernel_cpp.h>
17
18#include <fs_info.h>
19#include <fs_interface.h>
20
21#include <debug.h>
22#include <KernelExport.h>
23#include <NodeMonitor.h>
24
25
26//#define TRACE_OVERLAY
27#ifdef TRACE_OVERLAY
28#	define TRACE(x...)			dprintf("attribute_overlay: " x)
29#	define TRACE_VOLUME(x...)	dprintf("attribute_overlay: " x)
30#	define TRACE_ALWAYS(x...)	dprintf("attribute_overlay: " x)
31#else
32#	define TRACE(x...)			/* nothing */
33#	define TRACE_VOLUME(x...)	/* nothing */
34#	define TRACE_ALWAYS(x...)	dprintf("attribute_overlay: " x)
35#endif
36
37
38#define ATTRIBUTE_OVERLAY_FILE_MAGIC			'attr'
39#define ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME	"_HAIKU"
40
41
42#define OVERLAY_CALL(op, params...) \
43	TRACE("relaying op: " #op "\n"); \
44	OverlayInode *node = (OverlayInode *)vnode->private_node; \
45	fs_vnode *superVnode = node->SuperVnode(); \
46	if (superVnode->ops->op != NULL) \
47		return superVnode->ops->op(volume->super_volume, superVnode, params); \
48	return B_UNSUPPORTED;
49
50
51#define OVERLAY_VOLUME_CALL(op, params...) \
52	TRACE_VOLUME("relaying volume op: " #op "\n"); \
53	if (volume->super_volume->ops->op != NULL) \
54		return volume->super_volume->ops->op(volume->super_volume, params);
55
56
57namespace attribute_overlay {
58
59class AttributeFile;
60class AttributeEntry;
61
62
63struct attribute_dir_cookie {
64	AttributeFile *	file;
65	uint32			index;
66};
67
68
69class OverlayVolume {
70public:
71							OverlayVolume(fs_volume *volume);
72							~OverlayVolume();
73
74		fs_volume *			Volume() { return fVolume; }
75		fs_volume *			SuperVolume() { return fVolume->super_volume; }
76
77private:
78		fs_volume *			fVolume;
79};
80
81
82class OverlayInode {
83public:
84							OverlayInode(OverlayVolume *volume,
85								fs_vnode *superVnode, ino_t inodeNumber);
86							~OverlayInode();
87
88		status_t			InitCheck();
89
90		fs_volume *			Volume() { return fVolume->Volume(); }
91		fs_volume *			SuperVolume() { return fVolume->SuperVolume(); }
92		fs_vnode *			SuperVnode() { return &fSuperVnode; }
93		ino_t				InodeNumber() { return fInodeNumber; }
94
95		status_t			GetAttributeFile(AttributeFile **attributeFile);
96		status_t			WriteAttributeFile();
97		status_t			RemoveAttributeFile();
98
99private:
100		OverlayVolume *		fVolume;
101		fs_vnode			fSuperVnode;
102		ino_t				fInodeNumber;
103		AttributeFile *		fAttributeFile;
104};
105
106
107class AttributeFile {
108public:
109								AttributeFile(fs_volume *overlay,
110									fs_volume *volume, fs_vnode *vnode);
111								~AttributeFile();
112
113			status_t			InitCheck() { return fStatus; }
114
115			dev_t				VolumeID() { return fVolumeID; }
116			ino_t				FileInode() { return fFileInode; }
117
118			status_t			CreateEmpty();
119			status_t			WriteAttributeFile(fs_volume *overlay,
120									fs_volume *volume, fs_vnode *vnode);
121			status_t			RemoveAttributeFile(fs_volume *overlay,
122									fs_volume *volume, fs_vnode *vnode);
123
124			status_t			ReadAttributeDir(struct dirent *dirent,
125									size_t bufferSize, uint32 *numEntries,
126									uint32 *index);
127
128			uint32				CountAttributes();
129			AttributeEntry *	FindAttribute(const char *name,
130									uint32 *index = NULL);
131
132			status_t			CreateAttribute(const char *name, type_code type,
133									int openMode, AttributeEntry **entry);
134			status_t			OpenAttribute(const char *name, int openMode,
135									AttributeEntry **entry);
136			status_t			RemoveAttribute(const char *name,
137									AttributeEntry **entry);
138			status_t			AddAttribute(AttributeEntry *entry);
139
140private:
141			struct attribute_file {
142				uint32			magic;
143					// ATTRIBUTE_OVERLAY_FILE_MAGIC
144				uint32			entry_count;
145				uint8			entries[1];
146			} _PACKED;
147
148			status_t			fStatus;
149			dev_t				fVolumeID;
150			ino_t				fFileInode;
151			ino_t				fDirectoryInode;
152			ino_t				fAttributeDirInode;
153			ino_t				fAttributeFileInode;
154			attribute_file *	fFile;
155			uint32				fAttributeDirIndex;
156			AttributeEntry **	fEntries;
157};
158
159
160class AttributeEntry {
161public:
162								AttributeEntry(AttributeFile *parent,
163									uint8 *buffer);
164								AttributeEntry(AttributeFile *parent,
165									const char *name, type_code type);
166								~AttributeEntry();
167
168			status_t			InitCheck() { return fStatus; }
169
170			uint8 *				Entry() { return (uint8 *)fEntry; }
171			size_t				EntrySize();
172			uint8 *				Data() { return fData; }
173			size_t				DataSize() { return fEntry->size; }
174
175			status_t			SetType(type_code type);
176			type_code			Type() { return fEntry->type; }
177
178			status_t			SetSize(size_t size);
179			uint32				Size() { return fEntry->size; }
180
181			status_t			SetName(const char *name);
182			const char *		Name() { return fEntry->name; }
183			uint8				NameLength() { return fEntry->name_length; }
184
185			status_t			FillDirent(struct dirent *dirent,
186									size_t bufferSize, uint32 *numEntries);
187
188			status_t			Read(off_t position, void *buffer,
189									size_t *length);
190			status_t			Write(off_t position, const void *buffer,
191									size_t *length);
192
193			status_t			ReadStat(struct stat *stat);
194			status_t			WriteStat(const struct stat *stat,
195									uint32 statMask);
196
197private:
198			struct attribute_entry {
199				type_code		type;
200				uint32			size;
201				uint8			name_length; // including 0 byte
202				char			name[]; // 0 terminated, followed by data
203			} _PACKED;
204
205			AttributeFile *		fParent;
206			attribute_entry *	fEntry;
207			uint8 *				fData;
208			status_t			fStatus;
209			bool				fAllocatedEntry;
210			bool				fAllocatedData;
211};
212
213
214//	#pragma mark OverlayVolume
215
216
217OverlayVolume::OverlayVolume(fs_volume *volume)
218	:
219	fVolume(volume)
220{
221}
222
223
224OverlayVolume::~OverlayVolume()
225{
226}
227
228
229//	#pragma mark OverlayInode
230
231
232OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode,
233	ino_t inodeNumber)
234	:
235	fVolume(volume),
236	fSuperVnode(*superVnode),
237	fInodeNumber(inodeNumber),
238	fAttributeFile(NULL)
239{
240	TRACE("inode created\n");
241}
242
243
244OverlayInode::~OverlayInode()
245{
246	TRACE("inode destroyed\n");
247	delete fAttributeFile;
248}
249
250
251status_t
252OverlayInode::InitCheck()
253{
254	return B_OK;
255}
256
257
258status_t
259OverlayInode::GetAttributeFile(AttributeFile **attributeFile)
260{
261	if (fAttributeFile == NULL) {
262		fAttributeFile = new(std::nothrow) AttributeFile(Volume(),
263			SuperVolume(), &fSuperVnode);
264		if (fAttributeFile == NULL) {
265			TRACE_ALWAYS("no memory to allocate attribute file\n");
266			return B_NO_MEMORY;
267		}
268	}
269
270	status_t result = fAttributeFile->InitCheck();
271	if (result != B_OK) {
272		if (result == B_ENTRY_NOT_FOUND) {
273			// TODO: need to check if we're able to create the file
274			// but at least allow virtual attributes for now
275		}
276
277		result = fAttributeFile->CreateEmpty();
278		if (result != B_OK)
279			return result;
280	}
281
282	*attributeFile = fAttributeFile;
283	return B_OK;
284}
285
286
287status_t
288OverlayInode::WriteAttributeFile()
289{
290	if (fAttributeFile == NULL)
291		return B_NO_INIT;
292
293	status_t result = fAttributeFile->InitCheck();
294	if (result != B_OK)
295		return result;
296
297	return fAttributeFile->WriteAttributeFile(Volume(), SuperVolume(),
298		&fSuperVnode);
299}
300
301
302status_t
303OverlayInode::RemoveAttributeFile()
304{
305	if (fAttributeFile == NULL)
306		return B_NO_INIT;
307
308	status_t result = fAttributeFile->InitCheck();
309	if (result != B_OK)
310		return result;
311
312	return fAttributeFile->RemoveAttributeFile(Volume(), SuperVolume(),
313		&fSuperVnode);
314}
315
316
317//	#pragma mark AttributeFile
318
319
320AttributeFile::AttributeFile(fs_volume *overlay, fs_volume *volume,
321	fs_vnode *vnode)
322	:
323	fStatus(B_NO_INIT),
324	fVolumeID(volume->id),
325	fFileInode(0),
326	fDirectoryInode(0),
327	fAttributeDirInode(0),
328	fAttributeFileInode(0),
329	fFile(NULL),
330	fAttributeDirIndex(0),
331	fEntries(NULL)
332{
333	if (vnode->ops->get_vnode_name == NULL) {
334		TRACE_ALWAYS("cannot get vnode name, hook missing\n");
335		fStatus = B_UNSUPPORTED;
336		return;
337	}
338
339	char nameBuffer[B_FILE_NAME_LENGTH];
340	nameBuffer[sizeof(nameBuffer) - 1] = 0;
341	fStatus = vnode->ops->get_vnode_name(volume, vnode, nameBuffer,
342		sizeof(nameBuffer) - 1);
343	if (fStatus != B_OK) {
344		TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(fStatus));
345		return;
346	}
347
348	if (strcmp(nameBuffer, ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) {
349		// we don't want attribute overlays on the attribute dir itself
350		fStatus = B_UNSUPPORTED;
351		return;
352	}
353
354	struct stat stat;
355	if (vnode->ops->read_stat != NULL
356		&& vnode->ops->read_stat(volume, vnode, &stat) == B_OK) {
357		fFileInode = stat.st_ino;
358	}
359
360	// TODO: the ".." lookup is not actually valid for non-directory vnodes.
361	// we make use of the fact that a filesystem probably still provides the
362	// lookup hook and has hardcoded ".." to resolve to the parent entry. if we
363	// wanted to do this correctly we need some other way to relate this vnode
364	// to its parent directory vnode.
365	const char *lookup[]
366		= { "..", ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, nameBuffer };
367	int32 lookupCount = sizeof(lookup) / sizeof(lookup[0]);
368	fs_vnode currentVnode = *vnode;
369	ino_t lastInodeNumber = 0;
370
371	for (int32 i = 0; i < lookupCount; i++) {
372		if (currentVnode.ops->lookup == NULL) {
373			TRACE_ALWAYS("lookup not possible, lookup hook missing\n");
374			fStatus = B_UNSUPPORTED;
375			if (i > 0)
376				put_vnode(volume, lastInodeNumber);
377			return;
378		}
379
380		ino_t inodeNumber;
381		fStatus = currentVnode.ops->lookup(volume, &currentVnode, lookup[i],
382			&inodeNumber);
383
384		if (i > 0)
385			put_vnode(volume, lastInodeNumber);
386
387		if (fStatus != B_OK) {
388			if (fStatus != B_ENTRY_NOT_FOUND) {
389				TRACE_ALWAYS("lookup of \"%s\" failed: %s\n", lookup[i],
390					strerror(fStatus));
391			}
392			return;
393		}
394
395		if (i == 0)
396			fDirectoryInode = inodeNumber;
397		else if (i == 1)
398			fAttributeDirInode = inodeNumber;
399		else if (i == 2)
400			fAttributeFileInode = inodeNumber;
401
402		OverlayInode *overlayInode = NULL;
403		fStatus = get_vnode(overlay, inodeNumber, (void **)&overlayInode);
404		if (fStatus != B_OK) {
405			TRACE_ALWAYS("getting vnode failed: %s\n", strerror(fStatus));
406			return;
407		}
408
409		currentVnode = *overlayInode->SuperVnode();
410		lastInodeNumber = inodeNumber;
411	}
412
413	if (currentVnode.ops->read_stat == NULL || currentVnode.ops->open == NULL
414		|| currentVnode.ops->read == NULL) {
415		TRACE_ALWAYS("can't use attribute file, hooks missing\n");
416		put_vnode(volume, lastInodeNumber);
417		fStatus = B_UNSUPPORTED;
418		return;
419	}
420
421	fStatus = currentVnode.ops->read_stat(volume, &currentVnode, &stat);
422	if (fStatus != B_OK) {
423		TRACE_ALWAYS("failed to stat attribute file: %s\n", strerror(fStatus));
424		put_vnode(volume, lastInodeNumber);
425		return;
426	}
427
428	void *attrFileCookie = NULL;
429	fStatus = currentVnode.ops->open(volume, &currentVnode, O_RDONLY,
430		&attrFileCookie);
431	if (fStatus != B_OK) {
432		TRACE_ALWAYS("failed to open attribute file: %s\n", strerror(fStatus));
433		put_vnode(volume, lastInodeNumber);
434		return;
435	}
436
437	size_t readLength = stat.st_size;
438	uint8 *buffer = (uint8 *)malloc(readLength);
439	if (buffer == NULL) {
440		TRACE_ALWAYS("cannot allocate memory for read buffer\n");
441		put_vnode(volume, lastInodeNumber);
442		fStatus = B_NO_MEMORY;
443		return;
444	}
445
446	fStatus = currentVnode.ops->read(volume, &currentVnode, attrFileCookie, 0,
447		buffer, &readLength);
448	if (fStatus != B_OK) {
449		TRACE_ALWAYS("failed to read from file: %s\n", strerror(fStatus));
450		put_vnode(volume, lastInodeNumber);
451		return;
452	}
453
454	if (currentVnode.ops->close != NULL)
455		currentVnode.ops->close(volume, &currentVnode, attrFileCookie);
456	if (currentVnode.ops->free_cookie != NULL)
457		currentVnode.ops->free_cookie(volume, &currentVnode, attrFileCookie);
458
459	put_vnode(volume, lastInodeNumber);
460
461	fFile = (attribute_file *)buffer;
462	if (fFile->magic != ATTRIBUTE_OVERLAY_FILE_MAGIC) {
463		TRACE_ALWAYS("attribute file has bad magic\n");
464		fStatus = B_BAD_VALUE;
465		return;
466	}
467
468	fEntries = (AttributeEntry **)malloc(fFile->entry_count
469		* sizeof(AttributeEntry *));
470	if (fEntries == NULL) {
471		TRACE_ALWAYS("no memory to allocate entry pointers\n");
472		fStatus = B_NO_MEMORY;
473		return;
474	}
475
476	for (uint32 i = 0; i < fFile->entry_count; i++)
477		fEntries[i] = NULL;
478
479	size_t totalSize = 0;
480	readLength -= sizeof(attribute_file) - 1;
481	for (uint32 i = 0; i < fFile->entry_count; i++) {
482		fEntries[i] = new(std::nothrow) AttributeEntry(this,
483			fFile->entries + totalSize);
484		if (fEntries[i] == NULL) {
485			TRACE_ALWAYS("no memory to allocate attribute entry\n");
486			fStatus = B_NO_MEMORY;
487			return;
488		}
489
490		totalSize += fEntries[i]->EntrySize() + fEntries[i]->DataSize();
491		if (totalSize > readLength) {
492			TRACE_ALWAYS("attribute entries are too large for buffer\n");
493			fStatus = B_BAD_VALUE;
494			return;
495		}
496	}
497}
498
499
500AttributeFile::~AttributeFile()
501{
502	if (fFile == NULL)
503		return;
504
505	if (fEntries != NULL) {
506		for (uint32 i = 0; i < fFile->entry_count; i++)
507			delete fEntries[i];
508
509		free(fEntries);
510	}
511
512	free(fFile);
513}
514
515
516status_t
517AttributeFile::CreateEmpty()
518{
519	if (fFile == NULL) {
520		fFile = (attribute_file *)malloc(sizeof(attribute_file) - 1);
521		if (fFile == NULL) {
522			TRACE_ALWAYS("failed to allocate file buffer\n");
523			fStatus = B_NO_MEMORY;
524			return fStatus;
525		}
526
527		fFile->entry_count = 0;
528		fFile->magic = ATTRIBUTE_OVERLAY_FILE_MAGIC;
529	}
530
531	fStatus = B_OK;
532	return B_OK;
533}
534
535
536status_t
537AttributeFile::WriteAttributeFile(fs_volume *overlay, fs_volume *volume,
538	fs_vnode *vnode)
539{
540	if (fFile == NULL)
541		return B_NO_INIT;
542
543	char nameBuffer[B_FILE_NAME_LENGTH];
544	nameBuffer[sizeof(nameBuffer) - 1] = 0;
545	status_t result = vnode->ops->get_vnode_name(volume, vnode, nameBuffer,
546		sizeof(nameBuffer) - 1);
547	if (result != B_OK) {
548		TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result));
549		return result;
550	}
551
552	fs_vnode currentVnode = *vnode;
553	if (fDirectoryInode == 0) {
554		if (currentVnode.ops->lookup == NULL) {
555			TRACE_ALWAYS("lookup not possible, lookup hook missing\n");
556			return B_UNSUPPORTED;
557		}
558
559		// see TODO above
560		result = currentVnode.ops->lookup(volume, &currentVnode, "..",
561			&fDirectoryInode);
562		if (result != B_OK) {
563			TRACE_ALWAYS("lookup of parent directory failed: %s\n",
564				strerror(result));
565			return B_UNSUPPORTED;
566		}
567
568		put_vnode(volume, fDirectoryInode);
569	}
570
571	OverlayInode *overlayInode = NULL;
572	if (fAttributeDirInode == 0) {
573		result = get_vnode(overlay, fDirectoryInode, (void **)&overlayInode);
574		if (result != B_OK) {
575			TRACE_ALWAYS("failed to get directory vnode: %s\n",
576				strerror(result));
577			return result;
578		}
579
580		currentVnode = *overlayInode->SuperVnode();
581
582		// create the attribute directory
583		result = currentVnode.ops->create_dir(volume, &currentVnode,
584			ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, S_IRWXU | S_IRWXG | S_IRWXO);
585
586		if (result == B_OK) {
587			result = currentVnode.ops->lookup(volume, &currentVnode,
588				ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, &fAttributeDirInode);
589
590			// lookup() got us a reference we don't need -- put it
591			if (result == B_OK)
592				put_vnode(volume, fAttributeDirInode);
593		}
594
595		put_vnode(volume, fDirectoryInode);
596
597		if (result != B_OK) {
598			TRACE_ALWAYS("failed to create attribute directory: %s\n",
599				strerror(result));
600			fAttributeDirInode = 0;
601			return result;
602		}
603	}
604
605	void *attrFileCookie = NULL;
606	if (fAttributeFileInode == 0) {
607		result = get_vnode(overlay, fAttributeDirInode, (void **)&overlayInode);
608		if (result != B_OK) {
609			TRACE_ALWAYS("failed to get attribute directory vnode: %s\n",
610				strerror(result));
611			return result;
612		}
613
614		currentVnode = *overlayInode->SuperVnode();
615
616		// create the attribute file
617		result = currentVnode.ops->create(volume, &currentVnode,
618			nameBuffer, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP
619			| S_IWGRP | S_IROTH | S_IWOTH, &attrFileCookie,
620			&fAttributeFileInode);
621
622		put_vnode(volume, fAttributeDirInode);
623
624		if (result != B_OK) {
625			TRACE_ALWAYS("failed to create attribute file: %s\n",
626				strerror(result));
627			return result;
628		}
629
630		result = get_vnode(overlay, fAttributeFileInode,
631			(void **)&overlayInode);
632		if (result != B_OK) {
633			TRACE_ALWAYS("getting attribute file vnode after create failed: "
634				"%s\n", strerror(result));
635			return result;
636		}
637
638		currentVnode = *overlayInode->SuperVnode();
639	} else {
640		result = get_vnode(overlay, fAttributeFileInode,
641			(void **)&overlayInode);
642		if (result != B_OK) {
643			TRACE_ALWAYS("getting attribute file vnode failed: %s\n",
644				strerror(result));
645			return result;
646		}
647
648		currentVnode = *overlayInode->SuperVnode();
649
650		// open the attribute file
651		result = currentVnode.ops->open(volume, &currentVnode, O_RDWR | O_TRUNC,
652			&attrFileCookie);
653		if (result != B_OK) {
654			TRACE_ALWAYS("failed to open attribute file for writing: %s\n",
655				strerror(result));
656			put_vnode(volume, fAttributeFileInode);
657			return result;
658		}
659	}
660
661	off_t position = 0;
662	size_t writeLength = sizeof(attribute_file) - 1;
663	result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
664		position, fFile, &writeLength);
665	if (result != B_OK) {
666		TRACE_ALWAYS("failed to write to attribute file: %s\n",
667			strerror(result));
668		goto close_and_put;
669	}
670
671	for (uint32 i = 0; i < fFile->entry_count; i++) {
672		writeLength = fEntries[i]->EntrySize();
673		result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
674			position, fEntries[i]->Entry(), &writeLength);
675		if (result != B_OK) {
676			TRACE_ALWAYS("failed to write to attribute file: %s\n",
677				strerror(result));
678			goto close_and_put;
679		}
680
681		writeLength = fEntries[i]->DataSize();
682		result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
683			position, fEntries[i]->Data(), &writeLength);
684		if (result != B_OK) {
685			TRACE_ALWAYS("failed to write to attribute file: %s\n",
686				strerror(result));
687			goto close_and_put;
688		}
689	}
690
691close_and_put:
692	if (currentVnode.ops->close != NULL)
693		currentVnode.ops->close(volume, &currentVnode, attrFileCookie);
694	if (currentVnode.ops->free_cookie != NULL)
695		currentVnode.ops->free_cookie(volume, &currentVnode, attrFileCookie);
696
697	put_vnode(volume, fAttributeFileInode);
698	return B_OK;
699}
700
701
702status_t
703AttributeFile::RemoveAttributeFile(fs_volume *overlay, fs_volume *volume,
704	fs_vnode *vnode)
705{
706	bool hasAttributeFile = fAttributeFileInode != 0;
707	ino_t attributeDirInode = fAttributeDirInode;
708
709	// invalidate all of our cached inode numbers
710	fDirectoryInode = 0;
711	fAttributeDirInode = 0;
712	fAttributeFileInode = 0;
713
714	if (!hasAttributeFile) {
715		// there is no backing file at all yet
716		return B_OK;
717	}
718
719	char nameBuffer[B_FILE_NAME_LENGTH];
720	nameBuffer[sizeof(nameBuffer) - 1] = 0;
721	status_t result = vnode->ops->get_vnode_name(volume, vnode, nameBuffer,
722		sizeof(nameBuffer) - 1);
723	if (result != B_OK) {
724		TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result));
725		return result;
726	}
727
728	OverlayInode *overlayInode = NULL;
729	result = get_vnode(overlay, attributeDirInode, (void **)&overlayInode);
730	if (result != B_OK) {
731		TRACE_ALWAYS("getting attribute directory vnode failed: %s\n",
732			strerror(result));
733		return result;
734	}
735
736	fs_vnode attributeDir = *overlayInode->SuperVnode();
737	if (attributeDir.ops->unlink == NULL) {
738		TRACE_ALWAYS("cannot remove attribute file, unlink hook missing\n");
739		put_vnode(volume, attributeDirInode);
740		return B_UNSUPPORTED;
741	}
742
743	result = attributeDir.ops->unlink(volume, &attributeDir, nameBuffer);
744	if (result != B_OK) {
745		TRACE_ALWAYS("failed to unlink attribute file: %s\n", strerror(result));
746		put_vnode(volume, attributeDirInode);
747		return result;
748	}
749
750	put_vnode(volume, attributeDirInode);
751	return B_OK;
752}
753
754
755uint32
756AttributeFile::CountAttributes()
757{
758	if (fFile == NULL)
759		return 0;
760
761	return fFile->entry_count;
762}
763
764
765AttributeEntry *
766AttributeFile::FindAttribute(const char *name, uint32 *index)
767{
768	for (uint32 i = 0; i < fFile->entry_count; i++) {
769		if (strcmp(fEntries[i]->Name(), name) == 0) {
770			if (index)
771				*index = i;
772
773			return fEntries[i];
774		}
775	}
776
777	return NULL;
778}
779
780
781status_t
782AttributeFile::CreateAttribute(const char *name, type_code type, int openMode,
783	AttributeEntry **_entry)
784{
785	AttributeEntry *existing = FindAttribute(name);
786	if (existing != NULL) {
787		if ((openMode & O_TRUNC) != 0)
788			existing->SetSize(0);
789
790		// attribute already exists, only allow if the attribute type is
791		// compatible or the attribute size is 0
792		if (existing->Type() != type) {
793			if (existing->Size() != 0)
794				return B_FILE_EXISTS;
795			existing->SetType(type);
796		}
797
798		if (existing->InitCheck() == B_OK) {
799			*_entry = existing;
800			return B_OK;
801		}
802
803		// we tried to change the existing item but failed, try to just
804		// remove it instead and creating a new one
805		RemoveAttribute(name, NULL);
806	}
807
808	AttributeEntry *entry = new(std::nothrow) AttributeEntry(this, name, type);
809	if (entry == NULL)
810		return B_NO_MEMORY;
811
812	status_t result = AddAttribute(entry);
813	if (result != B_OK) {
814		delete entry;
815		return result;
816	}
817
818	*_entry = entry;
819	return B_OK;
820}
821
822
823status_t
824AttributeFile::OpenAttribute(const char *name, int openMode,
825	AttributeEntry **_entry)
826{
827	AttributeEntry *entry = FindAttribute(name);
828	if (entry == NULL)
829		return B_ENTRY_NOT_FOUND;
830
831	if (openMode & O_TRUNC)
832		entry->SetSize(0);
833
834	*_entry = entry;
835	return B_OK;
836}
837
838
839status_t
840AttributeFile::RemoveAttribute(const char *name, AttributeEntry **_entry)
841{
842	uint32 index = 0;
843	AttributeEntry *entry = FindAttribute(name, &index);
844	if (entry == NULL)
845		return B_ENTRY_NOT_FOUND;
846
847	for (uint32 i = index + 1; i < fFile->entry_count; i++)
848		fEntries[i - 1] = fEntries[i];
849	fFile->entry_count--;
850
851	if (_entry)
852		*_entry = entry;
853	else
854		delete entry;
855
856	notify_attribute_changed(fVolumeID, -1, fFileInode, name, B_ATTR_REMOVED);
857	return B_OK;
858}
859
860
861status_t
862AttributeFile::AddAttribute(AttributeEntry *entry)
863{
864	status_t result = entry->InitCheck();
865	if (result != B_OK)
866		return result;
867
868	if (FindAttribute(entry->Name()) != NULL)
869		return B_FILE_EXISTS;
870
871	AttributeEntry **newEntries = (AttributeEntry **)realloc(fEntries,
872		(fFile->entry_count + 1) * sizeof(AttributeEntry *));
873	if (newEntries == NULL)
874		return B_NO_MEMORY;
875
876	fEntries = newEntries;
877	fEntries[fFile->entry_count++] = entry;
878
879	notify_attribute_changed(fVolumeID, -1, fFileInode, entry->Name(),
880		B_ATTR_CREATED);
881
882	return B_OK;
883}
884
885
886status_t
887AttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize,
888	uint32 *numEntries, uint32 *index)
889{
890	if (fFile == NULL || *index >= fFile->entry_count) {
891		*numEntries = 0;
892		return B_OK;
893	}
894
895	return fEntries[(*index)++]->FillDirent(dirent, bufferSize, numEntries);
896}
897
898
899//	#pragma mark AttributeEntry
900
901
902AttributeEntry::AttributeEntry(AttributeFile *parent, uint8 *buffer)
903	:
904	fParent(parent),
905	fEntry(NULL),
906	fData(NULL),
907	fStatus(B_NO_INIT),
908	fAllocatedEntry(false),
909	fAllocatedData(false)
910{
911	if (buffer == NULL)
912		return;
913
914	fEntry = (attribute_entry *)buffer;
915	fData = (uint8 *)fEntry->name + fEntry->name_length;
916	fStatus = B_OK;
917}
918
919
920AttributeEntry::AttributeEntry(AttributeFile *parent, const char *name,
921	type_code type)
922	:
923	fParent(parent),
924	fEntry(NULL),
925	fData(NULL),
926	fStatus(B_NO_INIT),
927	fAllocatedEntry(false),
928	fAllocatedData(false)
929{
930	fStatus = SetName(name);
931	if (fStatus != B_OK)
932		return;
933
934	fEntry->type = type;
935	fEntry->size = 0;
936}
937
938
939AttributeEntry::~AttributeEntry()
940{
941	if (fAllocatedEntry)
942		free(fEntry);
943	if (fAllocatedData)
944		free(fData);
945}
946
947
948size_t
949AttributeEntry::EntrySize()
950{
951	return sizeof(attribute_entry) - 1 + fEntry->name_length;
952}
953
954
955status_t
956AttributeEntry::SetType(type_code type)
957{
958	fEntry->type = type;
959	return B_OK;
960}
961
962
963status_t
964AttributeEntry::SetSize(size_t size)
965{
966	if (size <= fEntry->size) {
967		fEntry->size = size;
968		return B_OK;
969	}
970
971	if (fAllocatedData) {
972		uint8 *newData = (uint8 *)realloc(fData, size);
973		if (newData == NULL) {
974			fStatus = B_NO_MEMORY;
975			return fStatus;
976		}
977
978		fData = newData;
979		fEntry->size = size;
980		return B_OK;
981	}
982
983	uint8 *newData = (uint8 *)malloc(size);
984	if (newData == NULL) {
985		fStatus = B_NO_MEMORY;
986		return fStatus;
987	}
988
989	memcpy(newData, fData, min_c(fEntry->size, size));
990	fEntry->size = size;
991	fAllocatedData = true;
992	fData = newData;
993	return B_OK;
994}
995
996
997status_t
998AttributeEntry::SetName(const char *name)
999{
1000	size_t nameLength = strlen(name) + 1;
1001	if (nameLength > 255) {
1002		fStatus = B_NAME_TOO_LONG;
1003		return fStatus;
1004	}
1005
1006	if (!fAllocatedEntry || fEntry->name_length < nameLength) {
1007		attribute_entry *newEntry = (attribute_entry *)malloc(
1008			sizeof(attribute_entry) + nameLength);
1009		if (newEntry == NULL) {
1010			fStatus = B_NO_MEMORY;
1011			return fStatus;
1012		}
1013
1014		if (fEntry != NULL)
1015			memcpy(newEntry, fEntry, sizeof(attribute_entry));
1016		if (fAllocatedEntry)
1017			free(fEntry);
1018
1019		fAllocatedEntry = true;
1020		fEntry = newEntry;
1021	}
1022
1023	fEntry->name_length = nameLength;
1024	strlcpy(fEntry->name, name, nameLength);
1025	return B_OK;
1026}
1027
1028
1029status_t
1030AttributeEntry::FillDirent(struct dirent *dirent, size_t bufferSize,
1031	uint32 *numEntries)
1032{
1033	dirent->d_dev = dirent->d_pdev = fParent->VolumeID();
1034	dirent->d_ino = (ino_t)this;
1035	dirent->d_pino = fParent->FileInode();
1036	dirent->d_reclen = offsetof(struct dirent, d_name) + fEntry->name_length;
1037	if (bufferSize < dirent->d_reclen) {
1038		*numEntries = 0;
1039		return B_BAD_VALUE;
1040	}
1041
1042	strncpy(dirent->d_name, fEntry->name, fEntry->name_length);
1043	dirent->d_name[fEntry->name_length - 1] = 0;
1044	*numEntries = 1;
1045	return B_OK;
1046}
1047
1048
1049status_t
1050AttributeEntry::Read(off_t position, void *buffer, size_t *length)
1051{
1052	*length = (size_t)min_c((off_t)*length, fEntry->size - position);
1053	memcpy(buffer, fData + position, *length);
1054	return B_OK;
1055}
1056
1057
1058status_t
1059AttributeEntry::Write(off_t position, const void *buffer, size_t *length)
1060{
1061	size_t neededSize = position + *length;
1062	if (neededSize > fEntry->size) {
1063		status_t result = SetSize(neededSize);
1064		if (result != B_OK) {
1065			*length = 0;
1066			return result;
1067		}
1068	}
1069
1070	memcpy(fData + position, buffer, *length);
1071	notify_attribute_changed(fParent->VolumeID(), -1, fParent->FileInode(),
1072		fEntry->name, B_ATTR_CHANGED);
1073	return B_OK;
1074}
1075
1076
1077status_t
1078AttributeEntry::ReadStat(struct stat *stat)
1079{
1080	stat->st_dev = fParent->VolumeID();
1081	stat->st_ino = (ino_t)this;
1082	stat->st_nlink = 1;
1083	stat->st_blksize = 512;
1084	stat->st_uid = 1;
1085	stat->st_gid = 1;
1086	stat->st_size = fEntry->size;
1087	stat->st_mode = S_ATTR | 0x0777;
1088	stat->st_type = fEntry->type;
1089	stat->st_atime = stat->st_mtime = stat->st_crtime = time(NULL);
1090	stat->st_blocks = (fEntry->size + stat->st_blksize - 1) / stat->st_blksize;
1091	return B_OK;
1092}
1093
1094
1095status_t
1096AttributeEntry::WriteStat(const struct stat *stat, uint32 statMask)
1097{
1098	return B_UNSUPPORTED;
1099}
1100
1101
1102//	#pragma mark - vnode ops
1103
1104
1105static status_t
1106overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1107{
1108	OverlayInode *node = (OverlayInode *)vnode->private_node;
1109	fs_vnode *superVnode = node->SuperVnode();
1110
1111	status_t result = B_OK;
1112	if (superVnode->ops->put_vnode != NULL) {
1113		result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
1114			reenter);
1115	}
1116
1117	delete node;
1118	return result;
1119}
1120
1121
1122static status_t
1123overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1124{
1125	OverlayInode *node = (OverlayInode *)vnode->private_node;
1126	fs_vnode *superVnode = node->SuperVnode();
1127
1128	status_t result = B_OK;
1129	if (superVnode->ops->remove_vnode != NULL) {
1130		result = superVnode->ops->remove_vnode(volume->super_volume, superVnode,
1131			reenter);
1132	}
1133
1134	delete node;
1135	return result;
1136}
1137
1138
1139static status_t
1140overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode,
1141	fs_volume *superVolume, fs_vnode *_superVnode)
1142{
1143	if (volume == superVolume) {
1144		*_superVnode = *vnode;
1145		return B_OK;
1146	}
1147
1148	OverlayInode *node = (OverlayInode *)vnode->private_node;
1149	fs_vnode *superVnode = node->SuperVnode();
1150
1151	if (superVnode->ops->get_super_vnode != NULL) {
1152		return superVnode->ops->get_super_vnode(volume->super_volume,
1153			superVnode, superVolume, _superVnode);
1154	}
1155
1156	*_superVnode = *superVnode;
1157	return B_OK;
1158}
1159
1160
1161static status_t
1162overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id)
1163{
1164	OVERLAY_CALL(lookup, name, id)
1165}
1166
1167
1168static status_t
1169overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer,
1170	size_t bufferSize)
1171{
1172	OVERLAY_CALL(get_vnode_name, buffer, bufferSize)
1173}
1174
1175
1176static bool
1177overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie)
1178{
1179	TRACE("relaying op: can_page\n");
1180	OverlayInode *node = (OverlayInode *)vnode->private_node;
1181	fs_vnode *superVnode = node->SuperVnode();
1182
1183	if (superVnode->ops->can_page != NULL) {
1184		return superVnode->ops->can_page(volume->super_volume, superVnode,
1185			cookie);
1186	}
1187
1188	return false;
1189}
1190
1191
1192static status_t
1193overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1194	const iovec *vecs, size_t count, size_t *numBytes)
1195{
1196	OVERLAY_CALL(read_pages, cookie, pos, vecs, count, numBytes)
1197}
1198
1199
1200static status_t
1201overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1202	const iovec *vecs, size_t count, size_t *numBytes)
1203{
1204	OVERLAY_CALL(write_pages, cookie, pos, vecs, count, numBytes)
1205}
1206
1207
1208static status_t
1209overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1210	io_request *request)
1211{
1212	OVERLAY_CALL(io, cookie, request)
1213}
1214
1215
1216static status_t
1217overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1218	io_request *request)
1219{
1220	OVERLAY_CALL(cancel_io, cookie, request)
1221}
1222
1223
1224static status_t
1225overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset,
1226	size_t size, struct file_io_vec *vecs, size_t *count)
1227{
1228	OVERLAY_CALL(get_file_map, offset, size, vecs, count)
1229}
1230
1231
1232static status_t
1233overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op,
1234	void *buffer, size_t length)
1235{
1236	OVERLAY_CALL(ioctl, cookie, op, buffer, length)
1237}
1238
1239
1240static status_t
1241overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie,
1242	int flags)
1243{
1244	OVERLAY_CALL(set_flags, cookie, flags)
1245}
1246
1247
1248static status_t
1249overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1250	selectsync *sync)
1251{
1252	OVERLAY_CALL(select, cookie, event, sync)
1253}
1254
1255
1256static status_t
1257overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1258	selectsync *sync)
1259{
1260	OVERLAY_CALL(deselect, cookie, event, sync)
1261}
1262
1263
1264static status_t
1265overlay_fsync(fs_volume *volume, fs_vnode *vnode)
1266{
1267	OverlayInode *node = (OverlayInode *)vnode->private_node;
1268	fs_vnode *superVnode = node->SuperVnode();
1269
1270	if (superVnode->ops->fsync != NULL)
1271		return superVnode->ops->fsync(volume->super_volume, superVnode);
1272
1273	return B_OK;
1274}
1275
1276
1277static status_t
1278overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer,
1279	size_t *bufferSize)
1280{
1281	OVERLAY_CALL(read_symlink, buffer, bufferSize)
1282}
1283
1284
1285static status_t
1286overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name,
1287	const char *path, int mode)
1288{
1289	OVERLAY_CALL(create_symlink, name, path, mode)
1290}
1291
1292
1293static status_t
1294overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name,
1295	fs_vnode *target)
1296{
1297	OverlayInode *targetNode = (OverlayInode *)target->private_node;
1298	OVERLAY_CALL(link, name, targetNode->SuperVnode())
1299}
1300
1301
1302static status_t
1303overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name)
1304{
1305	OVERLAY_CALL(unlink, name)
1306}
1307
1308
1309static status_t
1310overlay_rename(fs_volume *volume, fs_vnode *vnode,
1311	const char *fromName, fs_vnode *toDir, const char *toName)
1312{
1313	OverlayInode *toDirNode = (OverlayInode *)toDir->private_node;
1314	OVERLAY_CALL(rename, fromName, toDirNode->SuperVnode(), toName)
1315}
1316
1317
1318static status_t
1319overlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
1320{
1321	OVERLAY_CALL(access, mode)
1322}
1323
1324
1325static status_t
1326overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat)
1327{
1328	OVERLAY_CALL(read_stat, stat)
1329}
1330
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_SUPPORTS_MONITOR_CHILDREN;
1756		info->flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR /*| B_FS_HAS_QUERY*/;
1757		return B_OK;
1758	}
1759
1760	return B_UNSUPPORTED;
1761}
1762
1763
1764static status_t
1765overlay_write_fs_info(fs_volume *volume, const struct fs_info *info,
1766	uint32 mask)
1767{
1768	OVERLAY_VOLUME_CALL(write_fs_info, info, mask)
1769	return B_UNSUPPORTED;
1770}
1771
1772
1773static status_t
1774overlay_sync(fs_volume *volume)
1775{
1776	TRACE_VOLUME("relaying volume op: sync\n");
1777	if (volume->super_volume->ops->sync != NULL)
1778		return volume->super_volume->ops->sync(volume->super_volume);
1779	return B_UNSUPPORTED;
1780}
1781
1782
1783static status_t
1784overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type,
1785	uint32 *_flags, bool reenter)
1786{
1787	TRACE_VOLUME("relaying volume op: get_vnode\n");
1788	if (volume->super_volume->ops->get_vnode != NULL) {
1789		status_t status = volume->super_volume->ops->get_vnode(
1790			volume->super_volume, id, vnode, _type, _flags, reenter);
1791		if (status != B_OK)
1792			return status;
1793
1794		OverlayInode *node = new(std::nothrow) OverlayInode(
1795			(OverlayVolume *)volume->private_volume, vnode, id);
1796		if (node == NULL) {
1797			vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
1798			return B_NO_MEMORY;
1799		}
1800
1801		status = node->InitCheck();
1802		if (status != B_OK) {
1803			vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
1804			delete node;
1805			return status;
1806		}
1807
1808		vnode->private_node = node;
1809		vnode->ops = &sOverlayVnodeOps;
1810		return B_OK;
1811	}
1812
1813	return B_UNSUPPORTED;
1814}
1815
1816
1817static status_t
1818overlay_open_index_dir(fs_volume *volume, void **cookie)
1819{
1820	OVERLAY_VOLUME_CALL(open_index_dir, cookie)
1821	return B_UNSUPPORTED;
1822}
1823
1824
1825static status_t
1826overlay_close_index_dir(fs_volume *volume, void *cookie)
1827{
1828	OVERLAY_VOLUME_CALL(close_index_dir, cookie)
1829	return B_UNSUPPORTED;
1830}
1831
1832
1833static status_t
1834overlay_free_index_dir_cookie(fs_volume *volume, void *cookie)
1835{
1836	OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie)
1837	return B_UNSUPPORTED;
1838}
1839
1840
1841static status_t
1842overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer,
1843	size_t bufferSize, uint32 *_num)
1844{
1845	OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num)
1846	return B_UNSUPPORTED;
1847}
1848
1849
1850static status_t
1851overlay_rewind_index_dir(fs_volume *volume, void *cookie)
1852{
1853	OVERLAY_VOLUME_CALL(rewind_index_dir, cookie)
1854	return B_UNSUPPORTED;
1855}
1856
1857
1858static status_t
1859overlay_create_index(fs_volume *volume, const char *name, uint32 type,
1860	uint32 flags)
1861{
1862	OVERLAY_VOLUME_CALL(create_index, name, type, flags)
1863	return B_UNSUPPORTED;
1864}
1865
1866
1867static status_t
1868overlay_remove_index(fs_volume *volume, const char *name)
1869{
1870	OVERLAY_VOLUME_CALL(remove_index, name)
1871	return B_UNSUPPORTED;
1872}
1873
1874
1875static status_t
1876overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat)
1877{
1878	OVERLAY_VOLUME_CALL(read_index_stat, name, stat)
1879	return B_UNSUPPORTED;
1880}
1881
1882
1883static status_t
1884overlay_open_query(fs_volume *volume, const char *query, uint32 flags,
1885	port_id port, uint32 token, void **_cookie)
1886{
1887	OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie)
1888	return B_UNSUPPORTED;
1889}
1890
1891
1892static status_t
1893overlay_close_query(fs_volume *volume, void *cookie)
1894{
1895	OVERLAY_VOLUME_CALL(close_query, cookie)
1896	return B_UNSUPPORTED;
1897}
1898
1899
1900static status_t
1901overlay_free_query_cookie(fs_volume *volume, void *cookie)
1902{
1903	OVERLAY_VOLUME_CALL(free_query_cookie, cookie)
1904	return B_UNSUPPORTED;
1905}
1906
1907
1908static status_t
1909overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer,
1910	size_t bufferSize, uint32 *_num)
1911{
1912	OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num)
1913	return B_UNSUPPORTED;
1914}
1915
1916
1917static status_t
1918overlay_rewind_query(fs_volume *volume, void *cookie)
1919{
1920	OVERLAY_VOLUME_CALL(rewind_query, cookie)
1921	return B_UNSUPPORTED;
1922}
1923
1924
1925static status_t
1926overlay_all_layers_mounted(fs_volume *volume)
1927{
1928	return B_OK;
1929}
1930
1931
1932static status_t
1933overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode)
1934{
1935	OverlayInode *node = new(std::nothrow) OverlayInode(
1936		(OverlayVolume *)volume->private_volume, vnode, id);
1937	if (node == NULL)
1938		return B_NO_MEMORY;
1939
1940	status_t status = node->InitCheck();
1941	if (status != B_OK) {
1942		delete node;
1943		return status;
1944	}
1945
1946	vnode->private_node = node;
1947	vnode->ops = &sOverlayVnodeOps;
1948	return B_OK;
1949}
1950
1951
1952static status_t
1953overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode)
1954{
1955	delete (OverlayInode *)vnode->private_node;
1956	return B_OK;
1957}
1958
1959
1960static fs_volume_ops sOverlayVolumeOps = {
1961	&overlay_unmount,
1962
1963	&overlay_read_fs_info,
1964	&overlay_write_fs_info,
1965	&overlay_sync,
1966
1967	&overlay_get_vnode,
1968	&overlay_open_index_dir,
1969	&overlay_close_index_dir,
1970	&overlay_free_index_dir_cookie,
1971	&overlay_read_index_dir,
1972	&overlay_rewind_index_dir,
1973
1974	&overlay_create_index,
1975	&overlay_remove_index,
1976	&overlay_read_index_stat,
1977
1978	&overlay_open_query,
1979	&overlay_close_query,
1980	&overlay_free_query_cookie,
1981	&overlay_read_query,
1982	&overlay_rewind_query,
1983
1984	&overlay_all_layers_mounted,
1985	&overlay_create_sub_vnode,
1986	&overlay_delete_sub_vnode
1987};
1988
1989
1990//	#pragma mark - filesystem module
1991
1992
1993static status_t
1994overlay_mount(fs_volume *volume, const char *device, uint32 flags,
1995	const char *args, ino_t *rootID)
1996{
1997	TRACE_VOLUME("mounting attribute overlay\n");
1998	volume->private_volume = new(std::nothrow) OverlayVolume(volume);
1999	if (volume->private_volume == NULL)
2000		return B_NO_MEMORY;
2001
2002	volume->ops = &sOverlayVolumeOps;
2003	return B_OK;
2004}
2005
2006
2007static status_t
2008overlay_std_ops(int32 op, ...)
2009{
2010	switch (op) {
2011		case B_MODULE_INIT:
2012		case B_MODULE_UNINIT:
2013			return B_OK;
2014		default:
2015			return B_ERROR;
2016	}
2017}
2018
2019
2020static file_system_module_info sOverlayFileSystem = {
2021	{
2022		"file_systems/attribute_overlay" B_CURRENT_FS_API_VERSION,
2023		0,
2024		overlay_std_ops,
2025	},
2026
2027	"attribute_overlay",				// short_name
2028	"Attribute Overlay File System",	// pretty_name
2029	0,									// DDM flags
2030
2031	// scanning
2032	NULL, // identify_partition
2033	NULL, // scan_partition
2034	NULL, // free_identify_partition_cookie
2035	NULL, // free_partition_content_cookie
2036
2037	// general operations
2038	&overlay_mount,
2039
2040	// capability querying
2041	NULL, // get_supported_operations
2042
2043	NULL, // validate_resize
2044	NULL, // validate_move
2045	NULL, // validate_set_content_name
2046	NULL, // validate_set_content_parameters
2047	NULL, // validate_initialize
2048
2049	// shadow partition modification
2050	NULL, // shadow_changed
2051
2052	// writing
2053	NULL, // defragment
2054	NULL, // repair
2055	NULL, // resize
2056	NULL, // move
2057	NULL, // set_content_name
2058	NULL, // set_content_parameters
2059	NULL // initialize
2060};
2061
2062}	// namespace attribute_overlay
2063
2064using namespace attribute_overlay;
2065
2066module_info *modules[] = {
2067	(module_info *)&sOverlayFileSystem,
2068	NULL,
2069};
2070