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