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