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
42namespace write_overlay {
43
44status_t publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber,
45	void *privateNode, int type);
46
47class OverlayInode;
48
49struct open_cookie {
50	OverlayInode *	node;
51	int				open_mode;
52	void *			super_cookie;
53};
54
55
56struct open_dir_cookie {
57	uint32			index;
58};
59
60
61struct 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
85struct write_buffer {
86	write_buffer *	next;
87	off_t			position;
88	size_t			length;
89	uint8			buffer[1];
90};
91
92
93class OverlayVolume {
94public:
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
103private:
104		fs_volume *			fVolume;
105		ino_t				fCurrentInodeNumber;
106};
107
108
109class OverlayInode {
110public:
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
194private:
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
231OverlayVolume::OverlayVolume(fs_volume *volume)
232	:	fVolume(volume),
233		fCurrentInodeNumber((ino_t)1 << 60)
234{
235}
236
237
238OverlayVolume::~OverlayVolume()
239{
240}
241
242
243//	#pragma mark OverlayInode
244
245
246OverlayInode::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
291OverlayInode::~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
320status_t
321OverlayInode::InitCheck()
322{
323	return B_OK;
324}
325
326
327void
328OverlayInode::SetSuperVnode(fs_vnode *superVnode)
329{
330	RecursiveLocker locker(fLock);
331	fSuperVnode = *superVnode;
332}
333
334
335void
336OverlayInode::SetInodeNumber(ino_t inodeNumber)
337{
338	RecursiveLocker locker(fLock);
339	fInodeNumber = inodeNumber;
340}
341
342
343void
344OverlayInode::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
361void
362OverlayInode::SetDataModified()
363{
364	fIsDataModified = true;
365	if (!fIsModified)
366		SetModified();
367}
368
369
370void
371OverlayInode::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
381void
382OverlayInode::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
391bool
392OverlayInode::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
408status_t
409OverlayInode::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
433status_t
434OverlayInode::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
467void
468OverlayInode::SetName(const char *name)
469{
470	RecursiveLocker locker(fLock);
471	fName = name;
472	if (!fIsModified)
473		SetModified();
474}
475
476
477status_t
478OverlayInode::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
497status_t
498OverlayInode::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
510status_t
511OverlayInode::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
555status_t
556OverlayInode::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
569status_t
570OverlayInode::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
641status_t
642OverlayInode::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
658status_t
659OverlayInode::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
678status_t
679OverlayInode::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
792status_t
793OverlayInode::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
915status_t
916OverlayInode::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
933status_t
934OverlayInode::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
943status_t
944OverlayInode::CreateDir(const char *name, int perms)
945{
946	return _CreateCommon(name, S_IFDIR, perms, NULL, NULL, false, 0);
947}
948
949
950status_t
951OverlayInode::RemoveDir(const char *name)
952{
953	return RemoveEntry(name, NULL);
954}
955
956
957status_t
958OverlayInode::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
985status_t
986OverlayInode::CloseDir(void *cookie)
987{
988	return B_OK;
989}
990
991
992status_t
993OverlayInode::FreeDirCookie(void *cookie)
994{
995	free(cookie);
996	return B_OK;
997}
998
999
1000status_t
1001OverlayInode::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
1030status_t
1031OverlayInode::RewindDir(void *cookie)
1032{
1033	open_dir_cookie *dirCookie = (open_dir_cookie *)cookie;
1034	dirCookie->index = 0;
1035	return B_OK;
1036}
1037
1038
1039status_t
1040OverlayInode::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
1053status_t
1054OverlayInode::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
1071status_t
1072OverlayInode::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
1106status_t
1107OverlayInode::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
1164void
1165OverlayInode::_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
1215status_t
1216OverlayInode::_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
1254status_t
1255OverlayInode::_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
1342close_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
1355status_t
1356OverlayInode::_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
1419close_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
1434status_t
1435OverlayInode::_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
1529static status_t
1530overlay_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
1552static status_t
1553overlay_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
1574static status_t
1575overlay_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
1600static status_t
1601overlay_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
1608static status_t
1609overlay_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
1616static bool
1617overlay_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
1634static status_t
1635overlay_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
1667static status_t
1668overlay_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
1700static status_t
1701overlay_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
1720static status_t
1721overlay_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
1728static status_t
1729overlay_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
1736static status_t
1737overlay_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
1744static status_t
1745overlay_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
1752static status_t
1753overlay_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
1760static status_t
1761overlay_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
1768static status_t
1769overlay_fsync(fs_volume *volume, fs_vnode *vnode)
1770{
1771	return B_OK;
1772}
1773
1774
1775static status_t
1776overlay_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
1785static status_t
1786overlay_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
1795static status_t
1796overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name,
1797	fs_vnode *target)
1798{
1799	return B_UNSUPPORTED;
1800}
1801
1802
1803static status_t
1804overlay_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
1811static status_t
1812overlay_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
1859static status_t
1860overlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
1861{
1862	// TODO: implement
1863	return B_OK;
1864}
1865
1866
1867static status_t
1868overlay_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
1875static status_t
1876overlay_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
1884static status_t
1885overlay_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
1894static status_t
1895overlay_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
1902static status_t
1903overlay_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
1910static status_t
1911overlay_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
1918static status_t
1919overlay_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
1928static status_t
1929overlay_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
1938static status_t
1939overlay_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
1947static status_t
1948overlay_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
1955static status_t
1956overlay_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
1963static status_t
1964overlay_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
1971static status_t
1972overlay_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
1979static status_t
1980overlay_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
1989static status_t
1990overlay_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
1997static status_t
1998overlay_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
2005static status_t
2006overlay_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
2013static status_t
2014overlay_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
2021static status_t
2022overlay_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
2031static status_t
2032overlay_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
2039static status_t
2040overlay_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
2049static status_t
2050overlay_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
2066static status_t
2067overlay_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
2075static status_t
2076overlay_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
2084static status_t
2085overlay_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
2094static status_t
2095overlay_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
2104static status_t
2105overlay_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
2114static status_t
2115overlay_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
2124static status_t
2125overlay_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
2175static status_t
2176overlay_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
2190static status_t
2191overlay_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
2199static 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
2285static status_t
2286overlay_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
2299static status_t
2300overlay_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
2323static status_t
2324overlay_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
2332static status_t
2333overlay_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
2342static status_t
2343overlay_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
2376static status_t
2377overlay_open_index_dir(fs_volume *volume, void **cookie)
2378{
2379	OVERLAY_VOLUME_CALL(open_index_dir, cookie)
2380	return B_UNSUPPORTED;
2381}
2382
2383
2384static status_t
2385overlay_close_index_dir(fs_volume *volume, void *cookie)
2386{
2387	OVERLAY_VOLUME_CALL(close_index_dir, cookie)
2388	return B_UNSUPPORTED;
2389}
2390
2391
2392static status_t
2393overlay_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
2400static status_t
2401overlay_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
2409static status_t
2410overlay_rewind_index_dir(fs_volume *volume, void *cookie)
2411{
2412	OVERLAY_VOLUME_CALL(rewind_index_dir, cookie)
2413	return B_UNSUPPORTED;
2414}
2415
2416
2417static status_t
2418overlay_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
2426static status_t
2427overlay_remove_index(fs_volume *volume, const char *name)
2428{
2429	OVERLAY_VOLUME_CALL(remove_index, name)
2430	return B_UNSUPPORTED;
2431}
2432
2433
2434static status_t
2435overlay_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
2442static status_t
2443overlay_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
2451static status_t
2452overlay_close_query(fs_volume *volume, void *cookie)
2453{
2454	OVERLAY_VOLUME_CALL(close_query, cookie)
2455	return B_UNSUPPORTED;
2456}
2457
2458
2459static status_t
2460overlay_free_query_cookie(fs_volume *volume, void *cookie)
2461{
2462	OVERLAY_VOLUME_CALL(free_query_cookie, cookie)
2463	return B_UNSUPPORTED;
2464}
2465
2466
2467static status_t
2468overlay_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
2476static status_t
2477overlay_rewind_query(fs_volume *volume, void *cookie)
2478{
2479	OVERLAY_VOLUME_CALL(rewind_query, cookie)
2480	return B_UNSUPPORTED;
2481}
2482
2483
2484static status_t
2485overlay_all_layers_mounted(fs_volume *volume)
2486{
2487	return B_OK;
2488}
2489
2490
2491static status_t
2492overlay_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
2511static status_t
2512overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode)
2513{
2514	delete (OverlayInode *)vnode->private_node;
2515	return B_OK;
2516}
2517
2518
2519static 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
2552static status_t
2553overlay_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
2566static status_t
2567overlay_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
2579static 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
2622status_t
2623publish_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
2632using namespace write_overlay;
2633
2634module_info *modules[] = {
2635	(module_info *)&sOverlayFileSystem,
2636	NULL,
2637};
2638