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