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