xref: /haiku/src/add-ons/kernel/file_systems/layers/attribute_overlay/attribute_overlay.cpp (revision e7c8829c5d8e5d34a2a1e111f1c06aceff256013)
1 /*
2  * Copyright 2009, 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 #include <new>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include <dirent.h>
14 
15 #include <util/kernel_cpp.h>
16 
17 #include <fs_info.h>
18 #include <fs_interface.h>
19 
20 #include <debug.h>
21 #include <KernelExport.h>
22 #include <NodeMonitor.h>
23 
24 
25 //#define TRACE_OVERLAY
26 #ifdef TRACE_OVERLAY
27 #define TRACE(x...)			dprintf("attribute_overlay: " x)
28 #define TRACE_VOLUME(x...)	dprintf("attribute_overlay: " x)
29 #define TRACE_ALWAYS(x...)	dprintf("attribute_overlay: " x)
30 #else
31 #define TRACE(x...)			/* nothing */
32 #define TRACE_VOLUME(x...)	/* nothing */
33 #define TRACE_ALWAYS(x...)	dprintf("attribute_overlay: " x)
34 #endif
35 
36 
37 namespace attribute_overlay {
38 
39 class AttributeFile;
40 class AttributeEntry;
41 
42 
43 struct attribute_dir_cookie {
44 	AttributeFile *	file;
45 	uint32			index;
46 };
47 
48 
49 class OverlayVolume {
50 public:
51 							OverlayVolume(fs_volume *volume);
52 							~OverlayVolume();
53 
54 		fs_volume *			Volume() { return fVolume; }
55 		fs_volume *			SuperVolume() { return fVolume->super_volume; }
56 
57 private:
58 		fs_volume *			fVolume;
59 };
60 
61 
62 class OverlayInode {
63 public:
64 							OverlayInode(OverlayVolume *volume,
65 								fs_vnode *superVnode, ino_t inodeNumber);
66 							~OverlayInode();
67 
68 		status_t			InitCheck();
69 
70 		fs_volume *			Volume() { return fVolume->Volume(); }
71 		fs_volume *			SuperVolume() { return fVolume->SuperVolume(); }
72 		fs_vnode *			SuperVnode() { return &fSuperVnode; }
73 		ino_t				InodeNumber() { return fInodeNumber; }
74 
75 		status_t			GetAttributeFile(AttributeFile **attributeFile);
76 		status_t			WriteAttributeFile();
77 
78 private:
79 		OverlayVolume *		fVolume;
80 		fs_vnode			fSuperVnode;
81 		ino_t				fInodeNumber;
82 		AttributeFile *		fAttributeFile;
83 };
84 
85 
86 class AttributeFile {
87 public:
88 							AttributeFile(fs_volume *overlay, fs_volume *volume,
89 								fs_vnode *vnode);
90 							~AttributeFile();
91 
92 		status_t			InitCheck() { return fStatus; }
93 
94 		dev_t				VolumeID() { return fVolumeID; }
95 		ino_t				FileInode() { return fFileInode; }
96 
97 		status_t			CreateEmpty();
98 		status_t			WriteAttributeFile(fs_volume *overlay,
99 								fs_volume *volume, fs_vnode *vnode);
100 
101 		status_t			ReadAttributeDir(struct dirent *dirent,
102 								size_t bufferSize, uint32 *numEntries,
103 								uint32 *index);
104 
105 		uint32				CountAttributes();
106 		AttributeEntry *	FindAttribute(const char *name,
107 								uint32 *index = NULL);
108 
109 		status_t			CreateAttribute(const char *name, type_code type,
110 								int openMode, AttributeEntry **entry);
111 		status_t			OpenAttribute(const char *name, int openMode,
112 								AttributeEntry **entry);
113 		status_t			RemoveAttribute(const char *name,
114 								AttributeEntry **entry);
115 		status_t			AddAttribute(AttributeEntry *entry);
116 
117 private:
118 		#define ATTRIBUTE_OVERLAY_FILE_MAGIC			'attr'
119 		#define ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME	"_HAIKU"
120 
121 		struct attribute_file {
122 			uint32			magic; // 'attr'
123 			uint32			entry_count;
124 			uint8			entries[1];
125 		} _PACKED;
126 
127 		status_t			fStatus;
128 		dev_t				fVolumeID;
129 		ino_t				fFileInode;
130 		ino_t				fDirectoryInode;
131 		ino_t				fAttributeDirInode;
132 		ino_t				fAttributeFileInode;
133 		attribute_file *	fFile;
134 		uint32				fAttributeDirIndex;
135 		AttributeEntry **	fEntries;
136 };
137 
138 
139 class AttributeEntry {
140 public:
141 							AttributeEntry(AttributeFile *parent,
142 								uint8 *buffer);
143 							AttributeEntry(AttributeFile *parent,
144 								const char *name, type_code type);
145 							~AttributeEntry();
146 
147 		status_t			InitCheck() { return fStatus; }
148 
149 		uint8 *				Entry() { return (uint8 *)fEntry; }
150 		size_t				EntrySize();
151 		uint8 *				Data() { return fData; }
152 		size_t				DataSize() { return fEntry->size; }
153 
154 		status_t			SetType(type_code type);
155 		type_code			Type() { return fEntry->type; }
156 
157 		status_t			SetSize(size_t size);
158 		uint32				Size() { return fEntry->size; }
159 
160 		status_t			SetName(const char *name);
161 		const char *		Name() { return fEntry->name; }
162 		uint8				NameLength() { return fEntry->name_length; }
163 
164 		status_t			FillDirent(struct dirent *dirent,
165 								size_t bufferSize, uint32 *numEntries);
166 
167 		status_t			Read(off_t position, void *buffer, size_t *length);
168 		status_t			Write(off_t position, const void *buffer,
169 								size_t *length);
170 
171 		status_t			ReadStat(struct stat *stat);
172 		status_t			WriteStat(const struct stat *stat, uint32 statMask);
173 
174 private:
175 		struct attribute_entry {
176 			type_code		type;
177 			uint32			size;
178 			uint8			name_length; // including 0 byte
179 			char			name[1]; // 0 terminated, followed by data
180 		} _PACKED;
181 
182 		AttributeFile *		fParent;
183 		attribute_entry *	fEntry;
184 		uint8 *				fData;
185 		status_t			fStatus;
186 		bool				fAllocatedEntry;
187 		bool				fAllocatedData;
188 };
189 
190 
191 //	#pragma mark OverlayVolume
192 
193 
194 OverlayVolume::OverlayVolume(fs_volume *volume)
195 	:	fVolume(volume)
196 {
197 }
198 
199 
200 OverlayVolume::~OverlayVolume()
201 {
202 }
203 
204 
205 //	#pragma mark OverlayInode
206 
207 
208 OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode,
209 	ino_t inodeNumber)
210 	:	fVolume(volume),
211 		fSuperVnode(*superVnode),
212 		fInodeNumber(inodeNumber),
213 		fAttributeFile(NULL)
214 {
215 	TRACE("inode created\n");
216 }
217 
218 
219 OverlayInode::~OverlayInode()
220 {
221 	TRACE("inode destroyed\n");
222 	delete fAttributeFile;
223 }
224 
225 
226 status_t
227 OverlayInode::InitCheck()
228 {
229 	return B_OK;
230 }
231 
232 
233 status_t
234 OverlayInode::GetAttributeFile(AttributeFile **attributeFile)
235 {
236 	if (fAttributeFile == NULL) {
237 		fAttributeFile = new(std::nothrow) AttributeFile(Volume(),
238 			SuperVolume(), &fSuperVnode);
239 		if (fAttributeFile == NULL) {
240 			TRACE_ALWAYS("no memory to allocate attribute file\n");
241 			return B_NO_MEMORY;
242 		}
243 	}
244 
245 	status_t result = fAttributeFile->InitCheck();
246 	if (result != B_OK) {
247 		if (result == B_ENTRY_NOT_FOUND) {
248 			// TODO: need to check if we're able to create the file
249 			// but at least allow virtual attributes for now
250 		}
251 
252 		result = fAttributeFile->CreateEmpty();
253 		if (result != B_OK)
254 			return result;
255 	}
256 
257 	*attributeFile = fAttributeFile;
258 	return B_OK;
259 }
260 
261 
262 status_t
263 OverlayInode::WriteAttributeFile()
264 {
265 	if (fAttributeFile == NULL)
266 		return B_NO_INIT;
267 
268 	status_t result = fAttributeFile->InitCheck();
269 	if (result != B_OK)
270 		return result;
271 
272 	return fAttributeFile->WriteAttributeFile(Volume(), SuperVolume(),
273 		&fSuperVnode);
274 }
275 
276 
277 //	#pragma mark AttributeFile
278 
279 
280 AttributeFile::AttributeFile(fs_volume *overlay, fs_volume *volume,
281 	fs_vnode *vnode)
282 	:	fStatus(B_NO_INIT),
283 		fVolumeID(volume->id),
284 		fFileInode(0),
285 		fDirectoryInode(0),
286 		fAttributeDirInode(0),
287 		fAttributeFileInode(0),
288 		fFile(NULL),
289 		fAttributeDirIndex(0),
290 		fEntries(NULL)
291 {
292 	if (vnode->ops->get_vnode_name == NULL) {
293 		TRACE_ALWAYS("cannot get vnode name, hook missing\n");
294 		fStatus = B_UNSUPPORTED;
295 		return;
296 	}
297 
298 	char nameBuffer[B_FILE_NAME_LENGTH];
299 	nameBuffer[sizeof(nameBuffer) - 1] = 0;
300 	fStatus = vnode->ops->get_vnode_name(volume, vnode, nameBuffer,
301 		sizeof(nameBuffer) - 1);
302 	if (fStatus != B_OK) {
303 		TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(fStatus));
304 		return;
305 	}
306 
307 	if (strcmp(nameBuffer, ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) {
308 		// we don't want attribute overlays on the attribute dir itself
309 		fStatus = B_UNSUPPORTED;
310 		return;
311 	}
312 
313 	struct stat stat;
314 	if (vnode->ops->read_stat != NULL
315 		&& vnode->ops->read_stat(volume, vnode, &stat) == B_OK) {
316 		fFileInode = stat.st_ino;
317 	}
318 
319 	// TODO: the ".." lookup is not actually valid for non-directory vnodes.
320 	// we make use of the fact that a filesystem probably still provides the
321 	// lookup hook and has hardcoded ".." to resolve to the parent entry. if we
322 	// wanted to do this correctly we need some other way to relate this vnode
323 	// to its parent directory vnode.
324 	const char *lookup[]
325 		= { "..", ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, nameBuffer };
326 	int32 lookupCount = sizeof(lookup) / sizeof(lookup[0]);
327 	fs_vnode currentVnode = *vnode;
328 	ino_t lastInodeNumber = 0;
329 
330 	for (int32 i = 0; i < lookupCount; i++) {
331 		if (currentVnode.ops->lookup == NULL) {
332 			TRACE_ALWAYS("lookup not possible, lookup hook missing\n");
333 			fStatus = B_UNSUPPORTED;
334 			if (i > 0)
335 				put_vnode(volume, lastInodeNumber);
336 			return;
337 		}
338 
339 		ino_t inodeNumber;
340 		fStatus = currentVnode.ops->lookup(volume, &currentVnode, lookup[i],
341 			&inodeNumber);
342 
343 		if (i > 0)
344 			put_vnode(volume, lastInodeNumber);
345 
346 		if (fStatus != B_OK) {
347 			if (fStatus != B_ENTRY_NOT_FOUND) {
348 				TRACE_ALWAYS("lookup of \"%s\" failed: %s\n", lookup[i],
349 					strerror(fStatus));
350 			}
351 			return;
352 		}
353 
354 		if (i == 0)
355 			fDirectoryInode = inodeNumber;
356 		else if (i == 1)
357 			fAttributeDirInode = inodeNumber;
358 		else if (i == 2)
359 			fAttributeFileInode = inodeNumber;
360 
361 		OverlayInode *overlayInode = NULL;
362 		fStatus = get_vnode(overlay, inodeNumber, (void **)&overlayInode);
363 		if (fStatus != B_OK) {
364 			TRACE_ALWAYS("getting vnode failed: %s\n", strerror(fStatus));
365 			return;
366 		}
367 
368 		currentVnode = *overlayInode->SuperVnode();
369 		lastInodeNumber = inodeNumber;
370 	}
371 
372 	if (currentVnode.ops->read_stat == NULL || currentVnode.ops->open == NULL
373 		|| currentVnode.ops->read == NULL) {
374 		TRACE_ALWAYS("can't use attribute file, hooks missing\n");
375 		put_vnode(volume, lastInodeNumber);
376 		fStatus = B_UNSUPPORTED;
377 		return;
378 	}
379 
380 	fStatus = currentVnode.ops->read_stat(volume, &currentVnode, &stat);
381 	if (fStatus != B_OK) {
382 		TRACE_ALWAYS("failed to stat attribute file: %s\n", strerror(fStatus));
383 		put_vnode(volume, lastInodeNumber);
384 		return;
385 	}
386 
387 	void *attrFileCookie = NULL;
388 	fStatus = currentVnode.ops->open(volume, &currentVnode, O_RDONLY,
389 		&attrFileCookie);
390 	if (fStatus != B_OK) {
391 		TRACE_ALWAYS("failed to open attribute file: %s\n", strerror(fStatus));
392 		put_vnode(volume, lastInodeNumber);
393 		return;
394 	}
395 
396 	size_t readLength = stat.st_size;
397 	uint8 *buffer = (uint8 *)malloc(readLength);
398 	if (buffer == NULL) {
399 		TRACE_ALWAYS("cannot allocate memory for read buffer\n");
400 		put_vnode(volume, lastInodeNumber);
401 		fStatus = B_NO_MEMORY;
402 		return;
403 	}
404 
405 	fStatus = currentVnode.ops->read(volume, &currentVnode, attrFileCookie, 0,
406 		buffer, &readLength);
407 	if (fStatus != B_OK) {
408 		TRACE_ALWAYS("failed to read from file: %s\n", strerror(fStatus));
409 		put_vnode(volume, lastInodeNumber);
410 		return;
411 	}
412 
413 	if (currentVnode.ops->close != NULL)
414 		currentVnode.ops->close(volume, &currentVnode, attrFileCookie);
415 	if (currentVnode.ops->free_cookie != NULL)
416 		currentVnode.ops->free_cookie(volume, &currentVnode, attrFileCookie);
417 
418 	put_vnode(volume, lastInodeNumber);
419 
420 	fFile = (attribute_file *)buffer;
421 	if (fFile->magic != ATTRIBUTE_OVERLAY_FILE_MAGIC) {
422 		TRACE_ALWAYS("attribute file has bad magic\n");
423 		fStatus = B_BAD_VALUE;
424 		return;
425 	}
426 
427 	fEntries = (AttributeEntry **)malloc(fFile->entry_count
428 		* sizeof(AttributeEntry *));
429 	if (fEntries == NULL) {
430 		TRACE_ALWAYS("no memory to allocate entry pointers\n");
431 		fStatus = B_NO_MEMORY;
432 		return;
433 	}
434 
435 	for (uint32 i = 0; i < fFile->entry_count; i++)
436 		fEntries[i] = NULL;
437 
438 	size_t totalSize = 0;
439 	readLength -= sizeof(attribute_file) - 1;
440 	for (uint32 i = 0; i < fFile->entry_count; i++) {
441 		fEntries[i] = new(std::nothrow) AttributeEntry(this,
442 			fFile->entries + totalSize);
443 		if (fEntries[i] == NULL) {
444 			TRACE_ALWAYS("no memory to allocate attribute entry\n");
445 			fStatus = B_NO_MEMORY;
446 			return;
447 		}
448 
449 		totalSize += fEntries[i]->EntrySize() + fEntries[i]->DataSize();
450 		if (totalSize > readLength) {
451 			TRACE_ALWAYS("attribute entries are too large for buffer\n");
452 			fStatus = B_BAD_VALUE;
453 			return;
454 		}
455 	}
456 }
457 
458 
459 AttributeFile::~AttributeFile()
460 {
461 	if (fFile == NULL)
462 		return;
463 
464 	if (fEntries != NULL) {
465 		for (uint32 i = 0; i < fFile->entry_count; i++)
466 			delete fEntries[i];
467 
468 		free(fEntries);
469 	}
470 
471 	free(fFile);
472 }
473 
474 
475 status_t
476 AttributeFile::CreateEmpty()
477 {
478 	if (fFile == NULL) {
479 		fFile = (attribute_file *)malloc(sizeof(attribute_file) - 1);
480 		if (fFile == NULL) {
481 			TRACE_ALWAYS("failed to allocate file buffer\n");
482 			fStatus = B_NO_MEMORY;
483 			return fStatus;
484 		}
485 
486 		fFile->entry_count = 0;
487 		fFile->magic = ATTRIBUTE_OVERLAY_FILE_MAGIC;
488 	}
489 
490 	fStatus = B_OK;
491 	return B_OK;
492 }
493 
494 
495 status_t
496 AttributeFile::WriteAttributeFile(fs_volume *overlay, fs_volume *volume,
497 	fs_vnode *vnode)
498 {
499 	if (fFile == NULL)
500 		return B_NO_INIT;
501 
502 	if (fDirectoryInode == 0) {
503 		TRACE_ALWAYS("directory inode not known\n");
504 		return B_NO_INIT;
505 	}
506 
507 	char nameBuffer[B_FILE_NAME_LENGTH];
508 	nameBuffer[sizeof(nameBuffer) - 1] = 0;
509 	status_t result = vnode->ops->get_vnode_name(volume, vnode, nameBuffer,
510 		sizeof(nameBuffer) - 1);
511 	if (result != B_OK) {
512 		TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result));
513 		return result;
514 	}
515 
516 	fs_vnode currentVnode;
517 	OverlayInode *overlayInode = NULL;
518 	if (fAttributeDirInode == 0) {
519 		result = get_vnode(overlay, fDirectoryInode, (void **)&overlayInode);
520 		if (result != B_OK) {
521 			TRACE_ALWAYS("failed to get directory vnode: %s\n",
522 				strerror(result));
523 			return result;
524 		}
525 
526 		currentVnode = *overlayInode->SuperVnode();
527 
528 		// create the attribute directory
529 		result = currentVnode.ops->create_dir(volume, &currentVnode,
530 			ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, S_IRWXU | S_IRWXG | S_IRWXO);
531 
532 		if (result == B_OK) {
533 			result = currentVnode.ops->lookup(volume, &currentVnode,
534 				ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, &fAttributeDirInode);
535 
536 			// lookup() got us a reference we don't need -- put it
537 			if (result == B_OK)
538 				put_vnode(volume, fAttributeDirInode);
539 		}
540 
541 		put_vnode(volume, fDirectoryInode);
542 
543 		if (result != B_OK) {
544 			TRACE_ALWAYS("failed to create attribute directory: %s\n",
545 				strerror(result));
546 			fAttributeDirInode = 0;
547 			return result;
548 		}
549 	}
550 
551 	void *attrFileCookie = NULL;
552 	if (fAttributeFileInode == 0) {
553 		result = get_vnode(overlay, fAttributeDirInode, (void **)&overlayInode);
554 		if (result != B_OK) {
555 			TRACE_ALWAYS("failed to get attribute directory vnode: %s\n",
556 				strerror(result));
557 			return result;
558 		}
559 
560 		currentVnode = *overlayInode->SuperVnode();
561 
562 		// create the attribute file
563 		result = currentVnode.ops->create(volume, &currentVnode,
564 			nameBuffer, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP
565 			| S_IWGRP | S_IROTH | S_IWOTH, &attrFileCookie,
566 			&fAttributeFileInode);
567 
568 		put_vnode(volume, fAttributeDirInode);
569 
570 		if (result != B_OK) {
571 			TRACE_ALWAYS("failed to create attribute file: %s\n",
572 				strerror(result));
573 			return result;
574 		}
575 
576 		result = get_vnode(overlay, fAttributeFileInode, (void **)&overlayInode);
577 		if (result != B_OK) {
578 			TRACE_ALWAYS("getting attribute file vnode after create failed: %s\n",
579 				strerror(result));
580 			return result;
581 		}
582 
583 		currentVnode = *overlayInode->SuperVnode();
584 	} else {
585 		result = get_vnode(overlay, fAttributeFileInode, (void **)&overlayInode);
586 		if (result != B_OK) {
587 			TRACE_ALWAYS("getting attribute file vnode failed: %s\n",
588 				strerror(result));
589 			return result;
590 		}
591 
592 		currentVnode = *overlayInode->SuperVnode();
593 
594 		// open the attribute file
595 		result = currentVnode.ops->open(volume, &currentVnode, O_RDWR | O_TRUNC,
596 			&attrFileCookie);
597 		if (result != B_OK) {
598 			TRACE_ALWAYS("failed to open attribute file for writing: %s\n",
599 				strerror(result));
600 			put_vnode(volume, fAttributeFileInode);
601 			return result;
602 		}
603 	}
604 
605 	off_t position = 0;
606 	size_t writeLength = sizeof(attribute_file) - 1;
607 	result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
608 		position, fFile, &writeLength);
609 	if (result != B_OK) {
610 		TRACE_ALWAYS("failed to write to attribute file: %s\n",
611 			strerror(result));
612 		goto close_and_put;
613 	}
614 
615 	for (uint32 i = 0; i < fFile->entry_count; i++) {
616 		writeLength = fEntries[i]->EntrySize();
617 		result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
618 			position, fEntries[i]->Entry(), &writeLength);
619 		if (result != B_OK) {
620 			TRACE_ALWAYS("failed to write to attribute file: %s\n",
621 				strerror(result));
622 			goto close_and_put;
623 		}
624 
625 		writeLength = fEntries[i]->DataSize();
626 		result = currentVnode.ops->write(volume, &currentVnode, attrFileCookie,
627 			position, fEntries[i]->Data(), &writeLength);
628 		if (result != B_OK) {
629 			TRACE_ALWAYS("failed to write to attribute file: %s\n",
630 				strerror(result));
631 			goto close_and_put;
632 		}
633 	}
634 
635 close_and_put:
636 	if (currentVnode.ops->close != NULL)
637 		currentVnode.ops->close(volume, &currentVnode, attrFileCookie);
638 	if (currentVnode.ops->free_cookie != NULL)
639 		currentVnode.ops->free_cookie(volume, &currentVnode, attrFileCookie);
640 
641 	put_vnode(volume, fAttributeFileInode);
642 	return B_OK;
643 }
644 
645 
646 uint32
647 AttributeFile::CountAttributes()
648 {
649 	if (fFile == NULL)
650 		return 0;
651 
652 	return fFile->entry_count;
653 }
654 
655 
656 AttributeEntry *
657 AttributeFile::FindAttribute(const char *name, uint32 *index)
658 {
659 	for (uint32 i = 0; i < fFile->entry_count; i++) {
660 		if (strncmp(fEntries[i]->Name(), name, fEntries[i]->NameLength()) == 0) {
661 			if (index)
662 				*index = i;
663 
664 			return fEntries[i];
665 		}
666 	}
667 
668 	return NULL;
669 }
670 
671 
672 status_t
673 AttributeFile::CreateAttribute(const char *name, type_code type, int openMode,
674 	AttributeEntry **_entry)
675 {
676 	AttributeEntry *existing = FindAttribute(name);
677 	if (existing != NULL) {
678 		if (openMode & O_TRUNC)
679 			existing->SetSize(0);
680 
681 		// attribute already exists, only allow if the attribute type is
682 		// compatible or the attribute size is 0
683 		if (existing->Type() != type) {
684 			if (existing->Size() != 0)
685 				return B_FILE_EXISTS;
686 			existing->SetType(type);
687 		}
688 
689 		if (existing->InitCheck() == B_OK) {
690 			*_entry = existing;
691 			return B_OK;
692 		}
693 
694 		// we tried to change the existing item but failed, try to just
695 		// remove it instead and creating a new one
696 		RemoveAttribute(name, NULL);
697 	}
698 
699 	AttributeEntry *entry = new(std::nothrow) AttributeEntry(this, name, type);
700 	if (entry == NULL)
701 		return B_NO_MEMORY;
702 
703 	status_t result = AddAttribute(entry);
704 	if (result != B_OK) {
705 		delete entry;
706 		return result;
707 	}
708 
709 	*_entry = entry;
710 	return B_OK;
711 }
712 
713 
714 status_t
715 AttributeFile::OpenAttribute(const char *name, int openMode,
716 	AttributeEntry **_entry)
717 {
718 	AttributeEntry *entry = FindAttribute(name);
719 	if (entry == NULL)
720 		return B_ENTRY_NOT_FOUND;
721 
722 	if (openMode & O_TRUNC)
723 		entry->SetSize(0);
724 
725 	*_entry = entry;
726 	return B_OK;
727 }
728 
729 
730 status_t
731 AttributeFile::RemoveAttribute(const char *name, AttributeEntry **_entry)
732 {
733 	uint32 index = 0;
734 	AttributeEntry *entry = FindAttribute(name, &index);
735 	if (entry == NULL)
736 		return B_ENTRY_NOT_FOUND;
737 
738 	for (uint32 i = index + 1; i < fFile->entry_count; i++)
739 		fEntries[i - 1] = fEntries[i];
740 	fFile->entry_count--;
741 
742 	if (_entry)
743 		*_entry = entry;
744 	else
745 		delete entry;
746 
747 	notify_attribute_changed(fVolumeID, fFileInode, name, B_ATTR_REMOVED);
748 	return B_OK;
749 }
750 
751 
752 status_t
753 AttributeFile::AddAttribute(AttributeEntry *entry)
754 {
755 	status_t result = entry->InitCheck();
756 	if (result != B_OK)
757 		return result;
758 
759 	if (FindAttribute(entry->Name()) != NULL)
760 		return B_FILE_EXISTS;
761 
762 	AttributeEntry **newEntries = (AttributeEntry **)realloc(fEntries,
763 		(fFile->entry_count + 1) * sizeof(AttributeEntry *));
764 	if (newEntries == NULL)
765 		return B_NO_MEMORY;
766 
767 	fEntries = newEntries;
768 	fEntries[fFile->entry_count++] = entry;
769 
770 	notify_attribute_changed(fVolumeID, fFileInode, entry->Name(),
771 		B_ATTR_CREATED);
772 
773 	return B_OK;
774 }
775 
776 
777 status_t
778 AttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize,
779 	uint32 *numEntries, uint32 *index)
780 {
781 	if (fFile == NULL || *index >= fFile->entry_count) {
782 		*numEntries = 0;
783 		return B_OK;
784 	}
785 
786 	return fEntries[(*index)++]->FillDirent(dirent, bufferSize, numEntries);
787 }
788 
789 
790 //	#pragma mark AttributeEntry
791 
792 
793 AttributeEntry::AttributeEntry(AttributeFile *parent, uint8 *buffer)
794 	:	fParent(parent),
795 		fEntry(NULL),
796 		fData(NULL),
797 		fStatus(B_NO_INIT),
798 		fAllocatedEntry(false),
799 		fAllocatedData(false)
800 {
801 	if (buffer == NULL)
802 		return;
803 
804 	fEntry = (attribute_entry *)buffer;
805 	fData = (uint8 *)fEntry->name + fEntry->name_length;
806 	fStatus = B_OK;
807 }
808 
809 
810 AttributeEntry::AttributeEntry(AttributeFile *parent, const char *name,
811 	type_code type)
812 	:	fParent(parent),
813 		fEntry(NULL),
814 		fData(NULL),
815 		fStatus(B_NO_INIT),
816 		fAllocatedEntry(false),
817 		fAllocatedData(false)
818 {
819 	fStatus = SetName(name);
820 	if (fStatus != B_OK)
821 		return;
822 
823 	fEntry->type = type;
824 	fEntry->size = 0;
825 }
826 
827 
828 AttributeEntry::~AttributeEntry()
829 {
830 	if (fAllocatedEntry)
831 		free(fEntry);
832 	if (fAllocatedData)
833 		free(fData);
834 }
835 
836 
837 size_t
838 AttributeEntry::EntrySize()
839 {
840 	return sizeof(attribute_entry) - 1 + fEntry->name_length;
841 }
842 
843 
844 status_t
845 AttributeEntry::SetType(type_code type)
846 {
847 	fEntry->type = type;
848 	return B_OK;
849 }
850 
851 
852 status_t
853 AttributeEntry::SetSize(size_t size)
854 {
855 	if (size <= fEntry->size) {
856 		fEntry->size = size;
857 		return B_OK;
858 	}
859 
860 	if (fAllocatedData) {
861 		uint8 *newData = (uint8 *)realloc(fData, size);
862 		if (newData == NULL) {
863 			fStatus = B_NO_MEMORY;
864 			return fStatus;
865 		}
866 
867 		fData = newData;
868 		fEntry->size = size;
869 		return B_OK;
870 	}
871 
872 	uint8 *newData = (uint8 *)malloc(size);
873 	if (newData == NULL) {
874 		fStatus = B_NO_MEMORY;
875 		return fStatus;
876 	}
877 
878 	memcpy(newData, fData, min_c(fEntry->size, size));
879 	fEntry->size = size;
880 	fAllocatedData = true;
881 	fData = newData;
882 	return B_OK;
883 }
884 
885 
886 status_t
887 AttributeEntry::SetName(const char *name)
888 {
889 	size_t nameLength = strlen(name) + 1;
890 	if (nameLength > 255) {
891 		fStatus = B_NAME_TOO_LONG;
892 		return fStatus;
893 	}
894 
895 	if (!fAllocatedEntry || fEntry->name_length < nameLength) {
896 		attribute_entry *newEntry = (attribute_entry *)malloc(
897 			sizeof(attribute_entry) - 1 + nameLength);
898 		if (newEntry == NULL) {
899 			fStatus = B_NO_MEMORY;
900 			return fStatus;
901 		}
902 
903 		if (fEntry != NULL)
904 			memcpy(newEntry, fEntry, sizeof(attribute_entry) - 1);
905 		if (fAllocatedEntry)
906 			free(fEntry);
907 
908 		fAllocatedEntry = true;
909 		fEntry = newEntry;
910 	}
911 
912 	fEntry->name_length = nameLength;
913 	strlcpy(fEntry->name, name, nameLength);
914 	return B_OK;
915 }
916 
917 
918 status_t
919 AttributeEntry::FillDirent(struct dirent *dirent, size_t bufferSize,
920 	uint32 *numEntries)
921 {
922 	dirent->d_dev = dirent->d_pdev = fParent->VolumeID();
923 	dirent->d_ino = (ino_t)this;
924 	dirent->d_pino = fParent->FileInode();
925 	dirent->d_reclen = sizeof(struct dirent) + fEntry->name_length;
926 	if (bufferSize < dirent->d_reclen) {
927 		*numEntries = 0;
928 		return B_BAD_VALUE;
929 	}
930 
931 	strncpy(dirent->d_name, fEntry->name, fEntry->name_length);
932 	dirent->d_name[fEntry->name_length - 1] = 0;
933 	*numEntries = 1;
934 	return B_OK;
935 }
936 
937 
938 status_t
939 AttributeEntry::Read(off_t position, void *buffer, size_t *length)
940 {
941 	*length = min_c(*length, fEntry->size - position);
942 	memcpy(buffer, fData + position, *length);
943 	return B_OK;
944 }
945 
946 
947 status_t
948 AttributeEntry::Write(off_t position, const void *buffer, size_t *length)
949 {
950 	size_t neededSize = position + *length;
951 	if (neededSize > fEntry->size) {
952 		status_t result = SetSize(neededSize);
953 		if (result != B_OK) {
954 			*length = 0;
955 			return result;
956 		}
957 	}
958 
959 	memcpy(fData + position, buffer, *length);
960 	notify_attribute_changed(fParent->VolumeID(), fParent->FileInode(),
961 		fEntry->name, B_ATTR_CHANGED);
962 	return B_OK;
963 }
964 
965 
966 status_t
967 AttributeEntry::ReadStat(struct stat *stat)
968 {
969 	stat->st_dev = fParent->VolumeID();
970 	stat->st_ino = (ino_t)this;
971 	stat->st_nlink = 1;
972 	stat->st_blksize = 512;
973 	stat->st_uid = 1;
974 	stat->st_gid = 1;
975 	stat->st_size = fEntry->size;
976 	stat->st_mode = S_ATTR | 0x0777;
977 	stat->st_type = fEntry->type;
978 	stat->st_atime = stat->st_mtime = stat->st_crtime = time(NULL);
979 	stat->st_blocks = (fEntry->size + stat->st_blksize - 1) / stat->st_blksize;
980 	return B_OK;
981 }
982 
983 
984 status_t
985 AttributeEntry::WriteStat(const struct stat *stat, uint32 statMask)
986 {
987 	return B_UNSUPPORTED;
988 }
989 
990 
991 //	#pragma mark - vnode ops
992 
993 
994 #define OVERLAY_CALL(op, params...) \
995 	TRACE("relaying op: " #op "\n"); \
996 	OverlayInode *node = (OverlayInode *)vnode->private_node; \
997 	fs_vnode *superVnode = node->SuperVnode(); \
998 	if (superVnode->ops->op != NULL) \
999 		return superVnode->ops->op(volume->super_volume, superVnode, params);
1000 
1001 
1002 static status_t
1003 overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1004 {
1005 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1006 	fs_vnode *superVnode = node->SuperVnode();
1007 
1008 	status_t result = B_OK;
1009 	if (superVnode->ops->put_vnode != NULL) {
1010 		result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
1011 			reenter);
1012 	}
1013 
1014 	delete node;
1015 	return result;
1016 }
1017 
1018 
1019 static status_t
1020 overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1021 {
1022 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1023 	fs_vnode *superVnode = node->SuperVnode();
1024 
1025 	status_t result = B_OK;
1026 	if (superVnode->ops->remove_vnode != NULL) {
1027 		result = superVnode->ops->remove_vnode(volume->super_volume, superVnode,
1028 			reenter);
1029 	}
1030 
1031 	delete node;
1032 	return result;
1033 }
1034 
1035 
1036 static status_t
1037 overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode,
1038 	fs_volume *superVolume, fs_vnode *_superVnode)
1039 {
1040 	if (volume == superVolume) {
1041 		*_superVnode = *vnode;
1042 		return B_OK;
1043 	}
1044 
1045 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1046 	fs_vnode *superVnode = node->SuperVnode();
1047 
1048 	if (superVnode->ops->get_super_vnode != NULL) {
1049 		return superVnode->ops->get_super_vnode(volume->super_volume,
1050 			superVnode, superVolume, _superVnode);
1051 	}
1052 
1053 	*_superVnode = *superVnode;
1054 	return B_OK;
1055 }
1056 
1057 
1058 static status_t
1059 overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id)
1060 {
1061 	OVERLAY_CALL(lookup, name, id)
1062 	return B_UNSUPPORTED;
1063 }
1064 
1065 
1066 static status_t
1067 overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer,
1068 	size_t bufferSize)
1069 {
1070 	OVERLAY_CALL(get_vnode_name, buffer, bufferSize)
1071 	return B_UNSUPPORTED;
1072 }
1073 
1074 
1075 static bool
1076 overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie)
1077 {
1078 	OVERLAY_CALL(can_page, cookie)
1079 	return false;
1080 }
1081 
1082 
1083 static status_t
1084 overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1085 	const iovec *vecs, size_t count, size_t *numBytes)
1086 {
1087 	OVERLAY_CALL(read_pages, cookie, pos, vecs, count, numBytes)
1088 	return B_UNSUPPORTED;
1089 }
1090 
1091 
1092 static status_t
1093 overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1094 	const iovec *vecs, size_t count, size_t *numBytes)
1095 {
1096 	OVERLAY_CALL(write_pages, cookie, pos, vecs, count, numBytes)
1097 	return B_UNSUPPORTED;
1098 }
1099 
1100 
1101 #if 0
1102 static status_t
1103 overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1104 	io_request *request)
1105 {
1106 	OVERLAY_CALL(io, cookie, request)
1107 	return B_UNSUPPORTED;
1108 }
1109 #endif
1110 
1111 
1112 static status_t
1113 overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1114 	io_request *request)
1115 {
1116 	OVERLAY_CALL(cancel_io, cookie, request)
1117 	return B_UNSUPPORTED;
1118 }
1119 
1120 
1121 static status_t
1122 overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset,
1123 	size_t size, struct file_io_vec *vecs, size_t *count)
1124 {
1125 	OVERLAY_CALL(get_file_map, offset, size, vecs, count)
1126 	return B_UNSUPPORTED;
1127 }
1128 
1129 
1130 static status_t
1131 overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, ulong op,
1132 	void *buffer, size_t length)
1133 {
1134 	OVERLAY_CALL(ioctl, cookie, op, buffer, length)
1135 	return B_UNSUPPORTED;
1136 }
1137 
1138 
1139 static status_t
1140 overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie,
1141 	int flags)
1142 {
1143 	OVERLAY_CALL(set_flags, cookie, flags)
1144 	return B_UNSUPPORTED;
1145 }
1146 
1147 
1148 static status_t
1149 overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1150 	selectsync *sync)
1151 {
1152 	OVERLAY_CALL(select, cookie, event, sync)
1153 	return B_UNSUPPORTED;
1154 }
1155 
1156 
1157 static status_t
1158 overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1159 	selectsync *sync)
1160 {
1161 	OVERLAY_CALL(deselect, cookie, event, sync)
1162 	return B_UNSUPPORTED;
1163 }
1164 
1165 
1166 static status_t
1167 overlay_fsync(fs_volume *volume, fs_vnode *vnode)
1168 {
1169 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1170 	fs_vnode *superVnode = node->SuperVnode();
1171 
1172 	if (superVnode->ops->fsync != NULL)
1173 		return superVnode->ops->fsync(volume->super_volume, superVnode);
1174 
1175 	return B_OK;
1176 }
1177 
1178 
1179 static status_t
1180 overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer,
1181 	size_t *bufferSize)
1182 {
1183 	OVERLAY_CALL(read_symlink, buffer, bufferSize)
1184 	return B_UNSUPPORTED;
1185 }
1186 
1187 
1188 static status_t
1189 overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name,
1190 	const char *path, int mode)
1191 {
1192 	OVERLAY_CALL(create_symlink, name, path, mode)
1193 	return B_UNSUPPORTED;
1194 }
1195 
1196 
1197 static status_t
1198 overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name,
1199 	fs_vnode *target)
1200 {
1201 	OVERLAY_CALL(link, name, target)
1202 	return B_UNSUPPORTED;
1203 }
1204 
1205 
1206 static status_t
1207 overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name)
1208 {
1209 	OVERLAY_CALL(unlink, name)
1210 	return B_UNSUPPORTED;
1211 }
1212 
1213 
1214 static status_t
1215 overlay_rename(fs_volume *volume, fs_vnode *vnode,
1216 	const char *fromName, fs_vnode *toDir, const char *toName)
1217 {
1218 	OVERLAY_CALL(rename, fromName, toDir, toName)
1219 	return B_UNSUPPORTED;
1220 }
1221 
1222 
1223 static status_t
1224 overlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
1225 {
1226 	OVERLAY_CALL(access, mode)
1227 	return B_UNSUPPORTED;
1228 }
1229 
1230 
1231 static status_t
1232 overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat)
1233 {
1234 	OVERLAY_CALL(read_stat, stat)
1235 	return B_UNSUPPORTED;
1236 }
1237 
1238 
1239 static status_t
1240 overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat,
1241 	uint32 statMask)
1242 {
1243 	OVERLAY_CALL(write_stat, stat, statMask)
1244 	return B_UNSUPPORTED;
1245 }
1246 
1247 
1248 static status_t
1249 overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name,
1250 	int openMode, int perms, void **cookie, ino_t *newVnodeID)
1251 {
1252 	OVERLAY_CALL(create, name, openMode, perms, cookie, newVnodeID)
1253 	return B_UNSUPPORTED;
1254 }
1255 
1256 
1257 static status_t
1258 overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie)
1259 {
1260 	OVERLAY_CALL(open, openMode, cookie)
1261 	return B_UNSUPPORTED;
1262 }
1263 
1264 
1265 static status_t
1266 overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie)
1267 {
1268 	OVERLAY_CALL(close, cookie)
1269 	return B_UNSUPPORTED;
1270 }
1271 
1272 
1273 static status_t
1274 overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1275 {
1276 	OVERLAY_CALL(free_cookie, cookie)
1277 	return B_UNSUPPORTED;
1278 }
1279 
1280 
1281 static status_t
1282 overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1283 	void *buffer, size_t *length)
1284 {
1285 	OVERLAY_CALL(read, cookie, pos, buffer, length)
1286 	return B_UNSUPPORTED;
1287 }
1288 
1289 
1290 static status_t
1291 overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1292 	const void *buffer, size_t *length)
1293 {
1294 	OVERLAY_CALL(write, cookie, pos, buffer, length)
1295 	return B_UNSUPPORTED;
1296 }
1297 
1298 
1299 static status_t
1300 overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name,
1301 	int perms)
1302 {
1303 	OVERLAY_CALL(create_dir, name, perms)
1304 	return B_UNSUPPORTED;
1305 }
1306 
1307 
1308 static status_t
1309 overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name)
1310 {
1311 	OVERLAY_CALL(remove_dir, name)
1312 	return B_UNSUPPORTED;
1313 }
1314 
1315 
1316 static status_t
1317 overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
1318 {
1319 	OVERLAY_CALL(open_dir, cookie)
1320 	return B_UNSUPPORTED;
1321 }
1322 
1323 
1324 static status_t
1325 overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1326 {
1327 	OVERLAY_CALL(close_dir, cookie)
1328 	return B_UNSUPPORTED;
1329 }
1330 
1331 
1332 static status_t
1333 overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1334 {
1335 	OVERLAY_CALL(free_dir_cookie, cookie)
1336 	return B_UNSUPPORTED;
1337 }
1338 
1339 
1340 static status_t
1341 overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
1342 	struct dirent *buffer, size_t bufferSize, uint32 *num)
1343 {
1344 	TRACE("relaying op: read_dir\n");
1345 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1346 	fs_vnode *superVnode = node->SuperVnode();
1347 	if (superVnode->ops->read_dir != NULL) {
1348 		status_t result = superVnode->ops->read_dir(volume->super_volume,
1349 			superVnode, cookie, buffer, bufferSize, num);
1350 
1351 		// TODO: handle multiple records
1352 		if (result == B_OK && *num == 1 && strcmp(buffer->d_name,
1353 			ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) {
1354 			// skip over the attribute directory
1355 			return superVnode->ops->read_dir(volume->super_volume, superVnode,
1356 				cookie, buffer, bufferSize, num);
1357 		}
1358 
1359 		return result;
1360 	}
1361 
1362 	return B_UNSUPPORTED;
1363 }
1364 
1365 
1366 static status_t
1367 overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1368 {
1369 	OVERLAY_CALL(rewind_dir, cookie)
1370 	return B_UNSUPPORTED;
1371 }
1372 
1373 
1374 static status_t
1375 overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
1376 {
1377 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1378 	AttributeFile *attributeFile = NULL;
1379 	status_t result = node->GetAttributeFile(&attributeFile);
1380 	if (result != B_OK)
1381 		return result;
1382 
1383 	attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)malloc(
1384 		sizeof(attribute_dir_cookie));
1385 	if (dirCookie == NULL)
1386 		return B_NO_MEMORY;
1387 
1388 	dirCookie->file = attributeFile;
1389 	dirCookie->index = 0;
1390 	*cookie = dirCookie;
1391 	return B_OK;
1392 }
1393 
1394 
1395 static status_t
1396 overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1397 {
1398 	return B_OK;
1399 }
1400 
1401 
1402 static status_t
1403 overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1404 {
1405 	free(cookie);
1406 	return B_OK;
1407 }
1408 
1409 
1410 static status_t
1411 overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
1412 	struct dirent *buffer, size_t bufferSize, uint32 *num)
1413 {
1414 	attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie;
1415 	return dirCookie->file->ReadAttributeDir(buffer, bufferSize, num,
1416 		&dirCookie->index);
1417 }
1418 
1419 
1420 static status_t
1421 overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1422 {
1423 	attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie;
1424 	dirCookie->index = 0;
1425 	return B_OK;
1426 }
1427 
1428 
1429 static status_t
1430 overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
1431 	uint32 type, int openMode, void **cookie)
1432 {
1433 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1434 	AttributeFile *attributeFile = NULL;
1435 	status_t result = node->GetAttributeFile(&attributeFile);
1436 	if (result != B_OK)
1437 		return result;
1438 
1439 	return attributeFile->CreateAttribute(name, type, openMode,
1440 		(AttributeEntry **)cookie);
1441 }
1442 
1443 
1444 static status_t
1445 overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
1446 	int openMode, void **cookie)
1447 {
1448 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1449 	AttributeFile *attributeFile = NULL;
1450 	status_t result = node->GetAttributeFile(&attributeFile);
1451 	if (result != B_OK)
1452 		return result;
1453 
1454 	return attributeFile->OpenAttribute(name, openMode,
1455 		(AttributeEntry **)cookie);
1456 }
1457 
1458 
1459 static status_t
1460 overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie)
1461 {
1462 	return B_OK;
1463 }
1464 
1465 
1466 static status_t
1467 overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1468 {
1469 	return B_OK;
1470 }
1471 
1472 
1473 static status_t
1474 overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1475 	void *buffer, size_t *length)
1476 {
1477 	return ((AttributeEntry *)cookie)->Read(pos, buffer, length);
1478 }
1479 
1480 
1481 static status_t
1482 overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1483 	const void *buffer, size_t *length)
1484 {
1485 	return ((AttributeEntry *)cookie)->Write(pos, buffer, length);
1486 }
1487 
1488 
1489 static status_t
1490 overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
1491 	struct stat *stat)
1492 {
1493 	return ((AttributeEntry *)cookie)->ReadStat(stat);
1494 }
1495 
1496 
1497 static status_t
1498 overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
1499 	const struct stat *stat, int statMask)
1500 {
1501 	return ((AttributeEntry *)cookie)->WriteStat(stat, statMask);
1502 }
1503 
1504 
1505 static status_t
1506 overlay_rename_attr(fs_volume *volume, fs_vnode *vnode,
1507 	const char *fromName, fs_vnode *toVnode, const char *toName)
1508 {
1509 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1510 	AttributeFile *attributeFile = NULL;
1511 	status_t result = node->GetAttributeFile(&attributeFile);
1512 	if (result != B_OK)
1513 		return B_OK;
1514 
1515 	AttributeFile *toAttributeFile = attributeFile;
1516 	if (vnode->private_node != toVnode->private_node) {
1517 		OverlayInode *toNode = (OverlayInode *)toVnode->private_node;
1518 		result = toNode->GetAttributeFile(&toAttributeFile);
1519 		if (result != B_OK)
1520 			return result;
1521 	}
1522 
1523 	AttributeEntry *entry = NULL;
1524 	result = attributeFile->RemoveAttribute(fromName, &entry);
1525 	if (result != B_OK)
1526 		return result;
1527 
1528 	result = entry->SetName(toName);
1529 	if (result != B_OK) {
1530 		if (attributeFile->AddAttribute(entry) != B_OK)
1531 			delete entry;
1532 		return result;
1533 	}
1534 
1535 	result = toAttributeFile->AddAttribute(entry);
1536 	if (result != B_OK) {
1537 		if (entry->SetName(fromName) != B_OK
1538 			|| attributeFile->AddAttribute(entry) != B_OK)
1539 			delete entry;
1540 		return result;
1541 	}
1542 
1543 	return B_OK;
1544 }
1545 
1546 
1547 static status_t
1548 overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name)
1549 {
1550 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1551 	AttributeFile *attributeFile = NULL;
1552 	status_t result = node->GetAttributeFile(&attributeFile);
1553 	if (result != B_OK)
1554 		return result;
1555 
1556 	return attributeFile->RemoveAttribute(name, NULL);
1557 }
1558 
1559 
1560 static status_t
1561 overlay_create_special_node(fs_volume *volume, fs_vnode *vnode,
1562 	const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags,
1563 	fs_vnode *_superVnode, ino_t *nodeID)
1564 {
1565 	OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, nodeID)
1566 	return B_UNSUPPORTED;
1567 }
1568 
1569 
1570 static fs_vnode_ops sOverlayVnodeOps = {
1571 	&overlay_lookup,
1572 	&overlay_get_vnode_name,
1573 
1574 	&overlay_put_vnode,
1575 	&overlay_remove_vnode,
1576 
1577 	&overlay_can_page,
1578 	&overlay_read_pages,
1579 	&overlay_write_pages,
1580 
1581 	// TODO: the io scheduler uses it when available but we may simply
1582 	// return B_UNSUPPORTED and I'm not sure it then falls back correctly
1583 	NULL, //&overlay_io,
1584 	&overlay_cancel_io,
1585 
1586 	&overlay_get_file_map,
1587 
1588 	/* common */
1589 	&overlay_ioctl,
1590 	&overlay_set_flags,
1591 	&overlay_select,
1592 	&overlay_deselect,
1593 	&overlay_fsync,
1594 
1595 	&overlay_read_symlink,
1596 	&overlay_create_symlink,
1597 	&overlay_link,
1598 	&overlay_unlink,
1599 	&overlay_rename,
1600 
1601 	&overlay_access,
1602 	&overlay_read_stat,
1603 	&overlay_write_stat,
1604 
1605 	/* file */
1606 	&overlay_create,
1607 	&overlay_open,
1608 	&overlay_close,
1609 	&overlay_free_cookie,
1610 	&overlay_read,
1611 	&overlay_write,
1612 
1613 	/* directory */
1614 	&overlay_create_dir,
1615 	&overlay_remove_dir,
1616 	&overlay_open_dir,
1617 	&overlay_close_dir,
1618 	&overlay_free_dir_cookie,
1619 	&overlay_read_dir,
1620 	&overlay_rewind_dir,
1621 
1622 	/* attribute directory operations */
1623 	&overlay_open_attr_dir,
1624 	&overlay_close_attr_dir,
1625 	&overlay_free_attr_dir_cookie,
1626 	&overlay_read_attr_dir,
1627 	&overlay_rewind_attr_dir,
1628 
1629 	/* attribute operations */
1630 	&overlay_create_attr,
1631 	&overlay_open_attr,
1632 	&overlay_close_attr,
1633 	&overlay_free_attr_cookie,
1634 	&overlay_read_attr,
1635 	&overlay_write_attr,
1636 
1637 	&overlay_read_attr_stat,
1638 	&overlay_write_attr_stat,
1639 	&overlay_rename_attr,
1640 	&overlay_remove_attr,
1641 
1642 	/* support for node and FS layers */
1643 	&overlay_create_special_node,
1644 	&overlay_get_super_vnode
1645 };
1646 
1647 
1648 //	#pragma mark - volume ops
1649 
1650 
1651 #define OVERLAY_VOLUME_CALL(op, params...) \
1652 	TRACE_VOLUME("relaying volume op: " #op "\n"); \
1653 	if (volume->super_volume->ops->op != NULL) \
1654 		return volume->super_volume->ops->op(volume->super_volume, params);
1655 
1656 
1657 static status_t
1658 overlay_unmount(fs_volume *volume)
1659 {
1660 	TRACE_VOLUME("relaying volume op: unmount\n");
1661 	if (volume->super_volume != NULL
1662 		&& volume->super_volume->ops != NULL
1663 		&& volume->super_volume->ops->unmount != NULL)
1664 		volume->super_volume->ops->unmount(volume->super_volume);
1665 
1666 	delete (OverlayVolume *)volume->private_volume;
1667 	return B_OK;
1668 }
1669 
1670 
1671 static status_t
1672 overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
1673 {
1674 	TRACE_VOLUME("relaying volume op: read_fs_info\n");
1675 	status_t result = B_UNSUPPORTED;
1676 	if (volume->super_volume->ops->read_fs_info != NULL) {
1677 		result = volume->super_volume->ops->read_fs_info(volume->super_volume,
1678 			info);
1679 		if (result != B_OK)
1680 			return result;
1681 
1682 		info->flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR /*| B_FS_HAS_QUERY*/;
1683 		return B_OK;
1684 	}
1685 
1686 	return B_UNSUPPORTED;
1687 }
1688 
1689 
1690 static status_t
1691 overlay_write_fs_info(fs_volume *volume, const struct fs_info *info,
1692 	uint32 mask)
1693 {
1694 	OVERLAY_VOLUME_CALL(write_fs_info, info, mask)
1695 	return B_UNSUPPORTED;
1696 }
1697 
1698 
1699 static status_t
1700 overlay_sync(fs_volume *volume)
1701 {
1702 	TRACE_VOLUME("relaying volume op: sync\n");
1703 	if (volume->super_volume->ops->sync != NULL)
1704 		return volume->super_volume->ops->sync(volume->super_volume);
1705 	return B_UNSUPPORTED;
1706 }
1707 
1708 
1709 static status_t
1710 overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type,
1711 	uint32 *_flags, bool reenter)
1712 {
1713 	TRACE_VOLUME("relaying volume op: get_vnode\n");
1714 	if (volume->super_volume->ops->get_vnode != NULL) {
1715 		status_t status = volume->super_volume->ops->get_vnode(
1716 			volume->super_volume, id, vnode, _type, _flags, reenter);
1717 		if (status != B_OK)
1718 			return status;
1719 
1720 		OverlayInode *node = new(std::nothrow) OverlayInode(
1721 			(OverlayVolume *)volume->private_volume, vnode, id);
1722 		if (node == NULL) {
1723 			vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
1724 			return B_NO_MEMORY;
1725 		}
1726 
1727 		status = node->InitCheck();
1728 		if (status != B_OK) {
1729 			delete node;
1730 			return status;
1731 		}
1732 
1733 		vnode->private_node = node;
1734 		vnode->ops = &sOverlayVnodeOps;
1735 		return B_OK;
1736 	}
1737 
1738 	return B_UNSUPPORTED;
1739 }
1740 
1741 
1742 static status_t
1743 overlay_open_index_dir(fs_volume *volume, void **cookie)
1744 {
1745 	OVERLAY_VOLUME_CALL(open_index_dir, cookie)
1746 	return B_UNSUPPORTED;
1747 }
1748 
1749 
1750 static status_t
1751 overlay_close_index_dir(fs_volume *volume, void *cookie)
1752 {
1753 	OVERLAY_VOLUME_CALL(close_index_dir, cookie)
1754 	return B_UNSUPPORTED;
1755 }
1756 
1757 
1758 static status_t
1759 overlay_free_index_dir_cookie(fs_volume *volume, void *cookie)
1760 {
1761 	OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie)
1762 	return B_UNSUPPORTED;
1763 }
1764 
1765 
1766 static status_t
1767 overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer,
1768 	size_t bufferSize, uint32 *_num)
1769 {
1770 	OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num)
1771 	return B_UNSUPPORTED;
1772 }
1773 
1774 
1775 static status_t
1776 overlay_rewind_index_dir(fs_volume *volume, void *cookie)
1777 {
1778 	OVERLAY_VOLUME_CALL(rewind_index_dir, cookie)
1779 	return B_UNSUPPORTED;
1780 }
1781 
1782 
1783 static status_t
1784 overlay_create_index(fs_volume *volume, const char *name, uint32 type,
1785 	uint32 flags)
1786 {
1787 	OVERLAY_VOLUME_CALL(create_index, name, type, flags)
1788 	return B_UNSUPPORTED;
1789 }
1790 
1791 
1792 static status_t
1793 overlay_remove_index(fs_volume *volume, const char *name)
1794 {
1795 	OVERLAY_VOLUME_CALL(remove_index, name)
1796 	return B_UNSUPPORTED;
1797 }
1798 
1799 
1800 static status_t
1801 overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat)
1802 {
1803 	OVERLAY_VOLUME_CALL(read_index_stat, name, stat)
1804 	return B_UNSUPPORTED;
1805 }
1806 
1807 
1808 static status_t
1809 overlay_open_query(fs_volume *volume, const char *query, uint32 flags,
1810 	port_id port, uint32 token, void **_cookie)
1811 {
1812 	OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie)
1813 	return B_UNSUPPORTED;
1814 }
1815 
1816 
1817 static status_t
1818 overlay_close_query(fs_volume *volume, void *cookie)
1819 {
1820 	OVERLAY_VOLUME_CALL(close_query, cookie)
1821 	return B_UNSUPPORTED;
1822 }
1823 
1824 
1825 static status_t
1826 overlay_free_query_cookie(fs_volume *volume, void *cookie)
1827 {
1828 	OVERLAY_VOLUME_CALL(free_query_cookie, cookie)
1829 	return B_UNSUPPORTED;
1830 }
1831 
1832 
1833 static status_t
1834 overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer,
1835 	size_t bufferSize, uint32 *_num)
1836 {
1837 	OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num)
1838 	return B_UNSUPPORTED;
1839 }
1840 
1841 
1842 static status_t
1843 overlay_rewind_query(fs_volume *volume, void *cookie)
1844 {
1845 	OVERLAY_VOLUME_CALL(rewind_query, cookie)
1846 	return B_UNSUPPORTED;
1847 }
1848 
1849 
1850 static status_t
1851 overlay_all_layers_mounted(fs_volume *volume)
1852 {
1853 	return B_OK;
1854 }
1855 
1856 
1857 static status_t
1858 overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode)
1859 {
1860 	OverlayInode *node = new(std::nothrow) OverlayInode(
1861 		(OverlayVolume *)volume->private_volume, vnode, id);
1862 	if (node == NULL)
1863 		return B_NO_MEMORY;
1864 
1865 	status_t status = node->InitCheck();
1866 	if (status != B_OK) {
1867 		delete node;
1868 		return status;
1869 	}
1870 
1871 	vnode->private_node = node;
1872 	vnode->ops = &sOverlayVnodeOps;
1873 	return B_OK;
1874 }
1875 
1876 
1877 static status_t
1878 overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode)
1879 {
1880 	delete (OverlayInode *)vnode;
1881 	return B_OK;
1882 }
1883 
1884 
1885 static fs_volume_ops sOverlayVolumeOps = {
1886 	&overlay_unmount,
1887 
1888 	&overlay_read_fs_info,
1889 	&overlay_write_fs_info,
1890 	&overlay_sync,
1891 
1892 	&overlay_get_vnode,
1893 	&overlay_open_index_dir,
1894 	&overlay_close_index_dir,
1895 	&overlay_free_index_dir_cookie,
1896 	&overlay_read_index_dir,
1897 	&overlay_rewind_index_dir,
1898 
1899 	&overlay_create_index,
1900 	&overlay_remove_index,
1901 	&overlay_read_index_stat,
1902 
1903 	&overlay_open_query,
1904 	&overlay_close_query,
1905 	&overlay_free_query_cookie,
1906 	&overlay_read_query,
1907 	&overlay_rewind_query,
1908 
1909 	&overlay_all_layers_mounted,
1910 	&overlay_create_sub_vnode,
1911 	&overlay_delete_sub_vnode
1912 };
1913 
1914 
1915 //	#pragma mark - filesystem module
1916 
1917 
1918 static status_t
1919 overlay_mount(fs_volume *volume, const char *device, uint32 flags,
1920 	const char *args, ino_t *rootID)
1921 {
1922 	TRACE_VOLUME("mounting attribute overlay\n");
1923 	volume->private_volume = new(std::nothrow) OverlayVolume(volume);
1924 	if (volume->private_volume == NULL)
1925 		return B_NO_MEMORY;
1926 
1927 	volume->ops = &sOverlayVolumeOps;
1928 	return B_OK;
1929 }
1930 
1931 
1932 static status_t
1933 overlay_std_ops(int32 op, ...)
1934 {
1935 	switch (op) {
1936 		case B_MODULE_INIT:
1937 		case B_MODULE_UNINIT:
1938 			return B_OK;
1939 		default:
1940 			return B_ERROR;
1941 	}
1942 }
1943 
1944 
1945 static file_system_module_info sOverlayFileSystem = {
1946 	{
1947 		"file_systems/attribute_overlay"B_CURRENT_FS_API_VERSION,
1948 		0,
1949 		overlay_std_ops,
1950 	},
1951 
1952 	"attribute_overlay",				// short_name
1953 	"Attribute Overlay File System",	// pretty_name
1954 	0,									// DDM flags
1955 
1956 	// scanning
1957 	NULL, // identify_partition
1958 	NULL, // scan_partition
1959 	NULL, // free_identify_partition_cookie
1960 	NULL, // free_partition_content_cookie
1961 
1962 	// general operations
1963 	&overlay_mount,
1964 
1965 	// capability querying
1966 	NULL, // get_supported_operations
1967 
1968 	NULL, // validate_resize
1969 	NULL, // validate_move
1970 	NULL, // validate_set_content_name
1971 	NULL, // validate_set_content_parameters
1972 	NULL, // validate_initialize
1973 
1974 	// shadow partition modification
1975 	NULL, // shadow_changed
1976 
1977 	// writing
1978 	NULL, // defragment
1979 	NULL, // repair
1980 	NULL, // resize
1981 	NULL, // move
1982 	NULL, // set_content_name
1983 	NULL, // set_content_parameters
1984 	NULL // initialize
1985 };
1986 
1987 }	// namespace attribute_overlay
1988 
1989 using namespace attribute_overlay;
1990 
1991 module_info *modules[] = {
1992 	(module_info *)&sOverlayFileSystem,
1993 	NULL,
1994 };
1995