xref: /haiku/src/add-ons/kernel/file_systems/layers/write_overlay/write_overlay.cpp (revision 1a3518cf757c2da8006753f83962da5935bbc82b)
1 /*
2  * Copyright 2009-2016, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  */
8 
9 #include <new>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include <dirent.h>
14 
15 #include <util/kernel_cpp.h>
16 #include <util/AutoLock.h>
17 
18 #include <fs_cache.h>
19 #include <fs_info.h>
20 #include <fs_interface.h>
21 #include <io_requests.h>
22 
23 #include <debug.h>
24 #include <KernelExport.h>
25 #include <NodeMonitor.h>
26 
27 #include "IORequest.h"
28 
29 
30 //#define TRACE_OVERLAY
31 #ifdef TRACE_OVERLAY
32 #define TRACE(x...)			dprintf("write_overlay: " x)
33 #define TRACE_VOLUME(x...)	dprintf("write_overlay: " x)
34 #define TRACE_ALWAYS(x...)	dprintf("write_overlay: " x)
35 #else
36 #define TRACE(x...)			/* nothing */
37 #define TRACE_VOLUME(x...)	/* nothing */
38 #define TRACE_ALWAYS(x...)	dprintf("write_overlay: " x)
39 #endif
40 
41 
42 namespace write_overlay {
43 
44 status_t publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber,
45 	void *privateNode, int type);
46 
47 class OverlayInode;
48 
49 struct open_cookie {
50 	OverlayInode *	node;
51 	int				open_mode;
52 	void *			super_cookie;
53 };
54 
55 
56 struct open_dir_cookie {
57 	uint32			index;
58 };
59 
60 
61 struct overlay_dirent {
62 	ino_t			inode_number;
63 	char *			name;
64 	OverlayInode *	node; // only for attributes
65 
66 	void			remove_and_dispose(fs_volume *volume, ino_t directoryInode)
67 					{
68 						notify_entry_removed(volume->id, directoryInode,
69 							name, inode_number);
70 						remove_vnode(volume, inode_number);
71 						free(name);
72 						free(this);
73 					}
74 
75 	void			dispose_attribute(fs_volume *volume, ino_t fileInode)
76 					{
77 						notify_attribute_changed(volume->id, -1, fileInode,
78 							name, B_ATTR_REMOVED);
79 						free(name);
80 						free(this);
81 					}
82 };
83 
84 
85 struct write_buffer {
86 	write_buffer *	next;
87 	off_t			position;
88 	size_t			length;
89 	uint8			buffer[1];
90 };
91 
92 
93 class OverlayVolume {
94 public:
95 							OverlayVolume(fs_volume *volume);
96 							~OverlayVolume();
97 
98 		fs_volume *			Volume() { return fVolume; }
99 		fs_volume *			SuperVolume() { return fVolume->super_volume; }
100 
101 		ino_t				BuildInodeNumber() { return fCurrentInodeNumber++; }
102 
103 private:
104 		fs_volume *			fVolume;
105 		ino_t				fCurrentInodeNumber;
106 };
107 
108 
109 class OverlayInode {
110 public:
111 							OverlayInode(OverlayVolume *volume,
112 								fs_vnode *superVnode, ino_t inodeNumber,
113 								OverlayInode *parentDir = NULL,
114 								const char *name = NULL, mode_t mode = 0,
115 								bool attribute = false,
116 								type_code attributeType = 0);
117 							~OverlayInode();
118 
119 		status_t			InitCheck();
120 
121 		bool				Lock() { return recursive_lock_lock(&fLock) == B_OK; }
122 		void				Unlock() { recursive_lock_unlock(&fLock); }
123 
124 		bool				IsVirtual() { return fIsVirtual; }
125 		bool				IsModified() { return fIsModified; }
126 		bool				IsDataModified() { return fIsDataModified; }
127 		bool				IsAttribute() { return fIsAttribute; }
128 
129 		fs_volume *			Volume() { return fVolume->Volume(); }
130 		fs_volume *			SuperVolume() { return fVolume->SuperVolume(); }
131 
132 		void				SetSuperVnode(fs_vnode *superVnode);
133 		fs_vnode *			SuperVnode() { return &fSuperVnode; }
134 
135 		void				SetInodeNumber(ino_t inodeNumber);
136 		ino_t				InodeNumber() { return fInodeNumber; }
137 
138 		void				SetModified();
139 		void				SetDataModified();
140 		void				CreateCache();
141 
142 		void				SetParentDir(OverlayInode *parentDir);
143 		OverlayInode *		ParentDir() { return fParentDir; }
144 
145 		bool				IsNonEmptyDirectory();
146 
147 		status_t			Lookup(const char *name, ino_t *inodeNumber);
148 		status_t			LookupAttribute(const char *name,
149 								OverlayInode **node);
150 
151 		void				SetName(const char *name);
152 		status_t			GetName(char *buffer, size_t bufferSize);
153 
154 		status_t			ReadStat(struct stat *stat);
155 		status_t			WriteStat(const struct stat *stat, uint32 statMask);
156 
157 		status_t			Create(const char *name, int openMode, int perms,
158 								void **cookie, ino_t *newInodeNumber,
159 								bool attribute = false,
160 								type_code attributeType = 0);
161 		status_t			Open(int openMode, void **cookie);
162 		status_t			Close(void *cookie);
163 		status_t			FreeCookie(void *cookie);
164 		status_t			Read(void *cookie, off_t position, void *buffer,
165 								size_t *length, bool readPages,
166 								IORequest *ioRequest);
167 		status_t			Write(void *cookie, off_t position,
168 								const void *buffer, size_t length,
169 								IORequest *request);
170 
171 		status_t			SynchronousIO(void *cookie, IORequest *request);
172 
173 		status_t			SetFlags(void *cookie, int flags);
174 
175 		status_t			CreateDir(const char *name, int perms);
176 		status_t			RemoveDir(const char *name);
177 		status_t			OpenDir(void **cookie, bool attribute = false);
178 		status_t			CloseDir(void *cookie);
179 		status_t			FreeDirCookie(void *cookie);
180 		status_t			ReadDir(void *cookie, struct dirent *buffer,
181 								size_t bufferSize, uint32 *num,
182 								bool attribute = false);
183 		status_t			RewindDir(void *cookie);
184 
185 		status_t			CreateSymlink(const char *name, const char *path,
186 								int mode);
187 		status_t			ReadSymlink(char *buffer, size_t *bufferSize);
188 
189 		status_t			AddEntry(overlay_dirent *entry,
190 								bool attribute = false);
191 		status_t			RemoveEntry(const char *name,
192 								overlay_dirent **entry, bool attribute = false);
193 
194 private:
195 		void				_TrimBuffers();
196 
197 		status_t			_PopulateStat();
198 		status_t			_PopulateDirents();
199 		status_t			_PopulateAttributeDirents();
200 		status_t			_CreateCommon(const char *name, int type, int perms,
201 								ino_t *newInodeNumber, OverlayInode **node,
202 								bool attribute, type_code attributeType);
203 
204 		recursive_lock		fLock;
205 		OverlayVolume *		fVolume;
206 		OverlayInode *		fParentDir;
207 		const char *		fName;
208 		fs_vnode			fSuperVnode;
209 		ino_t				fInodeNumber;
210 		write_buffer *		fWriteBuffers;
211 		off_t				fOriginalNodeLength;
212 		overlay_dirent **	fDirents;
213 		uint32				fDirentCount;
214 		overlay_dirent **	fAttributeDirents;
215 		uint32				fAttributeDirentCount;
216 		struct stat			fStat;
217 		bool				fHasStat;
218 		bool				fHasDirents;
219 		bool				fHasAttributeDirents;
220 		bool				fIsVirtual;
221 		bool				fIsAttribute;
222 		bool				fIsModified;
223 		bool				fIsDataModified;
224 		void *				fFileCache;
225 };
226 
227 
228 //	#pragma mark OverlayVolume
229 
230 
231 OverlayVolume::OverlayVolume(fs_volume *volume)
232 	:	fVolume(volume),
233 		fCurrentInodeNumber((ino_t)1 << 60)
234 {
235 }
236 
237 
238 OverlayVolume::~OverlayVolume()
239 {
240 }
241 
242 
243 //	#pragma mark OverlayInode
244 
245 
246 OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode,
247 	ino_t inodeNumber, OverlayInode *parentDir, const char *name, mode_t mode,
248 	bool attribute, type_code attributeType)
249 	:	fVolume(volume),
250 		fParentDir(parentDir),
251 		fName(name),
252 		fInodeNumber(inodeNumber),
253 		fWriteBuffers(NULL),
254 		fOriginalNodeLength(-1),
255 		fDirents(NULL),
256 		fDirentCount(0),
257 		fAttributeDirents(NULL),
258 		fAttributeDirentCount(0),
259 		fHasStat(false),
260 		fHasDirents(false),
261 		fHasAttributeDirents(false),
262 		fIsVirtual(superVnode == NULL),
263 		fIsAttribute(attribute),
264 		fIsModified(false),
265 		fIsDataModified(false),
266 		fFileCache(NULL)
267 {
268 	TRACE("inode created %" B_PRIdINO "\n", fInodeNumber);
269 
270 	recursive_lock_init(&fLock, "write overlay inode lock");
271 	if (superVnode != NULL)
272 		fSuperVnode = *superVnode;
273 	else {
274 		fStat.st_dev = SuperVolume()->id;
275 		fStat.st_ino = fInodeNumber;
276 		fStat.st_mode = mode;
277 		fStat.st_nlink = 1;
278 		fStat.st_uid = 0;
279 		fStat.st_gid = 0;
280 		fStat.st_size = 0;
281 		fStat.st_rdev = 0;
282 		fStat.st_blksize = 1024;
283 		fStat.st_atime = fStat.st_mtime = fStat.st_ctime = fStat.st_crtime
284 			= time(NULL);
285 		fStat.st_type = attributeType;
286 		fHasStat = true;
287 	}
288 }
289 
290 
291 OverlayInode::~OverlayInode()
292 {
293 	TRACE("inode destroyed %" B_PRIdINO "\n", fInodeNumber);
294 	if (fFileCache != NULL)
295 		file_cache_delete(fFileCache);
296 
297 	write_buffer *element = fWriteBuffers;
298 	while (element) {
299 		write_buffer *next = element->next;
300 		free(element);
301 		element = next;
302 	}
303 
304 	for (uint32 i = 0; i < fDirentCount; i++) {
305 		free(fDirents[i]->name);
306 		free(fDirents[i]);
307 	}
308 	free(fDirents);
309 
310 	for (uint32 i = 0; i < fAttributeDirentCount; i++) {
311 		free(fAttributeDirents[i]->name);
312 		free(fAttributeDirents[i]);
313 	}
314 	free(fAttributeDirents);
315 
316 	recursive_lock_destroy(&fLock);
317 }
318 
319 
320 status_t
321 OverlayInode::InitCheck()
322 {
323 	return B_OK;
324 }
325 
326 
327 void
328 OverlayInode::SetSuperVnode(fs_vnode *superVnode)
329 {
330 	RecursiveLocker locker(fLock);
331 	fSuperVnode = *superVnode;
332 }
333 
334 
335 void
336 OverlayInode::SetInodeNumber(ino_t inodeNumber)
337 {
338 	RecursiveLocker locker(fLock);
339 	fInodeNumber = inodeNumber;
340 }
341 
342 
343 void
344 OverlayInode::SetModified()
345 {
346 	if (fIsAttribute) {
347 		fIsModified = true;
348 		return;
349 	}
350 
351 	// we must ensure that a modified node never get's put, as we cannot get it
352 	// from the underlying filesystem, so we get an additional reference here
353 	// and deliberately leak it
354 	// TODO: what about non-force unmounting then?
355 	void *unused = NULL;
356 	get_vnode(Volume(), fInodeNumber, &unused);
357 	fIsModified = true;
358 }
359 
360 
361 void
362 OverlayInode::SetDataModified()
363 {
364 	fIsDataModified = true;
365 	if (!fIsModified)
366 		SetModified();
367 }
368 
369 
370 void
371 OverlayInode::CreateCache()
372 {
373 	if (!S_ISDIR(fStat.st_mode) && !S_ISLNK(fStat.st_mode)) {
374 		fFileCache = file_cache_create(fStat.st_dev, fStat.st_ino, 0);
375 		if (fFileCache != NULL)
376 			file_cache_disable(fFileCache);
377 	}
378 }
379 
380 
381 void
382 OverlayInode::SetParentDir(OverlayInode *parentDir)
383 {
384 	RecursiveLocker locker(fLock);
385 	fParentDir = parentDir;
386 	if (fHasDirents && fDirentCount >= 2)
387 		fDirents[1]->inode_number = parentDir->InodeNumber();
388 }
389 
390 
391 bool
392 OverlayInode::IsNonEmptyDirectory()
393 {
394 	RecursiveLocker locker(fLock);
395 	if (!fHasStat)
396 		_PopulateStat();
397 
398 	if (!S_ISDIR(fStat.st_mode))
399 		return false;
400 
401 	if (!fHasDirents)
402 		_PopulateDirents();
403 
404 	return fDirentCount > 2; // accounting for "." and ".." entries
405 }
406 
407 
408 status_t
409 OverlayInode::Lookup(const char *name, ino_t *inodeNumber)
410 {
411 	RecursiveLocker locker(fLock);
412 	if (!fHasDirents)
413 		_PopulateDirents();
414 
415 	for (uint32 i = 0; i < fDirentCount; i++) {
416 		if (strcmp(fDirents[i]->name, name) == 0) {
417 			*inodeNumber = fDirents[i]->inode_number;
418 			locker.Unlock();
419 
420 			OverlayInode *node = NULL;
421 			status_t result = get_vnode(Volume(), *inodeNumber,
422 				(void **)&node);
423 			if (result == B_OK && node != NULL && i >= 2)
424 				node->SetParentDir(this);
425 			return result;
426 		}
427 	}
428 
429 	return B_ENTRY_NOT_FOUND;
430 }
431 
432 
433 status_t
434 OverlayInode::LookupAttribute(const char *name, OverlayInode **node)
435 {
436 	RecursiveLocker locker(fLock);
437 	if (!fHasAttributeDirents)
438 		_PopulateAttributeDirents();
439 
440 	for (uint32 i = 0; i < fAttributeDirentCount; i++) {
441 		overlay_dirent *dirent = fAttributeDirents[i];
442 		if (strcmp(dirent->name, name) == 0) {
443 			if (dirent->node == NULL) {
444 				OverlayInode *newNode = new(std::nothrow) OverlayInode(fVolume,
445 					SuperVnode(), fInodeNumber, NULL, dirent->name, 0, true, 0);
446 				if (newNode == NULL)
447 					return B_NO_MEMORY;
448 
449 				status_t result = newNode->InitCheck();
450 				if (result != B_OK) {
451 					delete newNode;
452 					return result;
453 				}
454 
455 				dirent->node = newNode;
456 			}
457 
458 			*node = dirent->node;
459 			return B_OK;
460 		}
461 	}
462 
463 	return B_ENTRY_NOT_FOUND;
464 }
465 
466 
467 void
468 OverlayInode::SetName(const char *name)
469 {
470 	RecursiveLocker locker(fLock);
471 	fName = name;
472 	if (!fIsModified)
473 		SetModified();
474 }
475 
476 
477 status_t
478 OverlayInode::GetName(char *buffer, size_t bufferSize)
479 {
480 	RecursiveLocker locker(fLock);
481 	if (fName != NULL) {
482 		strlcpy(buffer, fName, bufferSize);
483 		return B_OK;
484 	}
485 
486 	if (fIsVirtual || fIsAttribute)
487 		return B_UNSUPPORTED;
488 
489 	if (fSuperVnode.ops->get_vnode_name == NULL)
490 		return B_UNSUPPORTED;
491 
492 	return fSuperVnode.ops->get_vnode_name(SuperVolume(), &fSuperVnode, buffer,
493 		bufferSize);
494 }
495 
496 
497 status_t
498 OverlayInode::ReadStat(struct stat *stat)
499 {
500 	RecursiveLocker locker(fLock);
501 	if (!fHasStat)
502 		_PopulateStat();
503 
504 	memcpy(stat, &fStat, sizeof(struct stat));
505 	stat->st_blocks = (stat->st_size + stat->st_blksize - 1) / stat->st_blksize;
506 	return B_OK;
507 }
508 
509 
510 status_t
511 OverlayInode::WriteStat(const struct stat *stat, uint32 statMask)
512 {
513 	if (fIsAttribute)
514 		return B_UNSUPPORTED;
515 
516 	RecursiveLocker locker(fLock);
517 	if (!fHasStat)
518 		_PopulateStat();
519 
520 	if (statMask & B_STAT_SIZE) {
521 		if (fStat.st_size != stat->st_size) {
522 			fStat.st_size = stat->st_size;
523 			if (!fIsDataModified)
524 				SetDataModified();
525 			_TrimBuffers();
526 		}
527 	}
528 
529 	if (statMask & B_STAT_MODE)
530 		fStat.st_mode = (fStat.st_mode & ~S_IUMSK) | (stat->st_mode & S_IUMSK);
531 	if (statMask & B_STAT_UID)
532 		fStat.st_uid = stat->st_uid;
533 	if (statMask & B_STAT_GID)
534 		fStat.st_gid = stat->st_gid;
535 
536 	if (statMask & B_STAT_MODIFICATION_TIME)
537 		fStat.st_mtime = stat->st_mtime;
538 	if (statMask & B_STAT_CREATION_TIME)
539 		fStat.st_crtime = stat->st_crtime;
540 
541 	if ((statMask & (B_STAT_MODE | B_STAT_UID | B_STAT_GID)) != 0
542 		&& (statMask & B_STAT_MODIFICATION_TIME) == 0) {
543 		fStat.st_mtime = time(NULL);
544 		statMask |= B_STAT_MODIFICATION_TIME;
545 	}
546 
547 	if (!fIsModified)
548 		SetModified();
549 
550 	notify_stat_changed(SuperVolume()->id, -1, fInodeNumber, statMask);
551 	return B_OK;
552 }
553 
554 
555 status_t
556 OverlayInode::Create(const char *name, int openMode, int perms, void **cookie,
557 	ino_t *newInodeNumber, bool attribute, type_code attributeType)
558 {
559 	OverlayInode *newNode = NULL;
560 	status_t result = _CreateCommon(name, attribute ? S_ATTR : S_IFREG, perms,
561 		newInodeNumber, &newNode, attribute, attributeType);
562 	if (result != B_OK)
563 		return result;
564 
565 	return newNode->Open(openMode, cookie);
566 }
567 
568 
569 status_t
570 OverlayInode::Open(int openMode, void **_cookie)
571 {
572 	RecursiveLocker locker(fLock);
573 	if (!fHasStat)
574 		_PopulateStat();
575 
576 	open_cookie *cookie = (open_cookie *)malloc(sizeof(open_cookie));
577 	if (cookie == NULL)
578 		return B_NO_MEMORY;
579 
580 	cookie->open_mode = openMode;
581 	cookie->node = this;
582 	*_cookie = cookie;
583 
584 	if (fIsVirtual) {
585 		if (openMode & O_TRUNC) {
586 			fStat.st_size = 0;
587 			_TrimBuffers();
588 		}
589 
590 		return B_OK;
591 	}
592 
593 	if ((fIsAttribute && fSuperVnode.ops->open_attr == NULL)
594 		|| (!fIsAttribute && fSuperVnode.ops->open == NULL))
595 		return B_UNSUPPORTED;
596 
597 	if (openMode & O_TRUNC) {
598 		if (fStat.st_size != 0) {
599 			fStat.st_size = 0;
600 			_TrimBuffers();
601 			if (!fIsDataModified)
602 				SetDataModified();
603 		}
604 	}
605 
606 	openMode &= ~(O_RDWR | O_WRONLY | O_TRUNC | O_CREAT);
607 	status_t result;
608 	if (fIsAttribute) {
609 		result = fSuperVnode.ops->open_attr(SuperVolume(), &fSuperVnode,
610 			fName, openMode, &cookie->super_cookie);
611 	} else {
612 		result = fSuperVnode.ops->open(SuperVolume(), &fSuperVnode,
613 			openMode, &cookie->super_cookie);
614 	}
615 
616 	if (result != B_OK) {
617 		free(cookie);
618 		return result;
619 	}
620 
621 	if (fOriginalNodeLength < 0) {
622 		struct stat stat;
623 		if (fIsAttribute) {
624 			result = fSuperVnode.ops->read_attr_stat(SuperVolume(),
625 				&fSuperVnode, cookie->super_cookie, &stat);
626 		} else {
627 			result = fSuperVnode.ops->read_stat(SuperVolume(),
628 				&fSuperVnode, &stat);
629 		}
630 
631 		if (result != B_OK)
632 			return result;
633 
634 		fOriginalNodeLength = stat.st_size;
635 	}
636 
637 	return B_OK;
638 }
639 
640 
641 status_t
642 OverlayInode::Close(void *_cookie)
643 {
644 	if (fIsVirtual)
645 		return B_OK;
646 
647 	open_cookie *cookie = (open_cookie *)_cookie;
648 	if (fIsAttribute) {
649 		return fSuperVnode.ops->close_attr(SuperVolume(), &fSuperVnode,
650 			cookie->super_cookie);
651 	}
652 
653 	return fSuperVnode.ops->close(SuperVolume(), &fSuperVnode,
654 		cookie->super_cookie);
655 }
656 
657 
658 status_t
659 OverlayInode::FreeCookie(void *_cookie)
660 {
661 	status_t result = B_OK;
662 	open_cookie *cookie = (open_cookie *)_cookie;
663 	if (!fIsVirtual) {
664 		if (fIsAttribute) {
665 			result = fSuperVnode.ops->free_attr_cookie(SuperVolume(),
666 				&fSuperVnode, cookie->super_cookie);
667 		} else {
668 			result = fSuperVnode.ops->free_cookie(SuperVolume(),
669 				&fSuperVnode, cookie->super_cookie);
670 		}
671 	}
672 
673 	free(cookie);
674 	return result;
675 }
676 
677 
678 status_t
679 OverlayInode::Read(void *_cookie, off_t position, void *buffer, size_t *length,
680 	bool readPages, IORequest *ioRequest)
681 {
682 	RecursiveLocker locker(fLock);
683 	if (position >= fStat.st_size) {
684 		*length = 0;
685 		return B_OK;
686 	}
687 
688 	uint8 *pointer = (uint8 *)buffer;
689 	write_buffer *element = fWriteBuffers;
690 	size_t bytesLeft = (size_t)MIN(fStat.st_size - position, (off_t)*length);
691 	*length = bytesLeft;
692 
693 	void *superCookie = _cookie;
694 	if (!fIsVirtual && !readPages && _cookie != NULL)
695 		superCookie = ((open_cookie *)_cookie)->super_cookie;
696 
697 	while (bytesLeft > 0) {
698 		size_t gapSize = bytesLeft;
699 		if (element != NULL) {
700 			gapSize = (size_t)MIN((off_t)bytesLeft, element->position > position ?
701 				element->position - position : 0);
702 		}
703 
704 		if (gapSize > 0 && !fIsVirtual && position < fOriginalNodeLength) {
705 			// there's a part missing between the read position and our
706 			// next position, fill the gap with original file content
707 			size_t readLength = (size_t)MIN(fOriginalNodeLength - position,
708 				(off_t)gapSize);
709 			status_t result = B_ERROR;
710 			if (readPages) {
711 				iovec vector;
712 				vector.iov_base = pointer;
713 				vector.iov_len = readLength;
714 
715 				result = fSuperVnode.ops->read_pages(SuperVolume(),
716 					&fSuperVnode, superCookie, position, &vector, 1,
717 					&readLength);
718 			} else if (ioRequest != NULL) {
719 				IORequest *subRequest;
720 				result = ioRequest->CreateSubRequest(position, position,
721 					readLength, subRequest);
722 				if (result != B_OK)
723 					return result;
724 
725 				bool wereSuppressed = ioRequest->SuppressChildNotifications();
726 				ioRequest->SetSuppressChildNotifications(true);
727 				result = fSuperVnode.ops->io(SuperVolume(), &fSuperVnode,
728 					superCookie, subRequest);
729 				if (result != B_OK)
730 					return result;
731 
732 				result = subRequest->Wait(0, 0);
733 				readLength = subRequest->TransferredBytes();
734 				ioRequest->SetSuppressChildNotifications(wereSuppressed);
735 			} else if (fIsAttribute) {
736 				result = fSuperVnode.ops->read_attr(SuperVolume(), &fSuperVnode,
737 					superCookie, position, pointer, &readLength);
738 			} else {
739 				result = fSuperVnode.ops->read(SuperVolume(), &fSuperVnode,
740 					superCookie, position, pointer, &readLength);
741 			}
742 
743 			if (result != B_OK)
744 				return result;
745 
746 			pointer += readLength;
747 			position += readLength;
748 			bytesLeft -= readLength;
749 			gapSize -= readLength;
750 		}
751 
752 		if (gapSize > 0) {
753 			// there's a gap before our next position which we cannot
754 			// fill with original file content, zero it out
755 			if (ioRequest != NULL)
756 				;// TODO: handle this case
757 			else
758 				user_memset(pointer, 0, gapSize);
759 
760 			bytesLeft -= gapSize;
761 			position += gapSize;
762 			pointer += gapSize;
763 		}
764 
765 		// we've reached the end
766 		if (bytesLeft == 0 || element == NULL)
767 			break;
768 
769 		off_t elementEnd = element->position + element->length;
770 		if (elementEnd > position) {
771 			size_t copyLength = (size_t)MIN(elementEnd - position,
772 				(off_t)bytesLeft);
773 
774 			const void *source = element->buffer + (position
775 				- element->position);
776 			if (ioRequest != NULL) {
777 				ioRequest->CopyData(source, ioRequest->Offset()
778 					+ ((addr_t)pointer - (addr_t)buffer), copyLength);
779 			} else if (user_memcpy(pointer, source, copyLength) < B_OK)
780 				return B_BAD_ADDRESS;
781 
782 			bytesLeft -= copyLength;
783 			position += copyLength;
784 			pointer += copyLength;
785 		}
786 
787 		element = element->next;
788 	}
789 
790 	return B_OK;
791 }
792 
793 
794 status_t
795 OverlayInode::Write(void *_cookie, off_t position, const void *buffer,
796 	size_t length, IORequest *ioRequest)
797 {
798 	RecursiveLocker locker(fLock);
799 	if (_cookie != NULL) {
800 		open_cookie *cookie = (open_cookie *)_cookie;
801 		if (cookie->open_mode & O_APPEND)
802 			position = fStat.st_size;
803 	}
804 
805 	if (!fIsDataModified)
806 		SetDataModified();
807 
808 	// find insertion point
809 	write_buffer **link = &fWriteBuffers;
810 	write_buffer *other = fWriteBuffers;
811 	write_buffer *swallow = NULL;
812 	off_t newPosition = position;
813 	size_t newLength = length;
814 	uint32 swallowCount = 0;
815 
816 	while (other) {
817 		off_t newEnd = newPosition + newLength;
818 		off_t otherEnd = other->position + other->length;
819 		if (otherEnd < newPosition) {
820 			// other is completely before us
821 			link = &other->next;
822 			other = other->next;
823 			continue;
824 		}
825 
826 		if (other->position > newEnd) {
827 			// other is completely past us
828 			break;
829 		}
830 
831 		swallowCount++;
832 		if (swallow == NULL)
833 			swallow = other;
834 
835 		if (other->position <= newPosition) {
836 			if (swallowCount == 1 && otherEnd >= newEnd) {
837 				// other chunk completely covers us, just copy
838 				void *target = other->buffer + (newPosition - other->position);
839 				if (ioRequest != NULL)
840 					ioRequest->CopyData(ioRequest->Offset(), target, length);
841 				else if (user_memcpy(target, buffer, length) < B_OK)
842 					return B_BAD_ADDRESS;
843 
844 				fStat.st_mtime = time(NULL);
845 				if (fIsAttribute) {
846 					notify_attribute_changed(SuperVolume()->id, -1,
847 						fInodeNumber, fName, B_ATTR_CHANGED);
848 				} else {
849 					notify_stat_changed(SuperVolume()->id, -1, fInodeNumber,
850 						B_STAT_MODIFICATION_TIME);
851 				}
852 				return B_OK;
853 			}
854 
855 			newLength += newPosition - other->position;
856 			newPosition = other->position;
857 		}
858 
859 		if (otherEnd > newEnd)
860 			newLength += otherEnd - newEnd;
861 
862 		other = other->next;
863 	}
864 
865 	write_buffer *element = (write_buffer *)malloc(sizeof(write_buffer) - 1
866 		+ newLength);
867 	if (element == NULL)
868 		return B_NO_MEMORY;
869 
870 	element->next = *link;
871 	element->position = newPosition;
872 	element->length = newLength;
873 	*link = element;
874 
875 	bool sizeChanged = false;
876 	off_t newEnd = newPosition + newLength;
877 	if (newEnd > fStat.st_size) {
878 		fStat.st_size = newEnd;
879 		sizeChanged = true;
880 
881 		if (fFileCache)
882 			file_cache_set_size(fFileCache, newEnd);
883 	}
884 
885 	// populate the buffer with the existing chunks
886 	if (swallowCount > 0) {
887 		while (swallowCount-- > 0) {
888 			memcpy(element->buffer + (swallow->position - newPosition),
889 				swallow->buffer, swallow->length);
890 
891 			element->next = swallow->next;
892 			free(swallow);
893 			swallow = element->next;
894 		}
895 	}
896 
897 	void *target = element->buffer + (position - newPosition);
898 	if (ioRequest != NULL)
899 		ioRequest->CopyData(0, target, length);
900 	else if (user_memcpy(target, buffer, length) < B_OK)
901 		return B_BAD_ADDRESS;
902 
903 	fStat.st_mtime = time(NULL);
904 
905 	if (fIsAttribute) {
906 		notify_attribute_changed(SuperVolume()->id, -1, fInodeNumber, fName,
907 			B_ATTR_CHANGED);
908 	} else {
909 		notify_stat_changed(SuperVolume()->id, -1, fInodeNumber,
910 			B_STAT_MODIFICATION_TIME | (sizeChanged ? B_STAT_SIZE : 0));
911 	}
912 
913 	return B_OK;
914 }
915 
916 
917 status_t
918 OverlayInode::SynchronousIO(void *cookie, IORequest *request)
919 {
920 	status_t result;
921 	size_t length = request->Length();
922 	if (request->IsWrite())
923 		result = Write(cookie, request->Offset(), NULL, length, request);
924 	else
925 		result = Read(cookie, request->Offset(), NULL, &length, false, request);
926 
927 	if (result == B_OK)
928 		request->SetTransferredBytes(false, length);
929 
930 	request->SetStatusAndNotify(result);
931 	return result;
932 }
933 
934 
935 status_t
936 OverlayInode::SetFlags(void *_cookie, int flags)
937 {
938 	// we can only handle O_APPEND, O_NONBLOCK is ignored.
939 	open_cookie *cookie = (open_cookie *)_cookie;
940 	cookie->open_mode = (cookie->open_mode & ~O_APPEND) | (flags & ~O_APPEND);
941 	return B_OK;
942 }
943 
944 
945 status_t
946 OverlayInode::CreateDir(const char *name, int perms)
947 {
948 	return _CreateCommon(name, S_IFDIR, perms, NULL, NULL, false, 0);
949 }
950 
951 
952 status_t
953 OverlayInode::RemoveDir(const char *name)
954 {
955 	return RemoveEntry(name, NULL);
956 }
957 
958 
959 status_t
960 OverlayInode::OpenDir(void **cookie, bool attribute)
961 {
962 	RecursiveLocker locker(fLock);
963 	if (!attribute) {
964 		if (!fHasStat)
965 			_PopulateStat();
966 
967 		if (!S_ISDIR(fStat.st_mode))
968 			return B_NOT_A_DIRECTORY;
969 	}
970 
971 	if (!attribute && !fHasDirents)
972 		_PopulateDirents();
973 	else if (attribute && !fHasAttributeDirents)
974 		_PopulateAttributeDirents();
975 
976 	open_dir_cookie *dirCookie = (open_dir_cookie *)malloc(
977 		sizeof(open_dir_cookie));
978 	if (dirCookie == NULL)
979 		return B_NO_MEMORY;
980 
981 	dirCookie->index = 0;
982 	*cookie = dirCookie;
983 	return B_OK;
984 }
985 
986 
987 status_t
988 OverlayInode::CloseDir(void *cookie)
989 {
990 	return B_OK;
991 }
992 
993 
994 status_t
995 OverlayInode::FreeDirCookie(void *cookie)
996 {
997 	free(cookie);
998 	return B_OK;
999 }
1000 
1001 
1002 status_t
1003 OverlayInode::ReadDir(void *cookie, struct dirent *buffer, size_t bufferSize,
1004 	uint32 *num, bool attribute)
1005 {
1006 	RecursiveLocker locker(fLock);
1007 	uint32 direntCount = attribute ? fAttributeDirentCount : fDirentCount;
1008 	overlay_dirent **dirents = attribute ? fAttributeDirents : fDirents;
1009 
1010 	open_dir_cookie *dirCookie = (open_dir_cookie *)cookie;
1011 	if (dirCookie->index >= direntCount) {
1012 		*num = 0;
1013 		return B_OK;
1014 	}
1015 
1016 	overlay_dirent *dirent = dirents[dirCookie->index++];
1017 	size_t nameLength = MIN(strlen(dirent->name),
1018 		bufferSize - sizeof(struct dirent)) + 1;
1019 
1020 	buffer->d_dev = SuperVolume()->id;
1021 	buffer->d_pdev = 0;
1022 	buffer->d_ino = dirent->inode_number;
1023 	buffer->d_pino = 0;
1024 	buffer->d_reclen = sizeof(struct dirent) + nameLength;
1025 	strlcpy(buffer->d_name, dirent->name, nameLength);
1026 
1027 	*num = 1;
1028 	return B_OK;
1029 }
1030 
1031 
1032 status_t
1033 OverlayInode::RewindDir(void *cookie)
1034 {
1035 	open_dir_cookie *dirCookie = (open_dir_cookie *)cookie;
1036 	dirCookie->index = 0;
1037 	return B_OK;
1038 }
1039 
1040 
1041 status_t
1042 OverlayInode::CreateSymlink(const char *name, const char *path, int mode)
1043 {
1044 	OverlayInode *newNode = NULL;
1045 	// TODO: find out why mode is ignored
1046 	status_t result = _CreateCommon(name, S_IFLNK, 0777, NULL, &newNode,
1047 		false, 0);
1048 	if (result != B_OK)
1049 		return result;
1050 
1051 	return newNode->Write(NULL, 0, path, strlen(path), NULL);
1052 }
1053 
1054 
1055 status_t
1056 OverlayInode::ReadSymlink(char *buffer, size_t *bufferSize)
1057 {
1058 	if (fIsVirtual) {
1059 		if (!S_ISLNK(fStat.st_mode))
1060 			return B_BAD_VALUE;
1061 
1062 		status_t result = Read(NULL, 0, buffer, bufferSize, false, NULL);
1063 		*bufferSize = fStat.st_size;
1064 		return result;
1065 	}
1066 
1067 	if (fSuperVnode.ops->read_symlink == NULL)
1068 		return B_UNSUPPORTED;
1069 
1070 	return fSuperVnode.ops->read_symlink(SuperVolume(), &fSuperVnode, buffer,
1071 		bufferSize);
1072 }
1073 
1074 
1075 status_t
1076 OverlayInode::AddEntry(overlay_dirent *entry, bool attribute)
1077 {
1078 	RecursiveLocker locker(fLock);
1079 	if (!attribute && !fHasDirents)
1080 		_PopulateDirents();
1081 	else if (attribute && !fHasAttributeDirents)
1082 		_PopulateAttributeDirents();
1083 
1084 	status_t result = RemoveEntry(entry->name, NULL, attribute);
1085 	if (result != B_OK && result != B_ENTRY_NOT_FOUND)
1086 		return B_FILE_EXISTS;
1087 
1088 	overlay_dirent **newDirents = (overlay_dirent **)realloc(
1089 		attribute ? fAttributeDirents : fDirents,
1090 		sizeof(overlay_dirent *)
1091 			* ((attribute ? fAttributeDirentCount : fDirentCount) + 1));
1092 	if (newDirents == NULL)
1093 		return B_NO_MEMORY;
1094 
1095 	if (attribute) {
1096 		fAttributeDirents = newDirents;
1097 		fAttributeDirents[fAttributeDirentCount++] = entry;
1098 	} else {
1099 		fDirents = newDirents;
1100 		fDirents[fDirentCount++] = entry;
1101 	}
1102 
1103 	if (!fIsModified)
1104 		SetModified();
1105 
1106 	return B_OK;
1107 }
1108 
1109 
1110 status_t
1111 OverlayInode::RemoveEntry(const char *name, overlay_dirent **_entry,
1112 	bool attribute)
1113 {
1114 	RecursiveLocker locker(fLock);
1115 	if (!attribute && !fHasDirents)
1116 		_PopulateDirents();
1117 	else if (attribute && !fHasAttributeDirents)
1118 		_PopulateAttributeDirents();
1119 
1120 	uint32 direntCount = attribute ? fAttributeDirentCount : fDirentCount;
1121 	overlay_dirent **dirents = attribute ? fAttributeDirents : fDirents;
1122 	for (uint32 i = 0; i < direntCount; i++) {
1123 		overlay_dirent *entry = dirents[i];
1124 		if (strcmp(entry->name, name) == 0) {
1125 			if (_entry == NULL && !attribute) {
1126 				// check for non-empty directories when trying
1127 				// to dispose the entry
1128 				OverlayInode *node = NULL;
1129 				status_t result = get_vnode(Volume(), entry->inode_number,
1130 					(void **)&node);
1131 				if (result != B_OK)
1132 					return result;
1133 
1134 				if (node->IsNonEmptyDirectory())
1135 					result = B_DIRECTORY_NOT_EMPTY;
1136 
1137 				put_vnode(Volume(), entry->inode_number);
1138 				if (result != B_OK)
1139 					return result;
1140 			}
1141 
1142 			for (uint32 j = i + 1; j < direntCount; j++)
1143 				dirents[j - 1] = dirents[j];
1144 
1145 			if (attribute)
1146 				fAttributeDirentCount--;
1147 			else
1148 				fDirentCount--;
1149 
1150 			if (_entry != NULL)
1151 				*_entry = entry;
1152 			else if (attribute)
1153 				entry->dispose_attribute(Volume(), fInodeNumber);
1154 			else
1155 				entry->remove_and_dispose(Volume(), fInodeNumber);
1156 
1157 			if (!fIsModified)
1158 				SetModified();
1159 
1160 			return B_OK;
1161 		}
1162 	}
1163 
1164 	return B_ENTRY_NOT_FOUND;
1165 }
1166 
1167 
1168 void
1169 OverlayInode::_TrimBuffers()
1170 {
1171 	// the file size has been changed and we want to trim
1172 	// off everything that goes beyond the new size
1173 	write_buffer **link = &fWriteBuffers;
1174 	write_buffer *buffer = fWriteBuffers;
1175 
1176 	while (buffer != NULL) {
1177 		off_t bufferEnd = buffer->position + buffer->length;
1178 		if (bufferEnd > fStat.st_size)
1179 			break;
1180 
1181 		link = &buffer->next;
1182 		buffer = buffer->next;
1183 	}
1184 
1185 	if (buffer == NULL) {
1186 		// didn't find anything crossing or past the end
1187 		return;
1188 	}
1189 
1190 	if (buffer->position < fStat.st_size) {
1191 		// got a crossing buffer to resize
1192 		size_t newLength = fStat.st_size - buffer->position;
1193 		write_buffer *newBuffer = (write_buffer *)realloc(buffer,
1194 			sizeof(write_buffer) - 1 + newLength);
1195 
1196 		if (newBuffer != NULL) {
1197 			buffer = newBuffer;
1198 			*link = newBuffer;
1199 		} else {
1200 			// we don't really care if it worked, if it didn't we simply
1201 			// keep the old buffer and reset it's size
1202 		}
1203 
1204 		buffer->length = newLength;
1205 		link = &buffer->next;
1206 		buffer = buffer->next;
1207 	}
1208 
1209 	// everything else we can throw away
1210 	*link = NULL;
1211 	while (buffer != NULL) {
1212 		write_buffer *next = buffer->next;
1213 		free(buffer);
1214 		buffer = next;
1215 	}
1216 }
1217 
1218 
1219 status_t
1220 OverlayInode::_PopulateStat()
1221 {
1222 	if (fHasStat)
1223 		return B_OK;
1224 
1225  	fHasStat = true;
1226 	if (fIsAttribute) {
1227 		if (fName == NULL || fSuperVnode.ops->open_attr == NULL
1228 			|| fSuperVnode.ops->read_attr_stat == NULL)
1229 			return B_UNSUPPORTED;
1230 
1231 		void *cookie = NULL;
1232 		status_t result = fSuperVnode.ops->open_attr(SuperVolume(),
1233 			&fSuperVnode, fName, O_RDONLY, &cookie);
1234 		if (result != B_OK)
1235 			return result;
1236 
1237 		result = fSuperVnode.ops->read_attr_stat(SuperVolume(), &fSuperVnode,
1238 			cookie, &fStat);
1239 
1240 		if (fSuperVnode.ops->close_attr != NULL)
1241 			fSuperVnode.ops->close_attr(SuperVolume(), &fSuperVnode, cookie);
1242 
1243 		if (fSuperVnode.ops->free_attr_cookie != NULL) {
1244 			fSuperVnode.ops->free_attr_cookie(SuperVolume(), &fSuperVnode,
1245 				cookie);
1246 		}
1247 
1248 		return B_OK;
1249 	}
1250 
1251 	if (fSuperVnode.ops->read_stat == NULL)
1252 		return B_UNSUPPORTED;
1253 
1254 	return fSuperVnode.ops->read_stat(SuperVolume(), &fSuperVnode, &fStat);
1255 }
1256 
1257 
1258 status_t
1259 OverlayInode::_PopulateDirents()
1260 {
1261 	if (fHasDirents)
1262 		return B_OK;
1263 
1264 	fDirents = (overlay_dirent **)malloc(sizeof(overlay_dirent *) * 2);
1265 	if (fDirents == NULL)
1266 		return B_NO_MEMORY;
1267 
1268 	const char *names[] = { ".", ".." };
1269 	ino_t inodes[] = { fInodeNumber,
1270 		fParentDir != NULL ? fParentDir->InodeNumber() : 0 };
1271 	for (uint32 i = 0; i < 2; i++) {
1272 		fDirents[i] = (overlay_dirent *)malloc(sizeof(overlay_dirent));
1273 		if (fDirents[i] == NULL)
1274 			return B_NO_MEMORY;
1275 
1276 		fDirents[i]->inode_number = inodes[i];
1277 		fDirents[i]->name = strdup(names[i]);
1278 		if (fDirents[i]->name == NULL) {
1279 			free(fDirents[i]);
1280 			return B_NO_MEMORY;
1281 		}
1282 
1283 		fDirentCount++;
1284 	}
1285 
1286 	fHasDirents = true;
1287 	if (fIsVirtual || fSuperVnode.ops->open_dir == NULL
1288 		|| fSuperVnode.ops->read_dir == NULL)
1289 		return B_OK;
1290 
1291 	// we don't really care about errors from here on
1292 	void *superCookie = NULL;
1293 	status_t result = fSuperVnode.ops->open_dir(SuperVolume(),
1294 		&fSuperVnode, &superCookie);
1295 	if (result != B_OK)
1296 		return B_OK;
1297 
1298 	size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH;
1299 	struct dirent *buffer = (struct dirent *)malloc(bufferSize);
1300 	if (buffer == NULL)
1301 		goto close_dir;
1302 
1303 	while (true) {
1304 		uint32 num = 1;
1305 		result = fSuperVnode.ops->read_dir(SuperVolume(),
1306 			&fSuperVnode, superCookie, buffer, bufferSize, &num);
1307 		if (result != B_OK || num == 0)
1308 			break;
1309 
1310 		overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents,
1311 			sizeof(overlay_dirent *) * (fDirentCount + num));
1312 		if (newDirents == NULL) {
1313 			TRACE_ALWAYS("failed to allocate storage for dirents\n");
1314 			break;
1315 		}
1316 
1317 		fDirents = newDirents;
1318 		struct dirent *dirent = buffer;
1319 		for (uint32 i = 0; i < num; i++) {
1320 			if (strcmp(dirent->d_name, ".") != 0
1321 				&& strcmp(dirent->d_name, "..") != 0) {
1322 				overlay_dirent *entry = (overlay_dirent *)malloc(
1323 					sizeof(overlay_dirent));
1324 				if (entry == NULL) {
1325 					TRACE_ALWAYS("failed to allocate storage for dirent\n");
1326 					break;
1327 				}
1328 
1329 				entry->inode_number = dirent->d_ino;
1330 				entry->name = strdup(dirent->d_name);
1331 				if (entry->name == NULL) {
1332 					TRACE_ALWAYS("failed to duplicate dirent entry name\n");
1333 					free(entry);
1334 					break;
1335 				}
1336 
1337 				fDirents[fDirentCount++] = entry;
1338 			}
1339 
1340 			dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen);
1341 		}
1342 	}
1343 
1344 	free(buffer);
1345 
1346 close_dir:
1347 	if (fSuperVnode.ops->close_dir != NULL)
1348 		fSuperVnode.ops->close_dir(SuperVolume(), &fSuperVnode, superCookie);
1349 
1350 	if (fSuperVnode.ops->free_dir_cookie != NULL) {
1351 		fSuperVnode.ops->free_dir_cookie(SuperVolume(), &fSuperVnode,
1352 			superCookie);
1353 	}
1354 
1355 	return B_OK;
1356 }
1357 
1358 
1359 status_t
1360 OverlayInode::_PopulateAttributeDirents()
1361 {
1362 	if (fHasAttributeDirents)
1363 		return B_OK;
1364 
1365 	fHasAttributeDirents = true;
1366 	if (fIsVirtual || fSuperVnode.ops->open_attr_dir == NULL
1367 		|| fSuperVnode.ops->read_attr_dir == NULL)
1368 		return B_OK;
1369 
1370 	// we don't really care about errors from here on
1371 	void *superCookie = NULL;
1372 	status_t result = fSuperVnode.ops->open_attr_dir(SuperVolume(),
1373 		&fSuperVnode, &superCookie);
1374 	if (result != B_OK)
1375 		return B_OK;
1376 
1377 	size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH;
1378 	struct dirent *buffer = (struct dirent *)malloc(bufferSize);
1379 	if (buffer == NULL)
1380 		goto close_attr_dir;
1381 
1382 	while (true) {
1383 		uint32 num = 1;
1384 		result = fSuperVnode.ops->read_attr_dir(SuperVolume(),
1385 			&fSuperVnode, superCookie, buffer, bufferSize, &num);
1386 		if (result != B_OK || num == 0)
1387 			break;
1388 
1389 		overlay_dirent **newDirents = (overlay_dirent **)realloc(
1390 			fAttributeDirents, sizeof(overlay_dirent *)
1391 				* (fAttributeDirentCount + num));
1392 		if (newDirents == NULL) {
1393 			TRACE_ALWAYS("failed to allocate storage for attribute dirents\n");
1394 			break;
1395 		}
1396 
1397 		fAttributeDirents = newDirents;
1398 		struct dirent *dirent = buffer;
1399 		for (uint32 i = 0; i < num; i++) {
1400 			overlay_dirent *entry = (overlay_dirent *)malloc(
1401 				sizeof(overlay_dirent));
1402 			if (entry == NULL) {
1403 				TRACE_ALWAYS("failed to allocate storage for attr dirent\n");
1404 				break;
1405 			}
1406 
1407 			entry->node = NULL;
1408 			entry->inode_number = fInodeNumber;
1409 			entry->name = strdup(dirent->d_name);
1410 			if (entry->name == NULL) {
1411 				TRACE_ALWAYS("failed to duplicate dirent entry name\n");
1412 				free(entry);
1413 				break;
1414 			}
1415 
1416 			fAttributeDirents[fAttributeDirentCount++] = entry;
1417 			dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen);
1418 		}
1419 	}
1420 
1421 	free(buffer);
1422 
1423 close_attr_dir:
1424 	if (fSuperVnode.ops->close_attr_dir != NULL) {
1425 		fSuperVnode.ops->close_attr_dir(SuperVolume(), &fSuperVnode,
1426 			superCookie);
1427 	}
1428 
1429 	if (fSuperVnode.ops->free_attr_dir_cookie != NULL) {
1430 		fSuperVnode.ops->free_attr_dir_cookie(SuperVolume(), &fSuperVnode,
1431 			superCookie);
1432 	}
1433 
1434 	return B_OK;
1435 }
1436 
1437 
1438 status_t
1439 OverlayInode::_CreateCommon(const char *name, int type, int perms,
1440 	ino_t *newInodeNumber, OverlayInode **_node, bool attribute,
1441 	type_code attributeType)
1442 {
1443 	RecursiveLocker locker(fLock);
1444 	if (!fHasStat)
1445 		_PopulateStat();
1446 
1447 	if (!attribute && !S_ISDIR(fStat.st_mode))
1448 		return B_NOT_A_DIRECTORY;
1449 
1450 	locker.Unlock();
1451 
1452 	overlay_dirent *entry = (overlay_dirent *)malloc(sizeof(overlay_dirent));
1453 	if (entry == NULL)
1454 		return B_NO_MEMORY;
1455 
1456 	entry->node = NULL;
1457 	entry->name = strdup(name);
1458 	if (entry->name == NULL) {
1459 		free(entry);
1460 		return B_NO_MEMORY;
1461 	}
1462 
1463 	if (attribute)
1464 		entry->inode_number = fInodeNumber;
1465 	else
1466 		entry->inode_number = fVolume->BuildInodeNumber();
1467 
1468 	OverlayInode *node = new(std::nothrow) OverlayInode(fVolume, NULL,
1469 		entry->inode_number, this, entry->name, (perms & S_IUMSK) | type
1470 			| (attribute ? S_ATTR : 0), attribute, attributeType);
1471 	if (node == NULL) {
1472 		free(entry->name);
1473 		free(entry);
1474 		return B_NO_MEMORY;
1475 	}
1476 
1477 	status_t result = AddEntry(entry, attribute);
1478 	if (result != B_OK) {
1479 		free(entry->name);
1480 		free(entry);
1481 		delete node;
1482 		return result;
1483 	}
1484 
1485 	if (!attribute) {
1486 		result = publish_overlay_vnode(fVolume->Volume(), entry->inode_number,
1487 			node, type);
1488 		if (result != B_OK) {
1489 			RemoveEntry(entry->name, NULL);
1490 			delete node;
1491 			return result;
1492 		}
1493 	} else
1494 		entry->node = node;
1495 
1496 	node->Lock();
1497 	node->SetDataModified();
1498 	if (!attribute)
1499 		node->CreateCache();
1500 	node->Unlock();
1501 
1502 	if (newInodeNumber != NULL)
1503 		*newInodeNumber = entry->inode_number;
1504 	if (_node != NULL)
1505 		*_node = node;
1506 
1507 	if (attribute) {
1508 		notify_attribute_changed(SuperVolume()->id, -1, fInodeNumber,
1509 			entry->name, B_ATTR_CREATED);
1510 	} else {
1511 		notify_entry_created(SuperVolume()->id, fInodeNumber, entry->name,
1512 			entry->inode_number);
1513 	}
1514 
1515 	return B_OK;
1516 }
1517 
1518 
1519 //	#pragma mark - vnode ops
1520 
1521 
1522 #define OVERLAY_CALL(op, params...) \
1523 	TRACE("relaying op: " #op "\n"); \
1524 	OverlayInode *node = (OverlayInode *)vnode->private_node; \
1525 	if (node->IsVirtual()) \
1526 		return B_UNSUPPORTED; \
1527 	fs_vnode *superVnode = node->SuperVnode(); \
1528 	if (superVnode->ops->op != NULL) \
1529 		return superVnode->ops->op(volume->super_volume, superVnode, params); \
1530 	return B_UNSUPPORTED;
1531 
1532 
1533 static status_t
1534 overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1535 {
1536 	TRACE("put_vnode\n");
1537 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1538 	if (node->IsVirtual() || node->IsModified()) {
1539 		panic("loosing virtual/modified node\n");
1540 		delete node;
1541 		return B_OK;
1542 	}
1543 
1544 	status_t result = B_OK;
1545 	fs_vnode *superVnode = node->SuperVnode();
1546 	if (superVnode->ops->put_vnode != NULL) {
1547 		result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
1548 			reenter);
1549 	}
1550 
1551 	delete node;
1552 	return result;
1553 }
1554 
1555 
1556 static status_t
1557 overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1558 {
1559 	TRACE("remove_vnode\n");
1560 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1561 	if (node->IsVirtual()) {
1562 		delete node;
1563 		return B_OK;
1564 	}
1565 
1566 	status_t result = B_OK;
1567 	fs_vnode *superVnode = node->SuperVnode();
1568 	if (superVnode->ops->put_vnode != NULL) {
1569 		result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
1570 			reenter);
1571 	}
1572 
1573 	delete node;
1574 	return result;
1575 }
1576 
1577 
1578 static status_t
1579 overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode,
1580 	fs_volume *superVolume, fs_vnode *_superVnode)
1581 {
1582 	if (volume == superVolume) {
1583 		*_superVnode = *vnode;
1584 		return B_OK;
1585 	}
1586 
1587 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1588 	if (node->IsVirtual()) {
1589 		*_superVnode = *vnode;
1590 		return B_OK;
1591 	}
1592 
1593 	fs_vnode *superVnode = node->SuperVnode();
1594 	if (superVnode->ops->get_super_vnode != NULL) {
1595 		return superVnode->ops->get_super_vnode(volume->super_volume,
1596 			superVnode, superVolume, _superVnode);
1597 	}
1598 
1599 	*_superVnode = *superVnode;
1600 	return B_OK;
1601 }
1602 
1603 
1604 static status_t
1605 overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id)
1606 {
1607 	TRACE("lookup: \"%s\"\n", name);
1608 	return ((OverlayInode *)vnode->private_node)->Lookup(name, id);
1609 }
1610 
1611 
1612 static status_t
1613 overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer,
1614 	size_t bufferSize)
1615 {
1616 	return ((OverlayInode *)vnode->private_node)->GetName(buffer, bufferSize);
1617 }
1618 
1619 
1620 static bool
1621 overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie)
1622 {
1623 	TRACE("relaying op: can_page\n");
1624 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1625 	if (node->IsVirtual())
1626 		return false;
1627 
1628 	fs_vnode *superVnode = node->SuperVnode();
1629 	if (superVnode->ops->can_page != NULL) {
1630 		return superVnode->ops->can_page(volume->super_volume, superVnode,
1631 			cookie);
1632 	}
1633 
1634 	return false;
1635 }
1636 
1637 
1638 static status_t
1639 overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1640 	const iovec *vecs, size_t count, size_t *numBytes)
1641 {
1642 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1643 	size_t bytesLeft = *numBytes;
1644 
1645 	for (size_t i = 0; i < count; i++) {
1646 		size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft);
1647 		status_t result = node->Read(cookie, pos, vecs[i].iov_base,
1648 			&transferBytes, true, NULL);
1649 		if (result != B_OK) {
1650 			*numBytes -= bytesLeft;
1651 			return result;
1652 		}
1653 
1654 		bytesLeft -= transferBytes;
1655 		if (bytesLeft == 0)
1656 			return B_OK;
1657 
1658 		if (transferBytes < vecs[i].iov_len) {
1659 			*numBytes -= bytesLeft;
1660 			return B_OK;
1661 		}
1662 
1663 		pos += transferBytes;
1664 	}
1665 
1666 	*numBytes = 0;
1667 	return B_OK;
1668 }
1669 
1670 
1671 static status_t
1672 overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1673 	const iovec *vecs, size_t count, size_t *numBytes)
1674 {
1675 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1676 	size_t bytesLeft = *numBytes;
1677 
1678 	for (size_t i = 0; i < count; i++) {
1679 		size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft);
1680 		status_t result = node->Write(cookie, pos, vecs[i].iov_base,
1681 			transferBytes, NULL);
1682 		if (result != B_OK) {
1683 			*numBytes -= bytesLeft;
1684 			return result;
1685 		}
1686 
1687 		bytesLeft -= transferBytes;
1688 		if (bytesLeft == 0)
1689 			return B_OK;
1690 
1691 		if (transferBytes < vecs[i].iov_len) {
1692 			*numBytes -= bytesLeft;
1693 			return B_OK;
1694 		}
1695 
1696 		pos += transferBytes;
1697 	}
1698 
1699 	*numBytes = 0;
1700 	return B_OK;
1701 }
1702 
1703 
1704 static status_t
1705 overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1706 	io_request *request)
1707 {
1708 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1709 	if (io_request_is_write(request) || node->IsModified())
1710 		return node->SynchronousIO(cookie, (IORequest *)request);
1711 
1712 	TRACE("relaying op: io\n");
1713 	fs_vnode *superVnode = node->SuperVnode();
1714 	if (superVnode->ops->io != NULL) {
1715 		return superVnode->ops->io(volume->super_volume, superVnode,
1716 			cookie != NULL ? ((open_cookie *)cookie)->super_cookie : NULL,
1717 			request);
1718 	}
1719 
1720 	return B_UNSUPPORTED;
1721 }
1722 
1723 
1724 static status_t
1725 overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1726 	io_request *request)
1727 {
1728 	OVERLAY_CALL(cancel_io, cookie, request)
1729 }
1730 
1731 
1732 static status_t
1733 overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset,
1734 	size_t size, struct file_io_vec *vecs, size_t *count)
1735 {
1736 	OVERLAY_CALL(get_file_map, offset, size, vecs, count)
1737 }
1738 
1739 
1740 static status_t
1741 overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op,
1742 	void *buffer, size_t length)
1743 {
1744 	OVERLAY_CALL(ioctl, cookie, op, buffer, length)
1745 }
1746 
1747 
1748 static status_t
1749 overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie,
1750 	int flags)
1751 {
1752 	return ((OverlayInode *)vnode->private_node)->SetFlags(cookie, flags);
1753 }
1754 
1755 
1756 static status_t
1757 overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1758 	selectsync *sync)
1759 {
1760 	OVERLAY_CALL(select, cookie, event, sync)
1761 }
1762 
1763 
1764 static status_t
1765 overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1766 	selectsync *sync)
1767 {
1768 	OVERLAY_CALL(deselect, cookie, event, sync)
1769 }
1770 
1771 
1772 static status_t
1773 overlay_fsync(fs_volume *volume, fs_vnode *vnode)
1774 {
1775 	return B_OK;
1776 }
1777 
1778 
1779 static status_t
1780 overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer,
1781 	size_t *bufferSize)
1782 {
1783 	TRACE("read_symlink\n");
1784 	return ((OverlayInode *)vnode->private_node)->ReadSymlink(buffer,
1785 		bufferSize);
1786 }
1787 
1788 
1789 static status_t
1790 overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name,
1791 	const char *path, int mode)
1792 {
1793 	TRACE("create_symlink: \"%s\" -> \"%s\"\n", name, path);
1794 	return ((OverlayInode *)vnode->private_node)->CreateSymlink(name, path,
1795 		mode);
1796 }
1797 
1798 
1799 static status_t
1800 overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name,
1801 	fs_vnode *target)
1802 {
1803 	return B_UNSUPPORTED;
1804 }
1805 
1806 
1807 static status_t
1808 overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name)
1809 {
1810 	TRACE("unlink: \"%s\"\n", name);
1811 	return ((OverlayInode *)vnode->private_node)->RemoveEntry(name, NULL);
1812 }
1813 
1814 
1815 static status_t
1816 overlay_rename(fs_volume *volume, fs_vnode *vnode,
1817 	const char *fromName, fs_vnode *toVnode, const char *toName)
1818 {
1819 	TRACE("rename: \"%s\" -> \"%s\"\n", fromName, toName);
1820 	OverlayInode *fromNode = (OverlayInode *)vnode->private_node;
1821 	OverlayInode *toNode = (OverlayInode *)toVnode->private_node;
1822 	overlay_dirent *entry = NULL;
1823 
1824 	status_t result = fromNode->RemoveEntry(fromName, &entry);
1825 	if (result != B_OK)
1826 		return result;
1827 
1828 	char *oldName = entry->name;
1829 	entry->name = strdup(toName);
1830 	if (entry->name == NULL) {
1831 		entry->name = oldName;
1832 		if (fromNode->AddEntry(entry) != B_OK)
1833 			entry->remove_and_dispose(volume, fromNode->InodeNumber());
1834 
1835 		return B_NO_MEMORY;
1836 	}
1837 
1838 	result = toNode->AddEntry(entry);
1839 	if (result != B_OK) {
1840 		free(entry->name);
1841 		entry->name = oldName;
1842 		if (fromNode->AddEntry(entry) != B_OK)
1843 			entry->remove_and_dispose(volume, fromNode->InodeNumber());
1844 
1845 		return result;
1846 	}
1847 
1848 	OverlayInode *node = NULL;
1849 	result = get_vnode(volume, entry->inode_number, (void **)&node);
1850 	if (result == B_OK && node != NULL) {
1851 		node->SetName(entry->name);
1852 		node->SetParentDir(toNode);
1853 		put_vnode(volume, entry->inode_number);
1854 	}
1855 
1856 	free(oldName);
1857 	notify_entry_moved(volume->id, fromNode->InodeNumber(), fromName,
1858 		toNode->InodeNumber(), toName, entry->inode_number);
1859 	return B_OK;
1860 }
1861 
1862 
1863 static status_t
1864 overlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
1865 {
1866 	// TODO: implement
1867 	return B_OK;
1868 }
1869 
1870 
1871 static status_t
1872 overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat)
1873 {
1874 	TRACE("read_stat\n");
1875 	return ((OverlayInode *)vnode->private_node)->ReadStat(stat);
1876 }
1877 
1878 
1879 static status_t
1880 overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat,
1881 	uint32 statMask)
1882 {
1883 	TRACE("write_stat\n");
1884 	return ((OverlayInode *)vnode->private_node)->WriteStat(stat, statMask);
1885 }
1886 
1887 
1888 static status_t
1889 overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name,
1890 	int openMode, int perms, void **cookie, ino_t *newVnodeID)
1891 {
1892 	TRACE("create: \"%s\"\n", name);
1893 	return ((OverlayInode *)vnode->private_node)->Create(name, openMode,
1894 		perms, cookie, newVnodeID);
1895 }
1896 
1897 
1898 static status_t
1899 overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie)
1900 {
1901 	TRACE("open\n");
1902 	return ((OverlayInode *)vnode->private_node)->Open(openMode, cookie);
1903 }
1904 
1905 
1906 static status_t
1907 overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie)
1908 {
1909 	TRACE("close\n");
1910 	return ((OverlayInode *)vnode->private_node)->Close(cookie);
1911 }
1912 
1913 
1914 static status_t
1915 overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1916 {
1917 	TRACE("free_cookie\n");
1918 	return ((OverlayInode *)vnode->private_node)->FreeCookie(cookie);
1919 }
1920 
1921 
1922 static status_t
1923 overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1924 	void *buffer, size_t *length)
1925 {
1926 	TRACE("read\n");
1927 	return ((OverlayInode *)vnode->private_node)->Read(cookie, pos, buffer,
1928 		length, false, NULL);
1929 }
1930 
1931 
1932 static status_t
1933 overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1934 	const void *buffer, size_t *length)
1935 {
1936 	TRACE("write\n");
1937 	return ((OverlayInode *)vnode->private_node)->Write(cookie, pos, buffer,
1938 		*length, NULL);
1939 }
1940 
1941 
1942 static status_t
1943 overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name,
1944 	int perms)
1945 {
1946 	TRACE("create_dir: \"%s\"\n", name);
1947 	return ((OverlayInode *)vnode->private_node)->CreateDir(name, perms);
1948 }
1949 
1950 
1951 static status_t
1952 overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name)
1953 {
1954 	TRACE("remove_dir: \"%s\"\n", name);
1955 	return ((OverlayInode *)vnode->private_node)->RemoveDir(name);
1956 }
1957 
1958 
1959 static status_t
1960 overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
1961 {
1962 	TRACE("open_dir\n");
1963 	return ((OverlayInode *)vnode->private_node)->OpenDir(cookie);
1964 }
1965 
1966 
1967 static status_t
1968 overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1969 {
1970 	TRACE("close_dir\n");
1971 	return ((OverlayInode *)vnode->private_node)->CloseDir(cookie);
1972 }
1973 
1974 
1975 static status_t
1976 overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1977 {
1978 	TRACE("free_dir_cookie\n");
1979 	return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie);
1980 }
1981 
1982 
1983 static status_t
1984 overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
1985 	struct dirent *buffer, size_t bufferSize, uint32 *num)
1986 {
1987 	TRACE("read_dir\n");
1988 	return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer,
1989 		bufferSize, num);
1990 }
1991 
1992 
1993 static status_t
1994 overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1995 {
1996 	TRACE("rewind_dir\n");
1997 	return ((OverlayInode *)vnode->private_node)->RewindDir(cookie);
1998 }
1999 
2000 
2001 static status_t
2002 overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
2003 {
2004 	TRACE("open_attr_dir\n");
2005 	return ((OverlayInode *)vnode->private_node)->OpenDir(cookie, true);
2006 }
2007 
2008 
2009 static status_t
2010 overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
2011 {
2012 	TRACE("close_attr_dir\n");
2013 	return ((OverlayInode *)vnode->private_node)->CloseDir(cookie);
2014 }
2015 
2016 
2017 static status_t
2018 overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
2019 {
2020 	TRACE("free_attr_dir_cookie\n");
2021 	return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie);
2022 }
2023 
2024 
2025 static status_t
2026 overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
2027 	struct dirent *buffer, size_t bufferSize, uint32 *num)
2028 {
2029 	TRACE("read_attr_dir\n");
2030 	return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer,
2031 		bufferSize, num, true);
2032 }
2033 
2034 
2035 static status_t
2036 overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
2037 {
2038 	TRACE("rewind_attr_dir\n");
2039 	return ((OverlayInode *)vnode->private_node)->RewindDir(cookie);
2040 }
2041 
2042 
2043 static status_t
2044 overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
2045 	uint32 type, int openMode, void **cookie)
2046 {
2047 	TRACE("create_attr\n");
2048 	return ((OverlayInode *)vnode->private_node)->Create(name, openMode, 0,
2049 		cookie, NULL, true, type);
2050 }
2051 
2052 
2053 static status_t
2054 overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
2055 	int openMode, void **cookie)
2056 {
2057 	TRACE("open_attr\n");
2058 	OverlayInode *node = NULL;
2059 	OverlayInode *parentNode = (OverlayInode *)vnode->private_node;
2060 	status_t result = parentNode->LookupAttribute(name, &node);
2061 	if (result != B_OK)
2062 		return result;
2063 	if (node == NULL)
2064 		return B_ERROR;
2065 
2066 	return node->Open(openMode, cookie);
2067 }
2068 
2069 
2070 static status_t
2071 overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie)
2072 {
2073 	TRACE("close_attr\n");
2074 	open_cookie *cookie = (open_cookie *)_cookie;
2075 	return cookie->node->Close(cookie);
2076 }
2077 
2078 
2079 static status_t
2080 overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *_cookie)
2081 {
2082 	TRACE("free_attr_cookie\n");
2083 	open_cookie *cookie = (open_cookie *)_cookie;
2084 	return cookie->node->FreeCookie(cookie);
2085 }
2086 
2087 
2088 static status_t
2089 overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos,
2090 	void *buffer, size_t *length)
2091 {
2092 	TRACE("read_attr\n");
2093 	open_cookie *cookie = (open_cookie *)_cookie;
2094 	return cookie->node->Read(cookie, pos, buffer, length, false, NULL);
2095 }
2096 
2097 
2098 static status_t
2099 overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos,
2100 	const void *buffer, size_t *length)
2101 {
2102 	TRACE("write_attr\n");
2103 	open_cookie *cookie = (open_cookie *)_cookie;
2104 	return cookie->node->Write(cookie, pos, buffer, *length, NULL);
2105 }
2106 
2107 
2108 static status_t
2109 overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie,
2110 	struct stat *stat)
2111 {
2112 	TRACE("read_attr_stat\n");
2113 	open_cookie *cookie = (open_cookie *)_cookie;
2114 	return cookie->node->ReadStat(stat);
2115 }
2116 
2117 
2118 static status_t
2119 overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie,
2120 	const struct stat *stat, int statMask)
2121 {
2122 	TRACE("write_attr_stat\n");
2123 	open_cookie *cookie = (open_cookie *)_cookie;
2124 	return cookie->node->WriteStat(stat, statMask);
2125 }
2126 
2127 
2128 static status_t
2129 overlay_rename_attr(fs_volume *volume, fs_vnode *vnode,
2130 	const char *fromName, fs_vnode *toVnode, const char *toName)
2131 {
2132 	TRACE("rename attr: \"%s\" -> \"%s\"\n", fromName, toName);
2133 	OverlayInode *fromNode = (OverlayInode *)vnode->private_node;
2134 	OverlayInode *toNode = (OverlayInode *)toVnode->private_node;
2135 	overlay_dirent *entry = NULL;
2136 
2137 	status_t result = fromNode->RemoveEntry(fromName, &entry, true);
2138 	if (result != B_OK)
2139 		return result;
2140 
2141 	char *oldName = entry->name;
2142 	entry->name = strdup(toName);
2143 	if (entry->name == NULL) {
2144 		entry->name = oldName;
2145 		if (fromNode->AddEntry(entry, true) != B_OK)
2146 			entry->dispose_attribute(volume, fromNode->InodeNumber());
2147 
2148 		return B_NO_MEMORY;
2149 	}
2150 
2151 	result = toNode->AddEntry(entry, true);
2152 	if (result != B_OK) {
2153 		free(entry->name);
2154 		entry->name = oldName;
2155 		if (fromNode->AddEntry(entry, true) != B_OK)
2156 			entry->dispose_attribute(volume, fromNode->InodeNumber());
2157 
2158 		return result;
2159 	}
2160 
2161 	OverlayInode *node = entry->node;
2162 	if (node == NULL)
2163 		return B_ERROR;
2164 
2165 	node->SetName(entry->name);
2166 	node->SetSuperVnode(toNode->SuperVnode());
2167 	node->SetInodeNumber(toNode->InodeNumber());
2168 
2169 	notify_attribute_changed(volume->id, -1, fromNode->InodeNumber(), fromName,
2170 		B_ATTR_REMOVED);
2171 	notify_attribute_changed(volume->id, -1, toNode->InodeNumber(), toName,
2172 		B_ATTR_CREATED);
2173 
2174 	free(oldName);
2175 	return B_OK;
2176 }
2177 
2178 
2179 static status_t
2180 overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name)
2181 {
2182 	TRACE("remove_attr\n");
2183 	OverlayInode *node = (OverlayInode *)vnode->private_node;
2184 	status_t result = node->RemoveEntry(name, NULL, true);
2185 	if (result != B_OK)
2186 		return result;
2187 
2188 	notify_attribute_changed(volume->id, -1, node->InodeNumber(), name,
2189 		B_ATTR_REMOVED);
2190 	return result;
2191 }
2192 
2193 
2194 static status_t
2195 overlay_create_special_node(fs_volume *volume, fs_vnode *vnode,
2196 	const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags,
2197 	fs_vnode *_superVnode, ino_t *nodeID)
2198 {
2199 	OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, nodeID)
2200 }
2201 
2202 
2203 static fs_vnode_ops sOverlayVnodeOps = {
2204 	&overlay_lookup,
2205 	&overlay_get_vnode_name,
2206 
2207 	&overlay_put_vnode,
2208 	&overlay_remove_vnode,
2209 
2210 	&overlay_can_page,
2211 	&overlay_read_pages,
2212 	&overlay_write_pages,
2213 
2214 	&overlay_io,
2215 	&overlay_cancel_io,
2216 
2217 	&overlay_get_file_map,
2218 
2219 	/* common */
2220 	&overlay_ioctl,
2221 	&overlay_set_flags,
2222 	&overlay_select,
2223 	&overlay_deselect,
2224 	&overlay_fsync,
2225 
2226 	&overlay_read_symlink,
2227 	&overlay_create_symlink,
2228 	&overlay_link,
2229 	&overlay_unlink,
2230 	&overlay_rename,
2231 
2232 	&overlay_access,
2233 	&overlay_read_stat,
2234 	&overlay_write_stat,
2235 	NULL,	// fs_preallocate
2236 
2237 	/* file */
2238 	&overlay_create,
2239 	&overlay_open,
2240 	&overlay_close,
2241 	&overlay_free_cookie,
2242 	&overlay_read,
2243 	&overlay_write,
2244 
2245 	/* directory */
2246 	&overlay_create_dir,
2247 	&overlay_remove_dir,
2248 	&overlay_open_dir,
2249 	&overlay_close_dir,
2250 	&overlay_free_dir_cookie,
2251 	&overlay_read_dir,
2252 	&overlay_rewind_dir,
2253 
2254 	/* attribute directory operations */
2255 	&overlay_open_attr_dir,
2256 	&overlay_close_attr_dir,
2257 	&overlay_free_attr_dir_cookie,
2258 	&overlay_read_attr_dir,
2259 	&overlay_rewind_attr_dir,
2260 
2261 	/* attribute operations */
2262 	&overlay_create_attr,
2263 	&overlay_open_attr,
2264 	&overlay_close_attr,
2265 	&overlay_free_attr_cookie,
2266 	&overlay_read_attr,
2267 	&overlay_write_attr,
2268 
2269 	&overlay_read_attr_stat,
2270 	&overlay_write_attr_stat,
2271 	&overlay_rename_attr,
2272 	&overlay_remove_attr,
2273 
2274 	/* support for node and FS layers */
2275 	&overlay_create_special_node,
2276 	&overlay_get_super_vnode
2277 };
2278 
2279 
2280 //	#pragma mark - volume ops
2281 
2282 
2283 #define OVERLAY_VOLUME_CALL(op, params...) \
2284 	TRACE_VOLUME("relaying volume op: " #op "\n"); \
2285 	if (volume->super_volume->ops->op != NULL) \
2286 		return volume->super_volume->ops->op(volume->super_volume, params);
2287 
2288 
2289 static status_t
2290 overlay_unmount(fs_volume *volume)
2291 {
2292 	TRACE_VOLUME("relaying volume op: unmount\n");
2293 	if (volume->super_volume != NULL
2294 		&& volume->super_volume->ops != NULL
2295 		&& volume->super_volume->ops->unmount != NULL)
2296 		volume->super_volume->ops->unmount(volume->super_volume);
2297 
2298 	delete (OverlayVolume *)volume->private_volume;
2299 	return B_OK;
2300 }
2301 
2302 
2303 static status_t
2304 overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
2305 {
2306 	TRACE_VOLUME("relaying volume op: read_fs_info\n");
2307 	status_t result = B_UNSUPPORTED;
2308 	if (volume->super_volume->ops->read_fs_info != NULL) {
2309 		result = volume->super_volume->ops->read_fs_info(volume->super_volume,
2310 			info);
2311 		if (result != B_OK)
2312 			return result;
2313 
2314 		info->flags &= ~B_FS_IS_READONLY;
2315 
2316 		// TODO: maybe calculate based on available ram
2317 		off_t available = 1024 * 1024 * 100 / info->block_size;
2318 		info->total_blocks += available;
2319 		info->free_blocks += available;
2320 		return B_OK;
2321 	}
2322 
2323 	return B_UNSUPPORTED;
2324 }
2325 
2326 
2327 static status_t
2328 overlay_write_fs_info(fs_volume *volume, const struct fs_info *info,
2329 	uint32 mask)
2330 {
2331 	OVERLAY_VOLUME_CALL(write_fs_info, info, mask)
2332 	return B_UNSUPPORTED;
2333 }
2334 
2335 
2336 static status_t
2337 overlay_sync(fs_volume *volume)
2338 {
2339 	TRACE_VOLUME("relaying volume op: sync\n");
2340 	if (volume->super_volume->ops->sync != NULL)
2341 		return volume->super_volume->ops->sync(volume->super_volume);
2342 	return B_UNSUPPORTED;
2343 }
2344 
2345 
2346 static status_t
2347 overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type,
2348 	uint32 *_flags, bool reenter)
2349 {
2350 	TRACE_VOLUME("relaying volume op: get_vnode\n");
2351 	if (volume->super_volume->ops->get_vnode != NULL) {
2352 		status_t status = volume->super_volume->ops->get_vnode(
2353 			volume->super_volume, id, vnode, _type, _flags, reenter);
2354 		if (status != B_OK)
2355 			return status;
2356 
2357 		OverlayInode *node = new(std::nothrow) OverlayInode(
2358 			(OverlayVolume *)volume->private_volume, vnode, id);
2359 		if (node == NULL) {
2360 			vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
2361 			return B_NO_MEMORY;
2362 		}
2363 
2364 		status = node->InitCheck();
2365 		if (status != B_OK) {
2366 			vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
2367 			delete node;
2368 			return status;
2369 		}
2370 
2371 		vnode->private_node = node;
2372 		vnode->ops = &sOverlayVnodeOps;
2373 		return B_OK;
2374 	}
2375 
2376 	return B_UNSUPPORTED;
2377 }
2378 
2379 
2380 static status_t
2381 overlay_open_index_dir(fs_volume *volume, void **cookie)
2382 {
2383 	OVERLAY_VOLUME_CALL(open_index_dir, cookie)
2384 	return B_UNSUPPORTED;
2385 }
2386 
2387 
2388 static status_t
2389 overlay_close_index_dir(fs_volume *volume, void *cookie)
2390 {
2391 	OVERLAY_VOLUME_CALL(close_index_dir, cookie)
2392 	return B_UNSUPPORTED;
2393 }
2394 
2395 
2396 static status_t
2397 overlay_free_index_dir_cookie(fs_volume *volume, void *cookie)
2398 {
2399 	OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie)
2400 	return B_UNSUPPORTED;
2401 }
2402 
2403 
2404 static status_t
2405 overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer,
2406 	size_t bufferSize, uint32 *_num)
2407 {
2408 	OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num)
2409 	return B_UNSUPPORTED;
2410 }
2411 
2412 
2413 static status_t
2414 overlay_rewind_index_dir(fs_volume *volume, void *cookie)
2415 {
2416 	OVERLAY_VOLUME_CALL(rewind_index_dir, cookie)
2417 	return B_UNSUPPORTED;
2418 }
2419 
2420 
2421 static status_t
2422 overlay_create_index(fs_volume *volume, const char *name, uint32 type,
2423 	uint32 flags)
2424 {
2425 	OVERLAY_VOLUME_CALL(create_index, name, type, flags)
2426 	return B_UNSUPPORTED;
2427 }
2428 
2429 
2430 static status_t
2431 overlay_remove_index(fs_volume *volume, const char *name)
2432 {
2433 	OVERLAY_VOLUME_CALL(remove_index, name)
2434 	return B_UNSUPPORTED;
2435 }
2436 
2437 
2438 static status_t
2439 overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat)
2440 {
2441 	OVERLAY_VOLUME_CALL(read_index_stat, name, stat)
2442 	return B_UNSUPPORTED;
2443 }
2444 
2445 
2446 static status_t
2447 overlay_open_query(fs_volume *volume, const char *query, uint32 flags,
2448 	port_id port, uint32 token, void **_cookie)
2449 {
2450 	OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie)
2451 	return B_UNSUPPORTED;
2452 }
2453 
2454 
2455 static status_t
2456 overlay_close_query(fs_volume *volume, void *cookie)
2457 {
2458 	OVERLAY_VOLUME_CALL(close_query, cookie)
2459 	return B_UNSUPPORTED;
2460 }
2461 
2462 
2463 static status_t
2464 overlay_free_query_cookie(fs_volume *volume, void *cookie)
2465 {
2466 	OVERLAY_VOLUME_CALL(free_query_cookie, cookie)
2467 	return B_UNSUPPORTED;
2468 }
2469 
2470 
2471 static status_t
2472 overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer,
2473 	size_t bufferSize, uint32 *_num)
2474 {
2475 	OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num)
2476 	return B_UNSUPPORTED;
2477 }
2478 
2479 
2480 static status_t
2481 overlay_rewind_query(fs_volume *volume, void *cookie)
2482 {
2483 	OVERLAY_VOLUME_CALL(rewind_query, cookie)
2484 	return B_UNSUPPORTED;
2485 }
2486 
2487 
2488 static status_t
2489 overlay_all_layers_mounted(fs_volume *volume)
2490 {
2491 	return B_OK;
2492 }
2493 
2494 
2495 static status_t
2496 overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode)
2497 {
2498 	OverlayInode *node = new(std::nothrow) OverlayInode(
2499 		(OverlayVolume *)volume->private_volume, vnode, id);
2500 	if (node == NULL)
2501 		return B_NO_MEMORY;
2502 
2503 	status_t status = node->InitCheck();
2504 	if (status != B_OK) {
2505 		delete node;
2506 		return status;
2507 	}
2508 
2509 	vnode->private_node = node;
2510 	vnode->ops = &sOverlayVnodeOps;
2511 	return B_OK;
2512 }
2513 
2514 
2515 static status_t
2516 overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode)
2517 {
2518 	delete (OverlayInode *)vnode->private_node;
2519 	return B_OK;
2520 }
2521 
2522 
2523 static fs_volume_ops sOverlayVolumeOps = {
2524 	&overlay_unmount,
2525 
2526 	&overlay_read_fs_info,
2527 	&overlay_write_fs_info,
2528 	&overlay_sync,
2529 
2530 	&overlay_get_vnode,
2531 	&overlay_open_index_dir,
2532 	&overlay_close_index_dir,
2533 	&overlay_free_index_dir_cookie,
2534 	&overlay_read_index_dir,
2535 	&overlay_rewind_index_dir,
2536 
2537 	&overlay_create_index,
2538 	&overlay_remove_index,
2539 	&overlay_read_index_stat,
2540 
2541 	&overlay_open_query,
2542 	&overlay_close_query,
2543 	&overlay_free_query_cookie,
2544 	&overlay_read_query,
2545 	&overlay_rewind_query,
2546 
2547 	&overlay_all_layers_mounted,
2548 	&overlay_create_sub_vnode,
2549 	&overlay_delete_sub_vnode
2550 };
2551 
2552 
2553 //	#pragma mark - filesystem module
2554 
2555 
2556 static status_t
2557 overlay_mount(fs_volume *volume, const char *device, uint32 flags,
2558 	const char *args, ino_t *rootID)
2559 {
2560 	TRACE_VOLUME("mounting write overlay\n");
2561 	volume->private_volume = new(std::nothrow) OverlayVolume(volume);
2562 	if (volume->private_volume == NULL)
2563 		return B_NO_MEMORY;
2564 
2565 	volume->ops = &sOverlayVolumeOps;
2566 	return B_OK;
2567 }
2568 
2569 
2570 static status_t
2571 overlay_std_ops(int32 op, ...)
2572 {
2573 	switch (op) {
2574 		case B_MODULE_INIT:
2575 		case B_MODULE_UNINIT:
2576 			return B_OK;
2577 		default:
2578 			return B_ERROR;
2579 	}
2580 }
2581 
2582 
2583 static file_system_module_info sOverlayFileSystem = {
2584 	{
2585 		"file_systems/write_overlay" B_CURRENT_FS_API_VERSION,
2586 		0,
2587 		overlay_std_ops,
2588 	},
2589 
2590 	"write_overlay",				// short_name
2591 	"Write Overlay File System",	// pretty_name
2592 	0,								// DDM flags
2593 
2594 	// scanning
2595 	NULL, // identify_partition
2596 	NULL, // scan_partition
2597 	NULL, // free_identify_partition_cookie
2598 	NULL, // free_partition_content_cookie
2599 
2600 	// general operations
2601 	&overlay_mount,
2602 
2603 	// capability querying
2604 	NULL, // get_supported_operations
2605 
2606 	NULL, // validate_resize
2607 	NULL, // validate_move
2608 	NULL, // validate_set_content_name
2609 	NULL, // validate_set_content_parameters
2610 	NULL, // validate_initialize
2611 
2612 	// shadow partition modification
2613 	NULL, // shadow_changed
2614 
2615 	// writing
2616 	NULL, // defragment
2617 	NULL, // repair
2618 	NULL, // resize
2619 	NULL, // move
2620 	NULL, // set_content_name
2621 	NULL, // set_content_parameters
2622 	NULL // initialize
2623 };
2624 
2625 
2626 status_t
2627 publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber, void *privateNode,
2628 	int type)
2629 {
2630 	return publish_vnode(volume, inodeNumber, privateNode, &sOverlayVnodeOps,
2631 		type, 0);
2632 }
2633 
2634 }	// namespace write_overlay
2635 
2636 using namespace write_overlay;
2637 
2638 module_info *modules[] = {
2639 	(module_info *)&sOverlayFileSystem,
2640 	NULL,
2641 };
2642