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