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