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