xref: /haiku/src/add-ons/kernel/file_systems/layers/write_overlay/write_overlay.cpp (revision 4bd0c1066b227cec4b79883bdef697c7a27f2e90)
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 				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
780 				memcpy(pointer, source, copyLength);
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
842 					memcpy(target, buffer, length);
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
901 		memcpy(target, buffer, length);
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 		return Read(NULL, 0, buffer, bufferSize, false, NULL);
1063 	}
1064 
1065 	if (fSuperVnode.ops->read_symlink == NULL)
1066 		return B_UNSUPPORTED;
1067 
1068 	return fSuperVnode.ops->read_symlink(SuperVolume(), &fSuperVnode, buffer,
1069 		bufferSize);
1070 }
1071 
1072 
1073 status_t
1074 OverlayInode::AddEntry(overlay_dirent *entry, bool attribute)
1075 {
1076 	RecursiveLocker locker(fLock);
1077 	if (!attribute && !fHasDirents)
1078 		_PopulateDirents();
1079 	else if (attribute && !fHasAttributeDirents)
1080 		_PopulateAttributeDirents();
1081 
1082 	status_t result = RemoveEntry(entry->name, NULL, attribute);
1083 	if (result != B_OK && result != B_ENTRY_NOT_FOUND)
1084 		return B_FILE_EXISTS;
1085 
1086 	overlay_dirent **newDirents = (overlay_dirent **)realloc(
1087 		attribute ? fAttributeDirents : fDirents,
1088 		sizeof(overlay_dirent *)
1089 			* ((attribute ? fAttributeDirentCount : fDirentCount) + 1));
1090 	if (newDirents == NULL)
1091 		return B_NO_MEMORY;
1092 
1093 	if (attribute) {
1094 		fAttributeDirents = newDirents;
1095 		fAttributeDirents[fAttributeDirentCount++] = entry;
1096 	} else {
1097 		fDirents = newDirents;
1098 		fDirents[fDirentCount++] = entry;
1099 	}
1100 
1101 	if (!fIsModified)
1102 		SetModified();
1103 
1104 	return B_OK;
1105 }
1106 
1107 
1108 status_t
1109 OverlayInode::RemoveEntry(const char *name, overlay_dirent **_entry,
1110 	bool attribute)
1111 {
1112 	RecursiveLocker locker(fLock);
1113 	if (!attribute && !fHasDirents)
1114 		_PopulateDirents();
1115 	else if (attribute && !fHasAttributeDirents)
1116 		_PopulateAttributeDirents();
1117 
1118 	uint32 direntCount = attribute ? fAttributeDirentCount : fDirentCount;
1119 	overlay_dirent **dirents = attribute ? fAttributeDirents : fDirents;
1120 	for (uint32 i = 0; i < direntCount; i++) {
1121 		overlay_dirent *entry = dirents[i];
1122 		if (strcmp(entry->name, name) == 0) {
1123 			if (_entry == NULL && !attribute) {
1124 				// check for non-empty directories when trying
1125 				// to dispose the entry
1126 				OverlayInode *node = NULL;
1127 				status_t result = get_vnode(Volume(), entry->inode_number,
1128 					(void **)&node);
1129 				if (result != B_OK)
1130 					return result;
1131 
1132 				if (node->IsNonEmptyDirectory())
1133 					result = B_DIRECTORY_NOT_EMPTY;
1134 
1135 				put_vnode(Volume(), entry->inode_number);
1136 				if (result != B_OK)
1137 					return result;
1138 			}
1139 
1140 			for (uint32 j = i + 1; j < direntCount; j++)
1141 				dirents[j - 1] = dirents[j];
1142 
1143 			if (attribute)
1144 				fAttributeDirentCount--;
1145 			else
1146 				fDirentCount--;
1147 
1148 			if (_entry != NULL)
1149 				*_entry = entry;
1150 			else if (attribute)
1151 				entry->dispose_attribute(Volume(), fInodeNumber);
1152 			else
1153 				entry->remove_and_dispose(Volume(), fInodeNumber);
1154 
1155 			if (!fIsModified)
1156 				SetModified();
1157 
1158 			return B_OK;
1159 		}
1160 	}
1161 
1162 	return B_ENTRY_NOT_FOUND;
1163 }
1164 
1165 
1166 void
1167 OverlayInode::_TrimBuffers()
1168 {
1169 	// the file size has been changed and we want to trim
1170 	// off everything that goes beyond the new size
1171 	write_buffer **link = &fWriteBuffers;
1172 	write_buffer *buffer = fWriteBuffers;
1173 
1174 	while (buffer != NULL) {
1175 		off_t bufferEnd = buffer->position + buffer->length;
1176 		if (bufferEnd > fStat.st_size)
1177 			break;
1178 
1179 		link = &buffer->next;
1180 		buffer = buffer->next;
1181 	}
1182 
1183 	if (buffer == NULL) {
1184 		// didn't find anything crossing or past the end
1185 		return;
1186 	}
1187 
1188 	if (buffer->position < fStat.st_size) {
1189 		// got a crossing buffer to resize
1190 		size_t newLength = fStat.st_size - buffer->position;
1191 		write_buffer *newBuffer = (write_buffer *)realloc(buffer,
1192 			sizeof(write_buffer) - 1 + newLength);
1193 
1194 		if (newBuffer != NULL) {
1195 			buffer = newBuffer;
1196 			*link = newBuffer;
1197 		} else {
1198 			// we don't really care if it worked, if it didn't we simply
1199 			// keep the old buffer and reset it's size
1200 		}
1201 
1202 		buffer->length = newLength;
1203 		link = &buffer->next;
1204 		buffer = buffer->next;
1205 	}
1206 
1207 	// everything else we can throw away
1208 	*link = NULL;
1209 	while (buffer != NULL) {
1210 		write_buffer *next = buffer->next;
1211 		free(buffer);
1212 		buffer = next;
1213 	}
1214 }
1215 
1216 
1217 status_t
1218 OverlayInode::_PopulateStat()
1219 {
1220 	if (fHasStat)
1221 		return B_OK;
1222 
1223  	fHasStat = true;
1224 	if (fIsAttribute) {
1225 		if (fName == NULL || fSuperVnode.ops->open_attr == NULL
1226 			|| fSuperVnode.ops->read_attr_stat == NULL)
1227 			return B_UNSUPPORTED;
1228 
1229 		void *cookie = NULL;
1230 		status_t result = fSuperVnode.ops->open_attr(SuperVolume(),
1231 			&fSuperVnode, fName, O_RDONLY, &cookie);
1232 		if (result != B_OK)
1233 			return result;
1234 
1235 		result = fSuperVnode.ops->read_attr_stat(SuperVolume(), &fSuperVnode,
1236 			cookie, &fStat);
1237 
1238 		if (fSuperVnode.ops->close_attr != NULL)
1239 			fSuperVnode.ops->close_attr(SuperVolume(), &fSuperVnode, cookie);
1240 
1241 		if (fSuperVnode.ops->free_attr_cookie != NULL) {
1242 			fSuperVnode.ops->free_attr_cookie(SuperVolume(), &fSuperVnode,
1243 				cookie);
1244 		}
1245 
1246 		return B_OK;
1247 	}
1248 
1249 	if (fSuperVnode.ops->read_stat == NULL)
1250 		return B_UNSUPPORTED;
1251 
1252 	return fSuperVnode.ops->read_stat(SuperVolume(), &fSuperVnode, &fStat);
1253 }
1254 
1255 
1256 status_t
1257 OverlayInode::_PopulateDirents()
1258 {
1259 	if (fHasDirents)
1260 		return B_OK;
1261 
1262 	fDirents = (overlay_dirent **)malloc(sizeof(overlay_dirent *) * 2);
1263 	if (fDirents == NULL)
1264 		return B_NO_MEMORY;
1265 
1266 	const char *names[] = { ".", ".." };
1267 	ino_t inodes[] = { fInodeNumber,
1268 		fParentDir != NULL ? fParentDir->InodeNumber() : 0 };
1269 	for (uint32 i = 0; i < 2; i++) {
1270 		fDirents[i] = (overlay_dirent *)malloc(sizeof(overlay_dirent));
1271 		if (fDirents[i] == NULL)
1272 			return B_NO_MEMORY;
1273 
1274 		fDirents[i]->inode_number = inodes[i];
1275 		fDirents[i]->name = strdup(names[i]);
1276 		if (fDirents[i]->name == NULL) {
1277 			free(fDirents[i]);
1278 			return B_NO_MEMORY;
1279 		}
1280 
1281 		fDirentCount++;
1282 	}
1283 
1284 	fHasDirents = true;
1285 	if (fIsVirtual || fSuperVnode.ops->open_dir == NULL
1286 		|| fSuperVnode.ops->read_dir == NULL)
1287 		return B_OK;
1288 
1289 	// we don't really care about errors from here on
1290 	void *superCookie = NULL;
1291 	status_t result = fSuperVnode.ops->open_dir(SuperVolume(),
1292 		&fSuperVnode, &superCookie);
1293 	if (result != B_OK)
1294 		return B_OK;
1295 
1296 	size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH;
1297 	struct dirent *buffer = (struct dirent *)malloc(bufferSize);
1298 	if (buffer == NULL)
1299 		goto close_dir;
1300 
1301 	while (true) {
1302 		uint32 num = 1;
1303 		result = fSuperVnode.ops->read_dir(SuperVolume(),
1304 			&fSuperVnode, superCookie, buffer, bufferSize, &num);
1305 		if (result != B_OK || num == 0)
1306 			break;
1307 
1308 		overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents,
1309 			sizeof(overlay_dirent *) * (fDirentCount + num));
1310 		if (newDirents == NULL) {
1311 			TRACE_ALWAYS("failed to allocate storage for dirents\n");
1312 			break;
1313 		}
1314 
1315 		fDirents = newDirents;
1316 		struct dirent *dirent = buffer;
1317 		for (uint32 i = 0; i < num; i++) {
1318 			if (strcmp(dirent->d_name, ".") != 0
1319 				&& strcmp(dirent->d_name, "..") != 0) {
1320 				overlay_dirent *entry = (overlay_dirent *)malloc(
1321 					sizeof(overlay_dirent));
1322 				if (entry == NULL) {
1323 					TRACE_ALWAYS("failed to allocate storage for dirent\n");
1324 					break;
1325 				}
1326 
1327 				entry->inode_number = dirent->d_ino;
1328 				entry->name = strdup(dirent->d_name);
1329 				if (entry->name == NULL) {
1330 					TRACE_ALWAYS("failed to duplicate dirent entry name\n");
1331 					free(entry);
1332 					break;
1333 				}
1334 
1335 				fDirents[fDirentCount++] = entry;
1336 			}
1337 
1338 			dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen);
1339 		}
1340 	}
1341 
1342 	free(buffer);
1343 
1344 close_dir:
1345 	if (fSuperVnode.ops->close_dir != NULL)
1346 		fSuperVnode.ops->close_dir(SuperVolume(), &fSuperVnode, superCookie);
1347 
1348 	if (fSuperVnode.ops->free_dir_cookie != NULL) {
1349 		fSuperVnode.ops->free_dir_cookie(SuperVolume(), &fSuperVnode,
1350 			superCookie);
1351 	}
1352 
1353 	return B_OK;
1354 }
1355 
1356 
1357 status_t
1358 OverlayInode::_PopulateAttributeDirents()
1359 {
1360 	if (fHasAttributeDirents)
1361 		return B_OK;
1362 
1363 	fHasAttributeDirents = true;
1364 	if (fIsVirtual || fSuperVnode.ops->open_attr_dir == NULL
1365 		|| fSuperVnode.ops->read_attr_dir == NULL)
1366 		return B_OK;
1367 
1368 	// we don't really care about errors from here on
1369 	void *superCookie = NULL;
1370 	status_t result = fSuperVnode.ops->open_attr_dir(SuperVolume(),
1371 		&fSuperVnode, &superCookie);
1372 	if (result != B_OK)
1373 		return B_OK;
1374 
1375 	size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH;
1376 	struct dirent *buffer = (struct dirent *)malloc(bufferSize);
1377 	if (buffer == NULL)
1378 		goto close_attr_dir;
1379 
1380 	while (true) {
1381 		uint32 num = 1;
1382 		result = fSuperVnode.ops->read_attr_dir(SuperVolume(),
1383 			&fSuperVnode, superCookie, buffer, bufferSize, &num);
1384 		if (result != B_OK || num == 0)
1385 			break;
1386 
1387 		overlay_dirent **newDirents = (overlay_dirent **)realloc(
1388 			fAttributeDirents, sizeof(overlay_dirent *)
1389 				* (fAttributeDirentCount + num));
1390 		if (newDirents == NULL) {
1391 			TRACE_ALWAYS("failed to allocate storage for attribute dirents\n");
1392 			break;
1393 		}
1394 
1395 		fAttributeDirents = newDirents;
1396 		struct dirent *dirent = buffer;
1397 		for (uint32 i = 0; i < num; i++) {
1398 			overlay_dirent *entry = (overlay_dirent *)malloc(
1399 				sizeof(overlay_dirent));
1400 			if (entry == NULL) {
1401 				TRACE_ALWAYS("failed to allocate storage for attr dirent\n");
1402 				break;
1403 			}
1404 
1405 			entry->node = NULL;
1406 			entry->inode_number = fInodeNumber;
1407 			entry->name = strdup(dirent->d_name);
1408 			if (entry->name == NULL) {
1409 				TRACE_ALWAYS("failed to duplicate dirent entry name\n");
1410 				free(entry);
1411 				break;
1412 			}
1413 
1414 			fAttributeDirents[fAttributeDirentCount++] = entry;
1415 			dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen);
1416 		}
1417 	}
1418 
1419 	free(buffer);
1420 
1421 close_attr_dir:
1422 	if (fSuperVnode.ops->close_attr_dir != NULL) {
1423 		fSuperVnode.ops->close_attr_dir(SuperVolume(), &fSuperVnode,
1424 			superCookie);
1425 	}
1426 
1427 	if (fSuperVnode.ops->free_attr_dir_cookie != NULL) {
1428 		fSuperVnode.ops->free_attr_dir_cookie(SuperVolume(), &fSuperVnode,
1429 			superCookie);
1430 	}
1431 
1432 	return B_OK;
1433 }
1434 
1435 
1436 status_t
1437 OverlayInode::_CreateCommon(const char *name, int type, int perms,
1438 	ino_t *newInodeNumber, OverlayInode **_node, bool attribute,
1439 	type_code attributeType)
1440 {
1441 	RecursiveLocker locker(fLock);
1442 	if (!fHasStat)
1443 		_PopulateStat();
1444 
1445 	if (!attribute && !S_ISDIR(fStat.st_mode))
1446 		return B_NOT_A_DIRECTORY;
1447 
1448 	locker.Unlock();
1449 
1450 	overlay_dirent *entry = (overlay_dirent *)malloc(sizeof(overlay_dirent));
1451 	if (entry == NULL)
1452 		return B_NO_MEMORY;
1453 
1454 	entry->node = NULL;
1455 	entry->name = strdup(name);
1456 	if (entry->name == NULL) {
1457 		free(entry);
1458 		return B_NO_MEMORY;
1459 	}
1460 
1461 	if (attribute)
1462 		entry->inode_number = fInodeNumber;
1463 	else
1464 		entry->inode_number = fVolume->BuildInodeNumber();
1465 
1466 	OverlayInode *node = new(std::nothrow) OverlayInode(fVolume, NULL,
1467 		entry->inode_number, this, entry->name, (perms & S_IUMSK) | type
1468 			| (attribute ? S_ATTR : 0), attribute, attributeType);
1469 	if (node == NULL) {
1470 		free(entry->name);
1471 		free(entry);
1472 		return B_NO_MEMORY;
1473 	}
1474 
1475 	status_t result = AddEntry(entry, attribute);
1476 	if (result != B_OK) {
1477 		free(entry->name);
1478 		free(entry);
1479 		delete node;
1480 		return result;
1481 	}
1482 
1483 	if (!attribute) {
1484 		result = publish_overlay_vnode(fVolume->Volume(), entry->inode_number,
1485 			node, type);
1486 		if (result != B_OK) {
1487 			RemoveEntry(entry->name, NULL);
1488 			delete node;
1489 			return result;
1490 		}
1491 	} else
1492 		entry->node = node;
1493 
1494 	node->Lock();
1495 	node->SetDataModified();
1496 	if (!attribute)
1497 		node->CreateCache();
1498 	node->Unlock();
1499 
1500 	if (newInodeNumber != NULL)
1501 		*newInodeNumber = entry->inode_number;
1502 	if (_node != NULL)
1503 		*_node = node;
1504 
1505 	if (attribute) {
1506 		notify_attribute_changed(SuperVolume()->id, -1, fInodeNumber,
1507 			entry->name, B_ATTR_CREATED);
1508 	} else {
1509 		notify_entry_created(SuperVolume()->id, fInodeNumber, entry->name,
1510 			entry->inode_number);
1511 	}
1512 
1513 	return B_OK;
1514 }
1515 
1516 
1517 //	#pragma mark - vnode ops
1518 
1519 
1520 #define OVERLAY_CALL(op, params...) \
1521 	TRACE("relaying op: " #op "\n"); \
1522 	OverlayInode *node = (OverlayInode *)vnode->private_node; \
1523 	if (node->IsVirtual()) \
1524 		return B_UNSUPPORTED; \
1525 	fs_vnode *superVnode = node->SuperVnode(); \
1526 	if (superVnode->ops->op != NULL) \
1527 		return superVnode->ops->op(volume->super_volume, superVnode, params); \
1528 	return B_UNSUPPORTED;
1529 
1530 
1531 static status_t
1532 overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1533 {
1534 	TRACE("put_vnode\n");
1535 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1536 	if (node->IsVirtual() || node->IsModified()) {
1537 		panic("loosing virtual/modified node\n");
1538 		delete node;
1539 		return B_OK;
1540 	}
1541 
1542 	status_t result = B_OK;
1543 	fs_vnode *superVnode = node->SuperVnode();
1544 	if (superVnode->ops->put_vnode != NULL) {
1545 		result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
1546 			reenter);
1547 	}
1548 
1549 	delete node;
1550 	return result;
1551 }
1552 
1553 
1554 static status_t
1555 overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1556 {
1557 	TRACE("remove_vnode\n");
1558 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1559 	if (node->IsVirtual()) {
1560 		delete node;
1561 		return B_OK;
1562 	}
1563 
1564 	status_t result = B_OK;
1565 	fs_vnode *superVnode = node->SuperVnode();
1566 	if (superVnode->ops->put_vnode != NULL) {
1567 		result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
1568 			reenter);
1569 	}
1570 
1571 	delete node;
1572 	return result;
1573 }
1574 
1575 
1576 static status_t
1577 overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode,
1578 	fs_volume *superVolume, fs_vnode *_superVnode)
1579 {
1580 	if (volume == superVolume) {
1581 		*_superVnode = *vnode;
1582 		return B_OK;
1583 	}
1584 
1585 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1586 	if (node->IsVirtual()) {
1587 		*_superVnode = *vnode;
1588 		return B_OK;
1589 	}
1590 
1591 	fs_vnode *superVnode = node->SuperVnode();
1592 	if (superVnode->ops->get_super_vnode != NULL) {
1593 		return superVnode->ops->get_super_vnode(volume->super_volume,
1594 			superVnode, superVolume, _superVnode);
1595 	}
1596 
1597 	*_superVnode = *superVnode;
1598 	return B_OK;
1599 }
1600 
1601 
1602 static status_t
1603 overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id)
1604 {
1605 	TRACE("lookup: \"%s\"\n", name);
1606 	return ((OverlayInode *)vnode->private_node)->Lookup(name, id);
1607 }
1608 
1609 
1610 static status_t
1611 overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer,
1612 	size_t bufferSize)
1613 {
1614 	return ((OverlayInode *)vnode->private_node)->GetName(buffer, bufferSize);
1615 }
1616 
1617 
1618 static bool
1619 overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie)
1620 {
1621 	TRACE("relaying op: can_page\n");
1622 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1623 	if (node->IsVirtual())
1624 		return false;
1625 
1626 	fs_vnode *superVnode = node->SuperVnode();
1627 	if (superVnode->ops->can_page != NULL) {
1628 		return superVnode->ops->can_page(volume->super_volume, superVnode,
1629 			cookie);
1630 	}
1631 
1632 	return false;
1633 }
1634 
1635 
1636 static status_t
1637 overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1638 	const iovec *vecs, size_t count, size_t *numBytes)
1639 {
1640 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1641 	size_t bytesLeft = *numBytes;
1642 
1643 	for (size_t i = 0; i < count; i++) {
1644 		size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft);
1645 		status_t result = node->Read(cookie, pos, vecs[i].iov_base,
1646 			&transferBytes, true, NULL);
1647 		if (result != B_OK) {
1648 			*numBytes -= bytesLeft;
1649 			return result;
1650 		}
1651 
1652 		bytesLeft -= transferBytes;
1653 		if (bytesLeft == 0)
1654 			return B_OK;
1655 
1656 		if (transferBytes < vecs[i].iov_len) {
1657 			*numBytes -= bytesLeft;
1658 			return B_OK;
1659 		}
1660 
1661 		pos += transferBytes;
1662 	}
1663 
1664 	*numBytes = 0;
1665 	return B_OK;
1666 }
1667 
1668 
1669 static status_t
1670 overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1671 	const iovec *vecs, size_t count, size_t *numBytes)
1672 {
1673 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1674 	size_t bytesLeft = *numBytes;
1675 
1676 	for (size_t i = 0; i < count; i++) {
1677 		size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft);
1678 		status_t result = node->Write(cookie, pos, vecs[i].iov_base,
1679 			transferBytes, NULL);
1680 		if (result != B_OK) {
1681 			*numBytes -= bytesLeft;
1682 			return result;
1683 		}
1684 
1685 		bytesLeft -= transferBytes;
1686 		if (bytesLeft == 0)
1687 			return B_OK;
1688 
1689 		if (transferBytes < vecs[i].iov_len) {
1690 			*numBytes -= bytesLeft;
1691 			return B_OK;
1692 		}
1693 
1694 		pos += transferBytes;
1695 	}
1696 
1697 	*numBytes = 0;
1698 	return B_OK;
1699 }
1700 
1701 
1702 static status_t
1703 overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1704 	io_request *request)
1705 {
1706 	OverlayInode *node = (OverlayInode *)vnode->private_node;
1707 	if (io_request_is_write(request) || node->IsModified())
1708 		return node->SynchronousIO(cookie, (IORequest *)request);
1709 
1710 	TRACE("relaying op: io\n");
1711 	fs_vnode *superVnode = node->SuperVnode();
1712 	if (superVnode->ops->io != NULL) {
1713 		return superVnode->ops->io(volume->super_volume, superVnode,
1714 			cookie != NULL ? ((open_cookie *)cookie)->super_cookie : NULL,
1715 			request);
1716 	}
1717 
1718 	return B_UNSUPPORTED;
1719 }
1720 
1721 
1722 static status_t
1723 overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1724 	io_request *request)
1725 {
1726 	OVERLAY_CALL(cancel_io, cookie, request)
1727 }
1728 
1729 
1730 static status_t
1731 overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset,
1732 	size_t size, struct file_io_vec *vecs, size_t *count)
1733 {
1734 	OVERLAY_CALL(get_file_map, offset, size, vecs, count)
1735 }
1736 
1737 
1738 static status_t
1739 overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op,
1740 	void *buffer, size_t length)
1741 {
1742 	OVERLAY_CALL(ioctl, cookie, op, buffer, length)
1743 }
1744 
1745 
1746 static status_t
1747 overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie,
1748 	int flags)
1749 {
1750 	return ((OverlayInode *)vnode->private_node)->SetFlags(cookie, flags);
1751 }
1752 
1753 
1754 static status_t
1755 overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1756 	selectsync *sync)
1757 {
1758 	OVERLAY_CALL(select, cookie, event, sync)
1759 }
1760 
1761 
1762 static status_t
1763 overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1764 	selectsync *sync)
1765 {
1766 	OVERLAY_CALL(deselect, cookie, event, sync)
1767 }
1768 
1769 
1770 static status_t
1771 overlay_fsync(fs_volume *volume, fs_vnode *vnode)
1772 {
1773 	return B_OK;
1774 }
1775 
1776 
1777 static status_t
1778 overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer,
1779 	size_t *bufferSize)
1780 {
1781 	TRACE("read_symlink\n");
1782 	return ((OverlayInode *)vnode->private_node)->ReadSymlink(buffer,
1783 		bufferSize);
1784 }
1785 
1786 
1787 static status_t
1788 overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name,
1789 	const char *path, int mode)
1790 {
1791 	TRACE("create_symlink: \"%s\" -> \"%s\"\n", name, path);
1792 	return ((OverlayInode *)vnode->private_node)->CreateSymlink(name, path,
1793 		mode);
1794 }
1795 
1796 
1797 static status_t
1798 overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name,
1799 	fs_vnode *target)
1800 {
1801 	return B_UNSUPPORTED;
1802 }
1803 
1804 
1805 static status_t
1806 overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name)
1807 {
1808 	TRACE("unlink: \"%s\"\n", name);
1809 	return ((OverlayInode *)vnode->private_node)->RemoveEntry(name, NULL);
1810 }
1811 
1812 
1813 static status_t
1814 overlay_rename(fs_volume *volume, fs_vnode *vnode,
1815 	const char *fromName, fs_vnode *toVnode, const char *toName)
1816 {
1817 	TRACE("rename: \"%s\" -> \"%s\"\n", fromName, toName);
1818 	OverlayInode *fromNode = (OverlayInode *)vnode->private_node;
1819 	OverlayInode *toNode = (OverlayInode *)toVnode->private_node;
1820 	overlay_dirent *entry = NULL;
1821 
1822 	status_t result = fromNode->RemoveEntry(fromName, &entry);
1823 	if (result != B_OK)
1824 		return result;
1825 
1826 	char *oldName = entry->name;
1827 	entry->name = strdup(toName);
1828 	if (entry->name == NULL) {
1829 		entry->name = oldName;
1830 		if (fromNode->AddEntry(entry) != B_OK)
1831 			entry->remove_and_dispose(volume, fromNode->InodeNumber());
1832 
1833 		return B_NO_MEMORY;
1834 	}
1835 
1836 	result = toNode->AddEntry(entry);
1837 	if (result != B_OK) {
1838 		free(entry->name);
1839 		entry->name = oldName;
1840 		if (fromNode->AddEntry(entry) != B_OK)
1841 			entry->remove_and_dispose(volume, fromNode->InodeNumber());
1842 
1843 		return result;
1844 	}
1845 
1846 	OverlayInode *node = NULL;
1847 	result = get_vnode(volume, entry->inode_number, (void **)&node);
1848 	if (result == B_OK && node != NULL) {
1849 		node->SetName(entry->name);
1850 		node->SetParentDir(toNode);
1851 		put_vnode(volume, entry->inode_number);
1852 	}
1853 
1854 	free(oldName);
1855 	notify_entry_moved(volume->id, fromNode->InodeNumber(), fromName,
1856 		toNode->InodeNumber(), toName, entry->inode_number);
1857 	return B_OK;
1858 }
1859 
1860 
1861 static status_t
1862 overlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
1863 {
1864 	// TODO: implement
1865 	return B_OK;
1866 }
1867 
1868 
1869 static status_t
1870 overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat)
1871 {
1872 	TRACE("read_stat\n");
1873 	return ((OverlayInode *)vnode->private_node)->ReadStat(stat);
1874 }
1875 
1876 
1877 static status_t
1878 overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat,
1879 	uint32 statMask)
1880 {
1881 	TRACE("write_stat\n");
1882 	return ((OverlayInode *)vnode->private_node)->WriteStat(stat, statMask);
1883 }
1884 
1885 
1886 static status_t
1887 overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name,
1888 	int openMode, int perms, void **cookie, ino_t *newVnodeID)
1889 {
1890 	TRACE("create: \"%s\"\n", name);
1891 	return ((OverlayInode *)vnode->private_node)->Create(name, openMode,
1892 		perms, cookie, newVnodeID);
1893 }
1894 
1895 
1896 static status_t
1897 overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie)
1898 {
1899 	TRACE("open\n");
1900 	return ((OverlayInode *)vnode->private_node)->Open(openMode, cookie);
1901 }
1902 
1903 
1904 static status_t
1905 overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie)
1906 {
1907 	TRACE("close\n");
1908 	return ((OverlayInode *)vnode->private_node)->Close(cookie);
1909 }
1910 
1911 
1912 static status_t
1913 overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1914 {
1915 	TRACE("free_cookie\n");
1916 	return ((OverlayInode *)vnode->private_node)->FreeCookie(cookie);
1917 }
1918 
1919 
1920 static status_t
1921 overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1922 	void *buffer, size_t *length)
1923 {
1924 	TRACE("read\n");
1925 	return ((OverlayInode *)vnode->private_node)->Read(cookie, pos, buffer,
1926 		length, false, NULL);
1927 }
1928 
1929 
1930 static status_t
1931 overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1932 	const void *buffer, size_t *length)
1933 {
1934 	TRACE("write\n");
1935 	return ((OverlayInode *)vnode->private_node)->Write(cookie, pos, buffer,
1936 		*length, NULL);
1937 }
1938 
1939 
1940 static status_t
1941 overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name,
1942 	int perms)
1943 {
1944 	TRACE("create_dir: \"%s\"\n", name);
1945 	return ((OverlayInode *)vnode->private_node)->CreateDir(name, perms);
1946 }
1947 
1948 
1949 static status_t
1950 overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name)
1951 {
1952 	TRACE("remove_dir: \"%s\"\n", name);
1953 	return ((OverlayInode *)vnode->private_node)->RemoveDir(name);
1954 }
1955 
1956 
1957 static status_t
1958 overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
1959 {
1960 	TRACE("open_dir\n");
1961 	return ((OverlayInode *)vnode->private_node)->OpenDir(cookie);
1962 }
1963 
1964 
1965 static status_t
1966 overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1967 {
1968 	TRACE("close_dir\n");
1969 	return ((OverlayInode *)vnode->private_node)->CloseDir(cookie);
1970 }
1971 
1972 
1973 static status_t
1974 overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1975 {
1976 	TRACE("free_dir_cookie\n");
1977 	return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie);
1978 }
1979 
1980 
1981 static status_t
1982 overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
1983 	struct dirent *buffer, size_t bufferSize, uint32 *num)
1984 {
1985 	TRACE("read_dir\n");
1986 	return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer,
1987 		bufferSize, num);
1988 }
1989 
1990 
1991 static status_t
1992 overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1993 {
1994 	TRACE("rewind_dir\n");
1995 	return ((OverlayInode *)vnode->private_node)->RewindDir(cookie);
1996 }
1997 
1998 
1999 static status_t
2000 overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
2001 {
2002 	TRACE("open_attr_dir\n");
2003 	return ((OverlayInode *)vnode->private_node)->OpenDir(cookie, true);
2004 }
2005 
2006 
2007 static status_t
2008 overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
2009 {
2010 	TRACE("close_attr_dir\n");
2011 	return ((OverlayInode *)vnode->private_node)->CloseDir(cookie);
2012 }
2013 
2014 
2015 static status_t
2016 overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
2017 {
2018 	TRACE("free_attr_dir_cookie\n");
2019 	return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie);
2020 }
2021 
2022 
2023 static status_t
2024 overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
2025 	struct dirent *buffer, size_t bufferSize, uint32 *num)
2026 {
2027 	TRACE("read_attr_dir\n");
2028 	return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer,
2029 		bufferSize, num, true);
2030 }
2031 
2032 
2033 static status_t
2034 overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
2035 {
2036 	TRACE("rewind_attr_dir\n");
2037 	return ((OverlayInode *)vnode->private_node)->RewindDir(cookie);
2038 }
2039 
2040 
2041 static status_t
2042 overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
2043 	uint32 type, int openMode, void **cookie)
2044 {
2045 	TRACE("create_attr\n");
2046 	return ((OverlayInode *)vnode->private_node)->Create(name, openMode, 0,
2047 		cookie, NULL, true, type);
2048 }
2049 
2050 
2051 static status_t
2052 overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
2053 	int openMode, void **cookie)
2054 {
2055 	TRACE("open_attr\n");
2056 	OverlayInode *node = NULL;
2057 	OverlayInode *parentNode = (OverlayInode *)vnode->private_node;
2058 	status_t result = parentNode->LookupAttribute(name, &node);
2059 	if (result != B_OK)
2060 		return result;
2061 	if (node == NULL)
2062 		return B_ERROR;
2063 
2064 	return node->Open(openMode, cookie);
2065 }
2066 
2067 
2068 static status_t
2069 overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie)
2070 {
2071 	TRACE("close_attr\n");
2072 	open_cookie *cookie = (open_cookie *)_cookie;
2073 	return cookie->node->Close(cookie);
2074 }
2075 
2076 
2077 static status_t
2078 overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *_cookie)
2079 {
2080 	TRACE("free_attr_cookie\n");
2081 	open_cookie *cookie = (open_cookie *)_cookie;
2082 	return cookie->node->FreeCookie(cookie);
2083 }
2084 
2085 
2086 static status_t
2087 overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos,
2088 	void *buffer, size_t *length)
2089 {
2090 	TRACE("read_attr\n");
2091 	open_cookie *cookie = (open_cookie *)_cookie;
2092 	return cookie->node->Read(cookie, pos, buffer, length, false, NULL);
2093 }
2094 
2095 
2096 static status_t
2097 overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos,
2098 	const void *buffer, size_t *length)
2099 {
2100 	TRACE("write_attr\n");
2101 	open_cookie *cookie = (open_cookie *)_cookie;
2102 	return cookie->node->Write(cookie, pos, buffer, *length, NULL);
2103 }
2104 
2105 
2106 static status_t
2107 overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie,
2108 	struct stat *stat)
2109 {
2110 	TRACE("read_attr_stat\n");
2111 	open_cookie *cookie = (open_cookie *)_cookie;
2112 	return cookie->node->ReadStat(stat);
2113 }
2114 
2115 
2116 static status_t
2117 overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie,
2118 	const struct stat *stat, int statMask)
2119 {
2120 	TRACE("write_attr_stat\n");
2121 	open_cookie *cookie = (open_cookie *)_cookie;
2122 	return cookie->node->WriteStat(stat, statMask);
2123 }
2124 
2125 
2126 static status_t
2127 overlay_rename_attr(fs_volume *volume, fs_vnode *vnode,
2128 	const char *fromName, fs_vnode *toVnode, const char *toName)
2129 {
2130 	TRACE("rename attr: \"%s\" -> \"%s\"\n", fromName, toName);
2131 	OverlayInode *fromNode = (OverlayInode *)vnode->private_node;
2132 	OverlayInode *toNode = (OverlayInode *)toVnode->private_node;
2133 	overlay_dirent *entry = NULL;
2134 
2135 	status_t result = fromNode->RemoveEntry(fromName, &entry, true);
2136 	if (result != B_OK)
2137 		return result;
2138 
2139 	char *oldName = entry->name;
2140 	entry->name = strdup(toName);
2141 	if (entry->name == NULL) {
2142 		entry->name = oldName;
2143 		if (fromNode->AddEntry(entry, true) != B_OK)
2144 			entry->dispose_attribute(volume, fromNode->InodeNumber());
2145 
2146 		return B_NO_MEMORY;
2147 	}
2148 
2149 	result = toNode->AddEntry(entry, true);
2150 	if (result != B_OK) {
2151 		free(entry->name);
2152 		entry->name = oldName;
2153 		if (fromNode->AddEntry(entry, true) != B_OK)
2154 			entry->dispose_attribute(volume, fromNode->InodeNumber());
2155 
2156 		return result;
2157 	}
2158 
2159 	OverlayInode *node = entry->node;
2160 	if (node == NULL)
2161 		return B_ERROR;
2162 
2163 	node->SetName(entry->name);
2164 	node->SetSuperVnode(toNode->SuperVnode());
2165 	node->SetInodeNumber(toNode->InodeNumber());
2166 
2167 	notify_attribute_changed(volume->id, -1, fromNode->InodeNumber(), fromName,
2168 		B_ATTR_REMOVED);
2169 	notify_attribute_changed(volume->id, -1, toNode->InodeNumber(), toName,
2170 		B_ATTR_CREATED);
2171 
2172 	free(oldName);
2173 	return B_OK;
2174 }
2175 
2176 
2177 static status_t
2178 overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name)
2179 {
2180 	TRACE("remove_attr\n");
2181 	OverlayInode *node = (OverlayInode *)vnode->private_node;
2182 	status_t result = node->RemoveEntry(name, NULL, true);
2183 	if (result != B_OK)
2184 		return result;
2185 
2186 	notify_attribute_changed(volume->id, -1, node->InodeNumber(), name,
2187 		B_ATTR_REMOVED);
2188 	return result;
2189 }
2190 
2191 
2192 static status_t
2193 overlay_create_special_node(fs_volume *volume, fs_vnode *vnode,
2194 	const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags,
2195 	fs_vnode *_superVnode, ino_t *nodeID)
2196 {
2197 	OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, nodeID)
2198 }
2199 
2200 
2201 static fs_vnode_ops sOverlayVnodeOps = {
2202 	&overlay_lookup,
2203 	&overlay_get_vnode_name,
2204 
2205 	&overlay_put_vnode,
2206 	&overlay_remove_vnode,
2207 
2208 	&overlay_can_page,
2209 	&overlay_read_pages,
2210 	&overlay_write_pages,
2211 
2212 	&overlay_io,
2213 	&overlay_cancel_io,
2214 
2215 	&overlay_get_file_map,
2216 
2217 	/* common */
2218 	&overlay_ioctl,
2219 	&overlay_set_flags,
2220 	&overlay_select,
2221 	&overlay_deselect,
2222 	&overlay_fsync,
2223 
2224 	&overlay_read_symlink,
2225 	&overlay_create_symlink,
2226 	&overlay_link,
2227 	&overlay_unlink,
2228 	&overlay_rename,
2229 
2230 	&overlay_access,
2231 	&overlay_read_stat,
2232 	&overlay_write_stat,
2233 	NULL,	// fs_preallocate
2234 
2235 	/* file */
2236 	&overlay_create,
2237 	&overlay_open,
2238 	&overlay_close,
2239 	&overlay_free_cookie,
2240 	&overlay_read,
2241 	&overlay_write,
2242 
2243 	/* directory */
2244 	&overlay_create_dir,
2245 	&overlay_remove_dir,
2246 	&overlay_open_dir,
2247 	&overlay_close_dir,
2248 	&overlay_free_dir_cookie,
2249 	&overlay_read_dir,
2250 	&overlay_rewind_dir,
2251 
2252 	/* attribute directory operations */
2253 	&overlay_open_attr_dir,
2254 	&overlay_close_attr_dir,
2255 	&overlay_free_attr_dir_cookie,
2256 	&overlay_read_attr_dir,
2257 	&overlay_rewind_attr_dir,
2258 
2259 	/* attribute operations */
2260 	&overlay_create_attr,
2261 	&overlay_open_attr,
2262 	&overlay_close_attr,
2263 	&overlay_free_attr_cookie,
2264 	&overlay_read_attr,
2265 	&overlay_write_attr,
2266 
2267 	&overlay_read_attr_stat,
2268 	&overlay_write_attr_stat,
2269 	&overlay_rename_attr,
2270 	&overlay_remove_attr,
2271 
2272 	/* support for node and FS layers */
2273 	&overlay_create_special_node,
2274 	&overlay_get_super_vnode
2275 };
2276 
2277 
2278 //	#pragma mark - volume ops
2279 
2280 
2281 #define OVERLAY_VOLUME_CALL(op, params...) \
2282 	TRACE_VOLUME("relaying volume op: " #op "\n"); \
2283 	if (volume->super_volume->ops->op != NULL) \
2284 		return volume->super_volume->ops->op(volume->super_volume, params);
2285 
2286 
2287 static status_t
2288 overlay_unmount(fs_volume *volume)
2289 {
2290 	TRACE_VOLUME("relaying volume op: unmount\n");
2291 	if (volume->super_volume != NULL
2292 		&& volume->super_volume->ops != NULL
2293 		&& volume->super_volume->ops->unmount != NULL)
2294 		volume->super_volume->ops->unmount(volume->super_volume);
2295 
2296 	delete (OverlayVolume *)volume->private_volume;
2297 	return B_OK;
2298 }
2299 
2300 
2301 static status_t
2302 overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
2303 {
2304 	TRACE_VOLUME("relaying volume op: read_fs_info\n");
2305 	status_t result = B_UNSUPPORTED;
2306 	if (volume->super_volume->ops->read_fs_info != NULL) {
2307 		result = volume->super_volume->ops->read_fs_info(volume->super_volume,
2308 			info);
2309 		if (result != B_OK)
2310 			return result;
2311 
2312 		info->flags &= ~B_FS_IS_READONLY;
2313 
2314 		// TODO: maybe calculate based on available ram
2315 		off_t available = 1024 * 1024 * 100 / info->block_size;
2316 		info->total_blocks += available;
2317 		info->free_blocks += available;
2318 		return B_OK;
2319 	}
2320 
2321 	return B_UNSUPPORTED;
2322 }
2323 
2324 
2325 static status_t
2326 overlay_write_fs_info(fs_volume *volume, const struct fs_info *info,
2327 	uint32 mask)
2328 {
2329 	OVERLAY_VOLUME_CALL(write_fs_info, info, mask)
2330 	return B_UNSUPPORTED;
2331 }
2332 
2333 
2334 static status_t
2335 overlay_sync(fs_volume *volume)
2336 {
2337 	TRACE_VOLUME("relaying volume op: sync\n");
2338 	if (volume->super_volume->ops->sync != NULL)
2339 		return volume->super_volume->ops->sync(volume->super_volume);
2340 	return B_UNSUPPORTED;
2341 }
2342 
2343 
2344 static status_t
2345 overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type,
2346 	uint32 *_flags, bool reenter)
2347 {
2348 	TRACE_VOLUME("relaying volume op: get_vnode\n");
2349 	if (volume->super_volume->ops->get_vnode != NULL) {
2350 		status_t status = volume->super_volume->ops->get_vnode(
2351 			volume->super_volume, id, vnode, _type, _flags, reenter);
2352 		if (status != B_OK)
2353 			return status;
2354 
2355 		OverlayInode *node = new(std::nothrow) OverlayInode(
2356 			(OverlayVolume *)volume->private_volume, vnode, id);
2357 		if (node == NULL) {
2358 			vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
2359 			return B_NO_MEMORY;
2360 		}
2361 
2362 		status = node->InitCheck();
2363 		if (status != B_OK) {
2364 			vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
2365 			delete node;
2366 			return status;
2367 		}
2368 
2369 		vnode->private_node = node;
2370 		vnode->ops = &sOverlayVnodeOps;
2371 		return B_OK;
2372 	}
2373 
2374 	return B_UNSUPPORTED;
2375 }
2376 
2377 
2378 static status_t
2379 overlay_open_index_dir(fs_volume *volume, void **cookie)
2380 {
2381 	OVERLAY_VOLUME_CALL(open_index_dir, cookie)
2382 	return B_UNSUPPORTED;
2383 }
2384 
2385 
2386 static status_t
2387 overlay_close_index_dir(fs_volume *volume, void *cookie)
2388 {
2389 	OVERLAY_VOLUME_CALL(close_index_dir, cookie)
2390 	return B_UNSUPPORTED;
2391 }
2392 
2393 
2394 static status_t
2395 overlay_free_index_dir_cookie(fs_volume *volume, void *cookie)
2396 {
2397 	OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie)
2398 	return B_UNSUPPORTED;
2399 }
2400 
2401 
2402 static status_t
2403 overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer,
2404 	size_t bufferSize, uint32 *_num)
2405 {
2406 	OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num)
2407 	return B_UNSUPPORTED;
2408 }
2409 
2410 
2411 static status_t
2412 overlay_rewind_index_dir(fs_volume *volume, void *cookie)
2413 {
2414 	OVERLAY_VOLUME_CALL(rewind_index_dir, cookie)
2415 	return B_UNSUPPORTED;
2416 }
2417 
2418 
2419 static status_t
2420 overlay_create_index(fs_volume *volume, const char *name, uint32 type,
2421 	uint32 flags)
2422 {
2423 	OVERLAY_VOLUME_CALL(create_index, name, type, flags)
2424 	return B_UNSUPPORTED;
2425 }
2426 
2427 
2428 static status_t
2429 overlay_remove_index(fs_volume *volume, const char *name)
2430 {
2431 	OVERLAY_VOLUME_CALL(remove_index, name)
2432 	return B_UNSUPPORTED;
2433 }
2434 
2435 
2436 static status_t
2437 overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat)
2438 {
2439 	OVERLAY_VOLUME_CALL(read_index_stat, name, stat)
2440 	return B_UNSUPPORTED;
2441 }
2442 
2443 
2444 static status_t
2445 overlay_open_query(fs_volume *volume, const char *query, uint32 flags,
2446 	port_id port, uint32 token, void **_cookie)
2447 {
2448 	OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie)
2449 	return B_UNSUPPORTED;
2450 }
2451 
2452 
2453 static status_t
2454 overlay_close_query(fs_volume *volume, void *cookie)
2455 {
2456 	OVERLAY_VOLUME_CALL(close_query, cookie)
2457 	return B_UNSUPPORTED;
2458 }
2459 
2460 
2461 static status_t
2462 overlay_free_query_cookie(fs_volume *volume, void *cookie)
2463 {
2464 	OVERLAY_VOLUME_CALL(free_query_cookie, cookie)
2465 	return B_UNSUPPORTED;
2466 }
2467 
2468 
2469 static status_t
2470 overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer,
2471 	size_t bufferSize, uint32 *_num)
2472 {
2473 	OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num)
2474 	return B_UNSUPPORTED;
2475 }
2476 
2477 
2478 static status_t
2479 overlay_rewind_query(fs_volume *volume, void *cookie)
2480 {
2481 	OVERLAY_VOLUME_CALL(rewind_query, cookie)
2482 	return B_UNSUPPORTED;
2483 }
2484 
2485 
2486 static status_t
2487 overlay_all_layers_mounted(fs_volume *volume)
2488 {
2489 	return B_OK;
2490 }
2491 
2492 
2493 static status_t
2494 overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode)
2495 {
2496 	OverlayInode *node = new(std::nothrow) OverlayInode(
2497 		(OverlayVolume *)volume->private_volume, vnode, id);
2498 	if (node == NULL)
2499 		return B_NO_MEMORY;
2500 
2501 	status_t status = node->InitCheck();
2502 	if (status != B_OK) {
2503 		delete node;
2504 		return status;
2505 	}
2506 
2507 	vnode->private_node = node;
2508 	vnode->ops = &sOverlayVnodeOps;
2509 	return B_OK;
2510 }
2511 
2512 
2513 static status_t
2514 overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode)
2515 {
2516 	delete (OverlayInode *)vnode->private_node;
2517 	return B_OK;
2518 }
2519 
2520 
2521 static fs_volume_ops sOverlayVolumeOps = {
2522 	&overlay_unmount,
2523 
2524 	&overlay_read_fs_info,
2525 	&overlay_write_fs_info,
2526 	&overlay_sync,
2527 
2528 	&overlay_get_vnode,
2529 	&overlay_open_index_dir,
2530 	&overlay_close_index_dir,
2531 	&overlay_free_index_dir_cookie,
2532 	&overlay_read_index_dir,
2533 	&overlay_rewind_index_dir,
2534 
2535 	&overlay_create_index,
2536 	&overlay_remove_index,
2537 	&overlay_read_index_stat,
2538 
2539 	&overlay_open_query,
2540 	&overlay_close_query,
2541 	&overlay_free_query_cookie,
2542 	&overlay_read_query,
2543 	&overlay_rewind_query,
2544 
2545 	&overlay_all_layers_mounted,
2546 	&overlay_create_sub_vnode,
2547 	&overlay_delete_sub_vnode
2548 };
2549 
2550 
2551 //	#pragma mark - filesystem module
2552 
2553 
2554 static status_t
2555 overlay_mount(fs_volume *volume, const char *device, uint32 flags,
2556 	const char *args, ino_t *rootID)
2557 {
2558 	TRACE_VOLUME("mounting write overlay\n");
2559 	volume->private_volume = new(std::nothrow) OverlayVolume(volume);
2560 	if (volume->private_volume == NULL)
2561 		return B_NO_MEMORY;
2562 
2563 	volume->ops = &sOverlayVolumeOps;
2564 	return B_OK;
2565 }
2566 
2567 
2568 static status_t
2569 overlay_std_ops(int32 op, ...)
2570 {
2571 	switch (op) {
2572 		case B_MODULE_INIT:
2573 		case B_MODULE_UNINIT:
2574 			return B_OK;
2575 		default:
2576 			return B_ERROR;
2577 	}
2578 }
2579 
2580 
2581 static file_system_module_info sOverlayFileSystem = {
2582 	{
2583 		"file_systems/write_overlay" B_CURRENT_FS_API_VERSION,
2584 		0,
2585 		overlay_std_ops,
2586 	},
2587 
2588 	"write_overlay",				// short_name
2589 	"Write Overlay File System",	// pretty_name
2590 	0,								// DDM flags
2591 
2592 	// scanning
2593 	NULL, // identify_partition
2594 	NULL, // scan_partition
2595 	NULL, // free_identify_partition_cookie
2596 	NULL, // free_partition_content_cookie
2597 
2598 	// general operations
2599 	&overlay_mount,
2600 
2601 	// capability querying
2602 	NULL, // get_supported_operations
2603 
2604 	NULL, // validate_resize
2605 	NULL, // validate_move
2606 	NULL, // validate_set_content_name
2607 	NULL, // validate_set_content_parameters
2608 	NULL, // validate_initialize
2609 
2610 	// shadow partition modification
2611 	NULL, // shadow_changed
2612 
2613 	// writing
2614 	NULL, // defragment
2615 	NULL, // repair
2616 	NULL, // resize
2617 	NULL, // move
2618 	NULL, // set_content_name
2619 	NULL, // set_content_parameters
2620 	NULL // initialize
2621 };
2622 
2623 
2624 status_t
2625 publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber, void *privateNode,
2626 	int type)
2627 {
2628 	return publish_vnode(volume, inodeNumber, privateNode, &sOverlayVnodeOps,
2629 		type, 0);
2630 }
2631 
2632 }	// namespace write_overlay
2633 
2634 using namespace write_overlay;
2635 
2636 module_info *modules[] = {
2637 	(module_info *)&sOverlayFileSystem,
2638 	NULL,
2639 };
2640