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