xref: /haiku/src/add-ons/kernel/file_systems/layers/write_overlay/write_overlay.cpp (revision a1163de83ea633463a79de234b8742ee106531b2)
1  /*
2   * Copyright 2009, Haiku Inc. All rights reserved.
3   * Distributed under the terms of the MIT License.
4   *
5   * Authors:
6   *		Michael Lotz <mmlr@mlotz.ch>
7   */
8  
9  #include <new>
10  #include <stdlib.h>
11  #include <string.h>
12  
13  #include <dirent.h>
14  
15  #include <util/kernel_cpp.h>
16  
17  #include <fs_cache.h>
18  #include <fs_info.h>
19  #include <fs_interface.h>
20  
21  #include <debug.h>
22  #include <KernelExport.h>
23  #include <NodeMonitor.h>
24  
25  
26  //#define TRACE_OVERLAY
27  #ifdef TRACE_OVERLAY
28  #define TRACE(x...)			dprintf("write_overlay: " x)
29  #define TRACE_VOLUME(x...)	dprintf("write_overlay: " x)
30  #define TRACE_ALWAYS(x...)	dprintf("write_overlay: " x)
31  #else
32  #define TRACE(x...)			/* nothing */
33  #define TRACE_VOLUME(x...)	/* nothing */
34  #define TRACE_ALWAYS(x...)	dprintf("write_overlay: " x)
35  #endif
36  
37  
38  namespace write_overlay {
39  
40  status_t publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber,
41  	void *privateNode, int type);
42  
43  class OverlayInode;
44  
45  struct open_cookie {
46  	int				open_mode;
47  	void *			super_cookie;
48  };
49  
50  
51  struct open_dir_cookie {
52  	uint32			index;
53  };
54  
55  
56  struct overlay_dirent {
57  	ino_t			inode_number;
58  	char *			name;
59  
60  	void			remove_and_dispose(fs_volume *volume, ino_t directoryInode)
61  					{
62  						notify_entry_removed(volume->id, directoryInode,
63  							name, inode_number);
64  						remove_vnode(volume, inode_number);
65  						free(name);
66  						free(this);
67  					}
68  };
69  
70  
71  struct write_buffer {
72  	write_buffer *	next;
73  	off_t			position;
74  	size_t			length;
75  	uint8			buffer[1];
76  };
77  
78  
79  class OverlayVolume {
80  public:
81  							OverlayVolume(fs_volume *volume);
82  							~OverlayVolume();
83  
84  		fs_volume *			Volume() { return fVolume; }
85  		fs_volume *			SuperVolume() { return fVolume->super_volume; }
86  
87  		ino_t				BuildInodeNumber() { return fCurrentInodeNumber++; }
88  
89  private:
90  		fs_volume *			fVolume;
91  		ino_t				fCurrentInodeNumber;
92  };
93  
94  
95  class OverlayInode {
96  public:
97  							OverlayInode(OverlayVolume *volume,
98  								fs_vnode *superVnode, ino_t inodeNumber,
99  								OverlayInode *parentDir = NULL,
100  								const char *name = NULL, mode_t mode = 0);
101  							~OverlayInode();
102  
103  		status_t			InitCheck();
104  
105  		bool				IsVirtual() { return fIsVirtual; }
106  
107  		fs_volume *			Volume() { return fVolume->Volume(); }
108  		fs_volume *			SuperVolume() { return fVolume->SuperVolume(); }
109  		fs_vnode *			SuperVnode() { return &fSuperVnode; }
110  		ino_t				InodeNumber() { return fInodeNumber; }
111  
112  		void				CreateCache();
113  
114  		void				SetParentDir(OverlayInode *parentDir);
115  		OverlayInode *		ParentDir() { return fParentDir; }
116  
117  		status_t			Lookup(const char *name, ino_t *inodeNumber);
118  		void				SetName(const char *name);
119  		status_t			GetName(char *buffer, size_t bufferSize);
120  
121  		status_t			ReadStat(struct stat *stat);
122  		status_t			WriteStat(const struct stat *stat, uint32 statMask);
123  
124  		status_t			Create(const char *name, int openMode, int perms,
125  								void **cookie, ino_t *newInodeNumber);
126  		status_t			Open(int openMode, void **cookie);
127  		status_t			Close(void *cookie);
128  		status_t			FreeCookie(void *cookie);
129  		status_t			Read(void *cookie, off_t position, void *buffer,
130  								size_t *length, bool readPages);
131  		status_t			Write(void *cookie, off_t position,
132  								const void *buffer, size_t *length);
133  		status_t			SetFlags(void *cookie, int flags);
134  
135  		status_t			CreateDir(const char *name, int perms);
136  		status_t			RemoveDir(const char *name);
137  		status_t			OpenDir(void **cookie);
138  		status_t			CloseDir(void *cookie);
139  		status_t			FreeDirCookie(void *cookie);
140  		status_t			ReadDir(void *cookie, struct dirent *buffer,
141  								size_t bufferSize, uint32 *num);
142  		status_t			RewindDir(void *cookie);
143  
144  		status_t			CreateSymlink(const char *name, const char *path,
145  								int mode);
146  		status_t			ReadSymlink(char *buffer, size_t *bufferSize);
147  
148  		status_t			AddEntry(overlay_dirent *entry);
149  		status_t			RemoveEntry(const char *name,
150  								overlay_dirent **entry);
151  
152  private:
153  		status_t			_PopulateDirents();
154  		status_t			_CreateCommon(const char *name, int type, int perms,
155  								ino_t *newInodeNumber, OverlayInode **node);
156  
157  		OverlayVolume *		fVolume;
158  		OverlayInode *		fParentDir;
159  		const char *		fName;
160  		fs_vnode			fSuperVnode;
161  		ino_t				fInodeNumber;
162  		write_buffer *		fWriteBuffers;
163  		off_t				fOriginalNodeLength;
164  		overlay_dirent **	fDirents;
165  		uint32				fDirentCount;
166  		struct stat			fStat;
167  		bool				fHasStat;
168  		bool				fHasDirents;
169  		bool				fIsVirtual;
170  		void *				fFileCache;
171  };
172  
173  
174  //	#pragma mark OverlayVolume
175  
176  
177  OverlayVolume::OverlayVolume(fs_volume *volume)
178  	:	fVolume(volume),
179  		fCurrentInodeNumber((ino_t)1 << 60)
180  {
181  }
182  
183  
184  OverlayVolume::~OverlayVolume()
185  {
186  }
187  
188  
189  //	#pragma mark OverlayInode
190  
191  
192  OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode,
193  	ino_t inodeNumber, OverlayInode *parentDir, const char *name, mode_t mode)
194  	:	fVolume(volume),
195  		fParentDir(parentDir),
196  		fName(name),
197  		fInodeNumber(inodeNumber),
198  		fWriteBuffers(NULL),
199  		fOriginalNodeLength(-1),
200  		fDirents(NULL),
201  		fDirentCount(0),
202  		fHasStat(false),
203  		fHasDirents(false),
204  		fIsVirtual(superVnode == NULL),
205  		fFileCache(NULL)
206  {
207  	TRACE("inode created %lld\n", fInodeNumber);
208  
209  	if (superVnode != NULL)
210  		fSuperVnode = *superVnode;
211  	else {
212  		fStat.st_dev = SuperVolume()->id;
213  		fStat.st_ino = fInodeNumber;
214  		fStat.st_mode = mode;
215  		fStat.st_nlink = 1;
216  		fStat.st_uid = 0;
217  		fStat.st_gid = 0;
218  		fStat.st_size = 0;
219  		fStat.st_rdev = 0;
220  		fStat.st_blksize = 1024;
221  		fStat.st_atime = fStat.st_mtime = fStat.st_ctime = fStat.st_crtime
222  			= time(NULL);
223  		fStat.st_type = 0;
224  		fHasStat = true;
225  	}
226  }
227  
228  
229  OverlayInode::~OverlayInode()
230  {
231  	TRACE("inode destroyed %lld\n", fInodeNumber);
232  	if (fFileCache != NULL)
233  		file_cache_delete(fFileCache);
234  
235  	write_buffer *element = fWriteBuffers;
236  	while (element) {
237  		write_buffer *next = element->next;
238  		free(element);
239  		element = next;
240  	}
241  
242  	for (uint32 i = 0; i < fDirentCount; i++)
243  		free(fDirents[i]);
244  	free(fDirents);
245  }
246  
247  
248  status_t
249  OverlayInode::InitCheck()
250  {
251  	return B_OK;
252  }
253  
254  
255  void
256  OverlayInode::CreateCache()
257  {
258  	if (!S_ISDIR(fStat.st_mode) && !S_ISLNK(fStat.st_mode)) {
259  		fFileCache = file_cache_create(fStat.st_dev, fStat.st_ino, 0);
260  		if (fFileCache != NULL)
261  			file_cache_disable(fFileCache);
262  	}
263  }
264  
265  
266  void
267  OverlayInode::SetParentDir(OverlayInode *parentDir)
268  {
269  	fParentDir = parentDir;
270  }
271  
272  
273  status_t
274  OverlayInode::Lookup(const char *name, ino_t *inodeNumber)
275  {
276  	if (!fHasDirents)
277  		_PopulateDirents();
278  
279  	for (uint32 i = 0; i < fDirentCount; i++) {
280  		if (strcmp(fDirents[i]->name, name) == 0) {
281  			*inodeNumber = fDirents[i]->inode_number;
282  
283  			OverlayInode *node = NULL;
284  			status_t result = get_vnode(Volume(), *inodeNumber,
285  				(void **)&node);
286  			if (result == B_OK && node != NULL)
287  				node->SetParentDir(this);
288  			return result;
289  		}
290  	}
291  
292  	return B_ENTRY_NOT_FOUND;
293  }
294  
295  
296  void
297  OverlayInode::SetName(const char *name)
298  {
299  	fName = name;
300  }
301  
302  
303  status_t
304  OverlayInode::GetName(char *buffer, size_t bufferSize)
305  {
306  	if (fName != NULL) {
307  		strlcpy(buffer, fName, bufferSize);
308  		return B_OK;
309  	}
310  
311  	if (fIsVirtual)
312  		return B_UNSUPPORTED;
313  
314  	if (fSuperVnode.ops->get_vnode_name == NULL)
315  		return B_UNSUPPORTED;
316  
317  	return fSuperVnode.ops->get_vnode_name(SuperVolume(), &fSuperVnode, buffer,
318  		bufferSize);
319  }
320  
321  
322  status_t
323  OverlayInode::ReadStat(struct stat *stat)
324  {
325  	if (!fHasStat) {
326  		if (fSuperVnode.ops->read_stat == NULL)
327  			return B_UNSUPPORTED;
328  
329  		status_t result = fSuperVnode.ops->read_stat(SuperVolume(),
330  			&fSuperVnode, &fStat);
331  		if (result != B_OK)
332  			return result;
333  
334  		fHasStat = true;
335  	}
336  
337  	if (stat == NULL)
338  		return B_OK;
339  
340  	memcpy(stat, &fStat, sizeof(struct stat));
341  	stat->st_blocks = (stat->st_size + stat->st_blksize - 1) / stat->st_blksize;
342  	return B_OK;
343  }
344  
345  
346  status_t
347  OverlayInode::WriteStat(const struct stat *stat, uint32 statMask)
348  {
349  	if (!fHasStat)
350  		ReadStat(NULL);
351  
352  	if (statMask & B_STAT_SIZE)
353  		fStat.st_size = stat->st_size;
354  
355  	if (statMask & B_STAT_MODE)
356  		fStat.st_mode = (fStat.st_mode & ~S_IUMSK) | (stat->st_mode & S_IUMSK);
357  	if (statMask & B_STAT_UID)
358  		fStat.st_uid = stat->st_uid;
359  	if (statMask & B_STAT_GID)
360  		fStat.st_gid = stat->st_gid;
361  
362  	if (statMask & B_STAT_MODIFICATION_TIME)
363  		fStat.st_mtime = stat->st_mtime;
364  	if (statMask & B_STAT_CREATION_TIME)
365  		fStat.st_crtime = stat->st_crtime;
366  
367  	if ((statMask & (B_STAT_MODE | B_STAT_UID | B_STAT_GID)) != 0
368  		&& (statMask & B_STAT_MODIFICATION_TIME) == 0) {
369  		fStat.st_mtime = time(NULL);
370  		statMask |= B_STAT_MODIFICATION_TIME;
371  	}
372  
373  	notify_stat_changed(SuperVolume()->id, fInodeNumber, statMask);
374  	return B_OK;
375  }
376  
377  
378  status_t
379  OverlayInode::Create(const char *name, int openMode, int perms, void **cookie,
380  	ino_t *newInodeNumber)
381  {
382  	OverlayInode *newNode = NULL;
383  	status_t result = _CreateCommon(name, S_IFREG, perms, newInodeNumber,
384  		&newNode);
385  	if (result != B_OK)
386  		return result;
387  
388  	return newNode->Open(openMode, cookie);
389  }
390  
391  
392  status_t
393  OverlayInode::Open(int openMode, void **_cookie)
394  {
395  	if (!fHasStat)
396  		ReadStat(NULL);
397  
398  	open_cookie *cookie = (open_cookie *)malloc(sizeof(open_cookie));
399  	if (cookie == NULL)
400  		return B_NO_MEMORY;
401  
402  	cookie->open_mode = openMode;
403  	*_cookie = cookie;
404  
405  	if (fIsVirtual) {
406  		if (openMode & O_TRUNC)
407  			fStat.st_size = 0;
408  
409  		return B_OK;
410  	}
411  
412  	if (fSuperVnode.ops->open == NULL)
413  		return B_UNSUPPORTED;
414  
415  	if (fOriginalNodeLength < 0) {
416  		struct stat stat;
417  		status_t result = fSuperVnode.ops->read_stat(SuperVolume(),
418  			&fSuperVnode, &stat);
419  		if (result != B_OK)
420  			return result;
421  
422  		fOriginalNodeLength = stat.st_size;
423  	}
424  
425  	if (openMode & O_TRUNC)
426  		fStat.st_size = 0;
427  
428  	openMode &= ~(O_RDWR | O_WRONLY | O_TRUNC | O_CREAT);
429  	status_t result = fSuperVnode.ops->open(SuperVolume(), &fSuperVnode,
430  		openMode, &cookie->super_cookie);
431  	if (result != B_OK) {
432  		free(cookie);
433  		return result;
434  	}
435  
436  	return B_OK;
437  }
438  
439  
440  status_t
441  OverlayInode::Close(void *_cookie)
442  {
443  	if (fIsVirtual)
444  		return B_OK;
445  
446  	open_cookie *cookie = (open_cookie *)_cookie;
447  	return fSuperVnode.ops->close(SuperVolume(), &fSuperVnode,
448  		cookie->super_cookie);
449  }
450  
451  
452  status_t
453  OverlayInode::FreeCookie(void *_cookie)
454  {
455  	status_t result = B_OK;
456  	open_cookie *cookie = (open_cookie *)_cookie;
457  	if (!fIsVirtual) {
458  		result = fSuperVnode.ops->free_cookie(SuperVolume(),
459  			&fSuperVnode, cookie->super_cookie);
460  	}
461  
462  	free(cookie);
463  	return result;
464  }
465  
466  
467  status_t
468  OverlayInode::Read(void *_cookie, off_t position, void *buffer, size_t *length,
469  	bool readPages)
470  {
471  	if (position >= fStat.st_size) {
472  		*length = 0;
473  		return B_OK;
474  	}
475  
476  	uint8 *pointer = (uint8 *)buffer;
477  	write_buffer *element = fWriteBuffers;
478  	size_t bytesLeft = MIN(fStat.st_size - position, *length);
479  	*length = bytesLeft;
480  
481  	void *superCookie = _cookie;
482  	if (!fIsVirtual && !readPages && _cookie != NULL)
483  		superCookie = ((open_cookie *)_cookie)->super_cookie;
484  
485  	while (bytesLeft > 0) {
486  		size_t gapSize = bytesLeft;
487  		if (element != NULL) {
488  			gapSize = MIN(bytesLeft, element->position > position ?
489  				element->position - position : 0);
490  		}
491  
492  		if (gapSize > 0 && !fIsVirtual && position < fOriginalNodeLength) {
493  			// there's a part missing between the read position and our
494  			// next position, fill the gap with original file content
495  			size_t readLength = MIN(fOriginalNodeLength - position, gapSize);
496  			status_t result = B_ERROR;
497  			if (readPages) {
498  				iovec vector;
499  				vector.iov_base = pointer;
500  				vector.iov_len = readLength;
501  
502  				result = fSuperVnode.ops->read_pages(SuperVolume(),
503  					&fSuperVnode, superCookie, position, &vector, 1,
504  					&readLength);
505  			} else {
506  				result = fSuperVnode.ops->read(SuperVolume(), &fSuperVnode,
507  					superCookie, position, pointer, &readLength);
508  			}
509  
510  			if (result != B_OK)
511  				return result;
512  
513  			pointer += readLength;
514  			position += readLength;
515  			bytesLeft -= readLength;
516  			gapSize -= readLength;
517  		}
518  
519  		if (gapSize > 0) {
520  			// there's a gap before our next position which we cannot
521  			// fill with original file content, zero it out
522  			memset(pointer, 0, gapSize);
523  			bytesLeft -= gapSize;
524  			position += gapSize;
525  			pointer += gapSize;
526  		}
527  
528  		// we've reached the end
529  		if (bytesLeft == 0 || element == NULL)
530  			break;
531  
532  		off_t elementEnd = element->position + element->length;
533  		if (elementEnd > position) {
534  			size_t copyLength = MIN(elementEnd - position, bytesLeft);
535  			memcpy(pointer, element->buffer + (position - element->position),
536  				copyLength);
537  
538  			bytesLeft -= copyLength;
539  			position += copyLength;
540  			pointer += copyLength;
541  		}
542  
543  		element = element->next;
544  	}
545  
546  	return B_OK;
547  }
548  
549  
550  status_t
551  OverlayInode::Write(void *_cookie, off_t position, const void *buffer,
552  	size_t *length)
553  {
554  	if (_cookie != NULL) {
555  		open_cookie *cookie = (open_cookie *)_cookie;
556  		if (cookie->open_mode & O_APPEND)
557  			position = fStat.st_size;
558  	}
559  
560  	// find insertion point
561  	write_buffer **link = &fWriteBuffers;
562  	write_buffer *other = fWriteBuffers;
563  	write_buffer *swallow = NULL;
564  	off_t newPosition = position;
565  	size_t newLength = *length;
566  	uint32 swallowCount = 0;
567  
568  	while (other) {
569  		off_t newEnd = newPosition + newLength;
570  		off_t otherEnd = other->position + other->length;
571  		if (otherEnd < newPosition) {
572  			// other is completely before us
573  			link = &other->next;
574  			other = other->next;
575  			continue;
576  		}
577  
578  		if (other->position > newEnd) {
579  			// other is completely past us
580  			break;
581  		}
582  
583  		swallowCount++;
584  		if (swallow == NULL)
585  			swallow = other;
586  
587  		if (other->position <= newPosition) {
588  			if (swallowCount == 1 && otherEnd >= newEnd) {
589  				// other chunk completely covers us, just copy
590  				memcpy(other->buffer + (newPosition - other->position),
591  					buffer, *length);
592  
593  				fStat.st_mtime = time(NULL);
594  				notify_stat_changed(SuperVolume()->id, fInodeNumber,
595  					B_STAT_MODIFICATION_TIME);
596  				return B_OK;
597  			}
598  
599  			newLength += newPosition - other->position;
600  			newPosition = other->position;
601  		}
602  
603  		if (otherEnd > newEnd)
604  			newLength += otherEnd - newEnd;
605  
606  		other = other->next;
607  	}
608  
609  	write_buffer *element = (write_buffer *)malloc(sizeof(write_buffer) - 1
610  		+ newLength);
611  	if (element == NULL)
612  		return B_NO_MEMORY;
613  
614  	element->next = *link;
615  	element->position = newPosition;
616  	element->length = newLength;
617  	*link = element;
618  
619  	bool sizeChanged = false;
620  	off_t newEnd = newPosition + newLength;
621  	if (newEnd > fStat.st_size) {
622  		fStat.st_size = newEnd;
623  		sizeChanged = true;
624  
625  		if (fFileCache)
626  			file_cache_set_size(fFileCache, newEnd);
627  	}
628  
629  	// populate the buffer with the existing chunks
630  	if (swallowCount > 0) {
631  		while (swallowCount-- > 0) {
632  			memcpy(element->buffer + (swallow->position - newPosition),
633  				swallow->buffer, swallow->length);
634  
635  			element->next = swallow->next;
636  			free(swallow);
637  			swallow = element->next;
638  		}
639  	}
640  
641  	memcpy(element->buffer + (position - newPosition), buffer, *length);
642  
643  	fStat.st_mtime = time(NULL);
644  	notify_stat_changed(SuperVolume()->id, fInodeNumber,
645  		B_STAT_MODIFICATION_TIME | (sizeChanged ? B_STAT_SIZE : 0));
646  	return B_OK;
647  }
648  
649  
650  status_t
651  OverlayInode::SetFlags(void *_cookie, int flags)
652  {
653  	// we can only handle O_APPEND, O_NONBLOCK is ignored.
654  	open_cookie *cookie = (open_cookie *)_cookie;
655  	cookie->open_mode = (cookie->open_mode & ~O_APPEND) | (flags & ~O_APPEND);
656  	return B_OK;
657  }
658  
659  
660  status_t
661  OverlayInode::CreateDir(const char *name, int perms)
662  {
663  	return _CreateCommon(name, S_IFDIR, perms, NULL, NULL);
664  }
665  
666  
667  status_t
668  OverlayInode::RemoveDir(const char *name)
669  {
670  	return RemoveEntry(name, NULL);
671  }
672  
673  
674  status_t
675  OverlayInode::OpenDir(void **cookie)
676  {
677  	if (!fHasDirents)
678  		_PopulateDirents();
679  
680  	open_dir_cookie *dirCookie = (open_dir_cookie *)malloc(
681  		sizeof(open_dir_cookie));
682  	if (dirCookie == NULL)
683  		return B_NO_MEMORY;
684  
685  	dirCookie->index = 0;
686  	*cookie = dirCookie;
687  	return B_OK;
688  }
689  
690  
691  status_t
692  OverlayInode::CloseDir(void *cookie)
693  {
694  	return B_OK;
695  }
696  
697  
698  status_t
699  OverlayInode::FreeDirCookie(void *cookie)
700  {
701  	free(cookie);
702  	return B_OK;
703  }
704  
705  
706  status_t
707  OverlayInode::ReadDir(void *cookie, struct dirent *buffer, size_t bufferSize,
708  	uint32 *num)
709  {
710  	open_dir_cookie *dirCookie = (open_dir_cookie *)cookie;
711  	if (dirCookie->index >= fDirentCount) {
712  		*num = 0;
713  		return B_OK;
714  	}
715  
716  	overlay_dirent *dirent = fDirents[dirCookie->index++];
717  	size_t nameLength = MIN(strlen(dirent->name),
718  		bufferSize - sizeof(struct dirent)) + 1;
719  
720  	buffer->d_dev = SuperVolume()->id;
721  	buffer->d_pdev = 0;
722  	buffer->d_ino = dirent->inode_number;
723  	buffer->d_pino = 0;
724  	buffer->d_reclen = sizeof(struct dirent) + nameLength;
725  	strlcpy(buffer->d_name, dirent->name, nameLength);
726  
727  	*num = 1;
728  	return B_OK;
729  }
730  
731  
732  status_t
733  OverlayInode::RewindDir(void *cookie)
734  {
735  	open_dir_cookie *dirCookie = (open_dir_cookie *)cookie;
736  	dirCookie->index = 0;
737  	return B_OK;
738  }
739  
740  
741  status_t
742  OverlayInode::CreateSymlink(const char *name, const char *path, int mode)
743  {
744  	OverlayInode *newNode = NULL;
745  	// TODO: find out why mode is ignored
746  	status_t result = _CreateCommon(name, S_IFLNK, 0777, NULL, &newNode);
747  	if (result != B_OK)
748  		return result;
749  
750  	size_t writeLength = strlen(path);
751  	return newNode->Write(NULL, 0, path, &writeLength);
752  }
753  
754  
755  status_t
756  OverlayInode::ReadSymlink(char *buffer, size_t *bufferSize)
757  {
758  	if (fIsVirtual) {
759  		if (!S_ISLNK(fStat.st_mode))
760  			return B_BAD_VALUE;
761  
762  		return Read(NULL, 0, buffer, bufferSize, false);
763  	}
764  
765  	if (fSuperVnode.ops->read_symlink == NULL)
766  		return B_UNSUPPORTED;
767  
768  	return fSuperVnode.ops->read_symlink(SuperVolume(), &fSuperVnode, buffer,
769  		bufferSize);
770  }
771  
772  
773  status_t
774  OverlayInode::AddEntry(overlay_dirent *entry)
775  {
776  	if (!fHasDirents)
777  		_PopulateDirents();
778  
779  	status_t result = RemoveEntry(entry->name, NULL);
780  	if (result != B_OK && result != B_ENTRY_NOT_FOUND)
781  		return B_FILE_EXISTS;
782  
783  	overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents,
784  		sizeof(overlay_dirent *) * (fDirentCount + 1));
785  	if (newDirents == NULL)
786  		return B_NO_MEMORY;
787  
788  	fDirents = newDirents;
789  	fDirents[fDirentCount++] = entry;
790  	return B_OK;
791  }
792  
793  
794  status_t
795  OverlayInode::RemoveEntry(const char *name, overlay_dirent **_entry)
796  {
797  	if (!fHasDirents)
798  		_PopulateDirents();
799  
800  	// TODO: we may not simply remove non-empty directories
801  	for (uint32 i = 0; i < fDirentCount; i++) {
802  		overlay_dirent *entry = fDirents[i];
803  		if (strcmp(entry->name, name) == 0) {
804  			for (uint32 j = i + 1; j < fDirentCount; j++)
805  				fDirents[j - 1] = fDirents[j];
806  			fDirentCount--;
807  
808  			if (_entry != NULL)
809  				*_entry = entry;
810  			else
811  				entry->remove_and_dispose(Volume(), fInodeNumber);
812  
813  			return B_OK;
814  		}
815  	}
816  
817  	return B_ENTRY_NOT_FOUND;
818  }
819  
820  
821  status_t
822  OverlayInode::_PopulateDirents()
823  {
824  	if (fHasDirents)
825  		return B_OK;
826  
827  	fDirents = (overlay_dirent **)malloc(sizeof(overlay_dirent *) * 2);
828  	if (fDirents == NULL)
829  		return B_NO_MEMORY;
830  
831  	const char *names[] = { ".", ".." };
832  	ino_t inodes[] = { fInodeNumber,
833  		fParentDir != NULL ? fParentDir->InodeNumber() : 0 };
834  	for (uint32 i = 0; i < 2; i++) {
835  		fDirents[i] = (overlay_dirent *)malloc(sizeof(overlay_dirent));
836  		if (fDirents[i] == NULL)
837  			return B_NO_MEMORY;
838  
839  		fDirents[i]->inode_number = inodes[i];
840  		fDirents[i]->name = strdup(names[i]);
841  		if (fDirents[i]->name == NULL) {
842  			free(fDirents[i]);
843  			return B_NO_MEMORY;
844  		}
845  
846  		fDirentCount++;
847  	}
848  
849  	fHasDirents = true;
850  	if (fIsVirtual || fSuperVnode.ops->open_dir == NULL
851  		|| fSuperVnode.ops->read_dir == NULL)
852  		return B_OK;
853  
854  	// we don't really care about errors from here on
855  	void *superCookie = NULL;
856  	status_t result = fSuperVnode.ops->open_dir(SuperVolume(),
857  		&fSuperVnode, &superCookie);
858  	if (result != B_OK)
859  		return B_OK;
860  
861  	size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH;
862  	struct dirent *buffer = (struct dirent *)malloc(bufferSize);
863  	if (buffer == NULL)
864  		goto close_dir;
865  
866  	while (true) {
867  		uint32 num = 1;
868  		result = fSuperVnode.ops->read_dir(SuperVolume(),
869  			&fSuperVnode, superCookie, buffer, bufferSize, &num);
870  		if (result != B_OK || num == 0)
871  			break;
872  
873  		overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents,
874  			sizeof(overlay_dirent *) * (fDirentCount + num));
875  		if (newDirents == NULL) {
876  			TRACE_ALWAYS("failed to allocate storage for dirents\n");
877  			break;
878  		}
879  
880  		fDirents = newDirents;
881  		struct dirent *dirent = buffer;
882  		for (uint32 i = 0; i < num; i++) {
883  			if (strcmp(dirent->d_name, ".") != 0
884  				&& strcmp(dirent->d_name, "..") != 0) {
885  				overlay_dirent *entry = (overlay_dirent *)malloc(
886  					sizeof(overlay_dirent));
887  				if (entry == NULL) {
888  					TRACE_ALWAYS("failed to allocate storage for dirent\n");
889  					break;
890  				}
891  
892  				entry->inode_number = dirent->d_ino;
893  				entry->name = strdup(dirent->d_name);
894  				if (entry->name == NULL) {
895  					TRACE_ALWAYS("failed to duplicate dirent entry name\n");
896  					free(entry);
897  					break;
898  				}
899  
900  				fDirents[fDirentCount++] = entry;
901  			}
902  
903  			dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen);
904  		}
905  	}
906  
907  	free(buffer);
908  
909  close_dir:
910  	if (fSuperVnode.ops->close_dir != NULL)
911  		fSuperVnode.ops->close_dir(SuperVolume(), &fSuperVnode, superCookie);
912  
913  	if (fSuperVnode.ops->free_dir_cookie != NULL) {
914  		fSuperVnode.ops->free_dir_cookie(SuperVolume(), &fSuperVnode,
915  			superCookie);
916  	}
917  
918  	return B_OK;
919  }
920  
921  
922  status_t
923  OverlayInode::_CreateCommon(const char *name, int type, int perms,
924  	ino_t *newInodeNumber, OverlayInode **_node)
925  {
926  	if (!fHasStat)
927  		ReadStat(NULL);
928  
929  	if (!S_ISDIR(fStat.st_mode))
930  		return B_NOT_A_DIRECTORY;
931  
932  	overlay_dirent *entry = (overlay_dirent *)malloc(sizeof(overlay_dirent));
933  	if (entry == NULL)
934  		return B_NO_MEMORY;
935  
936  	entry->name = strdup(name);
937  	if (entry->name == NULL) {
938  		free(entry);
939  		return B_NO_MEMORY;
940  	}
941  
942  	entry->inode_number = fVolume->BuildInodeNumber();
943  
944  	OverlayInode *node = new(std::nothrow) OverlayInode(fVolume, NULL,
945  		entry->inode_number, this, entry->name, (perms & S_IUMSK) | type);
946  	if (node == NULL) {
947  		free(entry->name);
948  		free(entry);
949  		return B_NO_MEMORY;
950  	}
951  
952  	status_t result = AddEntry(entry);
953  	if (result != B_OK) {
954  		free(entry->name);
955  		free(entry);
956  		delete node;
957  		return result;
958  	}
959  
960  	result = publish_overlay_vnode(fVolume->Volume(), entry->inode_number,
961  		node, type);
962  	if (result != B_OK) {
963  		RemoveEntry(entry->name, NULL);
964  		delete node;
965  		return result;
966  	}
967  
968  	node->CreateCache();
969  
970  	if (newInodeNumber != NULL)
971  		*newInodeNumber = entry->inode_number;
972  	if (_node != NULL)
973  		*_node = node;
974  
975  	notify_entry_created(SuperVolume()->id, fInodeNumber, entry->name,
976  		entry->inode_number);
977  
978  	return B_OK;
979  }
980  
981  
982  //	#pragma mark - vnode ops
983  
984  
985  #define OVERLAY_CALL(op, params...) \
986  	TRACE("relaying op: " #op "\n"); \
987  	OverlayInode *node = (OverlayInode *)vnode->private_node; \
988  	if (node->IsVirtual()) \
989  		return B_UNSUPPORTED; \
990  	fs_vnode *superVnode = node->SuperVnode(); \
991  	if (superVnode->ops->op != NULL) \
992  		return superVnode->ops->op(volume->super_volume, superVnode, params); \
993  	return B_UNSUPPORTED;
994  
995  
996  static status_t
997  overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
998  {
999  	TRACE("put_vnode\n");
1000  	OverlayInode *node = (OverlayInode *)vnode->private_node;
1001  	if (node->IsVirtual()) {
1002  		delete node;
1003  		return B_OK;
1004  	}
1005  
1006  	status_t result = B_OK;
1007  	fs_vnode *superVnode = node->SuperVnode();
1008  	if (superVnode->ops->put_vnode != NULL) {
1009  		result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
1010  			reenter);
1011  	}
1012  
1013  	delete node;
1014  	return result;
1015  }
1016  
1017  
1018  static status_t
1019  overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1020  {
1021  	TRACE("remove_vnode\n");
1022  	OverlayInode *node = (OverlayInode *)vnode->private_node;
1023  	if (node->IsVirtual()) {
1024  		delete node;
1025  		return B_OK;
1026  	}
1027  
1028  	status_t result = B_OK;
1029  	fs_vnode *superVnode = node->SuperVnode();
1030  	if (superVnode->ops->put_vnode != NULL) {
1031  		result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
1032  			reenter);
1033  	}
1034  
1035  	delete node;
1036  	return result;
1037  }
1038  
1039  
1040  static status_t
1041  overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode,
1042  	fs_volume *superVolume, fs_vnode *_superVnode)
1043  {
1044  	if (volume == superVolume) {
1045  		*_superVnode = *vnode;
1046  		return B_OK;
1047  	}
1048  
1049  	OverlayInode *node = (OverlayInode *)vnode->private_node;
1050  	if (node->IsVirtual()) {
1051  		*_superVnode = *vnode;
1052  		return B_OK;
1053  	}
1054  
1055  	fs_vnode *superVnode = node->SuperVnode();
1056  	if (superVnode->ops->get_super_vnode != NULL) {
1057  		return superVnode->ops->get_super_vnode(volume->super_volume,
1058  			superVnode, superVolume, _superVnode);
1059  	}
1060  
1061  	*_superVnode = *superVnode;
1062  	return B_OK;
1063  }
1064  
1065  
1066  static status_t
1067  overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id)
1068  {
1069  	TRACE("lookup: \"%s\"\n", name);
1070  	return ((OverlayInode *)vnode->private_node)->Lookup(name, id);
1071  }
1072  
1073  
1074  static status_t
1075  overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer,
1076  	size_t bufferSize)
1077  {
1078  	return ((OverlayInode *)vnode->private_node)->GetName(buffer, bufferSize);
1079  }
1080  
1081  
1082  static bool
1083  overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie)
1084  {
1085  	TRACE("relaying op: can_page\n");
1086  	OverlayInode *node = (OverlayInode *)vnode->private_node;
1087  	if (node->IsVirtual())
1088  		return false;
1089  
1090  	fs_vnode *superVnode = node->SuperVnode();
1091  	if (superVnode->ops->can_page != NULL) {
1092  		return superVnode->ops->can_page(volume->super_volume, superVnode,
1093  			cookie);
1094  	}
1095  
1096  	return false;
1097  }
1098  
1099  
1100  static status_t
1101  overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1102  	const iovec *vecs, size_t count, size_t *numBytes)
1103  {
1104  	OverlayInode *node = (OverlayInode *)vnode->private_node;
1105  	size_t bytesLeft = *numBytes;
1106  
1107  	for (size_t i = 0; i < count; i++) {
1108  		size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft);
1109  		status_t result = node->Read(cookie, pos, vecs[i].iov_base,
1110  			&transferBytes, true);
1111  		if (result != B_OK) {
1112  			*numBytes -= bytesLeft;
1113  			return result;
1114  		}
1115  
1116  		bytesLeft -= transferBytes;
1117  		if (bytesLeft == 0)
1118  			return B_OK;
1119  
1120  		if (transferBytes < vecs[i].iov_len) {
1121  			*numBytes -= bytesLeft;
1122  			return B_OK;
1123  		}
1124  
1125  		pos += transferBytes;
1126  	}
1127  
1128  	*numBytes = 0;
1129  	return B_OK;
1130  }
1131  
1132  
1133  static status_t
1134  overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1135  	const iovec *vecs, size_t count, size_t *numBytes)
1136  {
1137  	OverlayInode *node = (OverlayInode *)vnode->private_node;
1138  	size_t bytesLeft = *numBytes;
1139  
1140  	for (size_t i = 0; i < count; i++) {
1141  		size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft);
1142  		status_t result = node->Write(cookie, pos, vecs[i].iov_base,
1143  			&transferBytes);
1144  		if (result != B_OK) {
1145  			*numBytes -= bytesLeft;
1146  			return result;
1147  		}
1148  
1149  		bytesLeft -= transferBytes;
1150  		if (bytesLeft == 0)
1151  			return B_OK;
1152  
1153  		if (transferBytes < vecs[i].iov_len) {
1154  			*numBytes -= bytesLeft;
1155  			return B_OK;
1156  		}
1157  
1158  		pos += transferBytes;
1159  	}
1160  
1161  	*numBytes = 0;
1162  	return B_OK;
1163  }
1164  
1165  
1166  #if 0
1167  static status_t
1168  overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1169  	io_request *request)
1170  {
1171  	OVERLAY_CALL(io, cookie, request)
1172  }
1173  #endif
1174  
1175  
1176  static status_t
1177  overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1178  	io_request *request)
1179  {
1180  	OVERLAY_CALL(cancel_io, cookie, request)
1181  }
1182  
1183  
1184  static status_t
1185  overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset,
1186  	size_t size, struct file_io_vec *vecs, size_t *count)
1187  {
1188  	OVERLAY_CALL(get_file_map, offset, size, vecs, count)
1189  }
1190  
1191  
1192  static status_t
1193  overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, ulong op,
1194  	void *buffer, size_t length)
1195  {
1196  	OVERLAY_CALL(ioctl, cookie, op, buffer, length)
1197  }
1198  
1199  
1200  static status_t
1201  overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie,
1202  	int flags)
1203  {
1204  	return ((OverlayInode *)vnode->private_node)->SetFlags(cookie, flags);
1205  }
1206  
1207  
1208  static status_t
1209  overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1210  	selectsync *sync)
1211  {
1212  	OVERLAY_CALL(select, cookie, event, sync)
1213  }
1214  
1215  
1216  static status_t
1217  overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1218  	selectsync *sync)
1219  {
1220  	OVERLAY_CALL(deselect, cookie, event, sync)
1221  }
1222  
1223  
1224  static status_t
1225  overlay_fsync(fs_volume *volume, fs_vnode *vnode)
1226  {
1227  	return B_OK;
1228  }
1229  
1230  
1231  static status_t
1232  overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer,
1233  	size_t *bufferSize)
1234  {
1235  	TRACE("read_symlink\n");
1236  	return ((OverlayInode *)vnode->private_node)->ReadSymlink(buffer,
1237  		bufferSize);
1238  }
1239  
1240  
1241  static status_t
1242  overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name,
1243  	const char *path, int mode)
1244  {
1245  	TRACE("create_symlink: \"%s\" -> \"%s\"\n", name, path);
1246  	return ((OverlayInode *)vnode->private_node)->CreateSymlink(name, path,
1247  		mode);
1248  }
1249  
1250  
1251  static status_t
1252  overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name,
1253  	fs_vnode *target)
1254  {
1255  	return B_UNSUPPORTED;
1256  }
1257  
1258  
1259  static status_t
1260  overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name)
1261  {
1262  	TRACE("unlink: \"%s\"\n", name);
1263  	return ((OverlayInode *)vnode->private_node)->RemoveEntry(name, NULL);
1264  }
1265  
1266  
1267  static status_t
1268  overlay_rename(fs_volume *volume, fs_vnode *vnode,
1269  	const char *fromName, fs_vnode *toVnode, const char *toName)
1270  {
1271  	TRACE("rename: \"%s\" -> \"%s\"\n", fromName, toName);
1272  	OverlayInode *fromNode = (OverlayInode *)vnode->private_node;
1273  	OverlayInode *toNode = (OverlayInode *)toVnode->private_node;
1274  	overlay_dirent *entry = NULL;
1275  
1276  	status_t result = fromNode->RemoveEntry(fromName, &entry);
1277  	if (result != B_OK)
1278  		return result;
1279  
1280  	char *oldName = entry->name;
1281  	entry->name = strdup(toName);
1282  	if (entry->name == NULL) {
1283  		entry->name = oldName;
1284  		if (fromNode->AddEntry(entry) != B_OK)
1285  			entry->remove_and_dispose(volume, fromNode->InodeNumber());
1286  
1287  		return B_NO_MEMORY;
1288  	}
1289  
1290  	result = toNode->AddEntry(entry);
1291  	if (result != B_OK) {
1292  		free(entry->name);
1293  		entry->name = oldName;
1294  		if (fromNode->AddEntry(entry) != B_OK)
1295  			entry->remove_and_dispose(volume, fromNode->InodeNumber());
1296  
1297  		return result;
1298  	}
1299  
1300  	OverlayInode *node = NULL;
1301  	result = get_vnode(volume, entry->inode_number, (void **)&node);
1302  	if (result == B_OK && node != NULL) {
1303  		node->SetName(entry->name);
1304  		node->SetParentDir(toNode);
1305  		put_vnode(volume, entry->inode_number);
1306  	}
1307  
1308  	free(oldName);
1309  	notify_entry_moved(volume->id, fromNode->InodeNumber(), fromName,
1310  		toNode->InodeNumber(), toName, entry->inode_number);
1311  	return B_OK;
1312  }
1313  
1314  
1315  static status_t
1316  overlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
1317  {
1318  	// TODO: implement
1319  	return B_OK;
1320  }
1321  
1322  
1323  static status_t
1324  overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat)
1325  {
1326  	TRACE("read_stat\n");
1327  	return ((OverlayInode *)vnode->private_node)->ReadStat(stat);
1328  }
1329  
1330  
1331  static status_t
1332  overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat,
1333  	uint32 statMask)
1334  {
1335  	TRACE("write_stat\n");
1336  	return ((OverlayInode *)vnode->private_node)->WriteStat(stat, statMask);
1337  }
1338  
1339  
1340  static status_t
1341  overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name,
1342  	int openMode, int perms, void **cookie, ino_t *newVnodeID)
1343  {
1344  	TRACE("create: \"%s\"\n", name);
1345  	return ((OverlayInode *)vnode->private_node)->Create(name, openMode,
1346  		perms, cookie, newVnodeID);
1347  }
1348  
1349  
1350  static status_t
1351  overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie)
1352  {
1353  	TRACE("open\n");
1354  	return ((OverlayInode *)vnode->private_node)->Open(openMode, cookie);
1355  }
1356  
1357  
1358  static status_t
1359  overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie)
1360  {
1361  	TRACE("close\n");
1362  	return ((OverlayInode *)vnode->private_node)->Close(cookie);
1363  }
1364  
1365  
1366  static status_t
1367  overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1368  {
1369  	TRACE("free_cookie\n");
1370  	return ((OverlayInode *)vnode->private_node)->FreeCookie(cookie);
1371  }
1372  
1373  
1374  static status_t
1375  overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1376  	void *buffer, size_t *length)
1377  {
1378  	TRACE("read\n");
1379  	return ((OverlayInode *)vnode->private_node)->Read(cookie, pos, buffer,
1380  		length, false);
1381  }
1382  
1383  
1384  static status_t
1385  overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1386  	const void *buffer, size_t *length)
1387  {
1388  	TRACE("write\n");
1389  	return ((OverlayInode *)vnode->private_node)->Write(cookie, pos, buffer,
1390  		length);
1391  }
1392  
1393  
1394  static status_t
1395  overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name,
1396  	int perms)
1397  {
1398  	TRACE("create_dir: \"%s\"\n", name);
1399  	return ((OverlayInode *)vnode->private_node)->CreateDir(name, perms);
1400  }
1401  
1402  
1403  static status_t
1404  overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name)
1405  {
1406  	TRACE("remove_dir: \"%s\"\n", name);
1407  	return ((OverlayInode *)vnode->private_node)->RemoveDir(name);
1408  }
1409  
1410  
1411  static status_t
1412  overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
1413  {
1414  	TRACE("open_dir\n");
1415  	return ((OverlayInode *)vnode->private_node)->OpenDir(cookie);
1416  }
1417  
1418  
1419  static status_t
1420  overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1421  {
1422  	TRACE("close_dir\n");
1423  	return ((OverlayInode *)vnode->private_node)->CloseDir(cookie);
1424  }
1425  
1426  
1427  static status_t
1428  overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1429  {
1430  	TRACE("free_dir_cookie\n");
1431  	return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie);
1432  }
1433  
1434  
1435  static status_t
1436  overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
1437  	struct dirent *buffer, size_t bufferSize, uint32 *num)
1438  {
1439  	TRACE("read_dir\n");
1440  	return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer,
1441  		bufferSize, num);
1442  }
1443  
1444  
1445  static status_t
1446  overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1447  {
1448  	TRACE("rewind_dir\n");
1449  	return ((OverlayInode *)vnode->private_node)->RewindDir(cookie);
1450  }
1451  
1452  
1453  static status_t
1454  overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
1455  {
1456  	OVERLAY_CALL(open_attr_dir, cookie)
1457  }
1458  
1459  
1460  static status_t
1461  overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1462  {
1463  	OVERLAY_CALL(close_attr_dir, cookie)
1464  }
1465  
1466  
1467  static status_t
1468  overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1469  {
1470  	OVERLAY_CALL(free_attr_dir_cookie, cookie)
1471  }
1472  
1473  
1474  static status_t
1475  overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
1476  	struct dirent *buffer, size_t bufferSize, uint32 *num)
1477  {
1478  	OVERLAY_CALL(read_attr_dir, cookie, buffer, bufferSize, num)
1479  }
1480  
1481  
1482  static status_t
1483  overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1484  {
1485  	OVERLAY_CALL(rewind_attr_dir, cookie)
1486  }
1487  
1488  
1489  static status_t
1490  overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
1491  	uint32 type, int openMode, void **cookie)
1492  {
1493  	OVERLAY_CALL(create_attr, name, type, openMode, cookie)
1494  }
1495  
1496  
1497  static status_t
1498  overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
1499  	int openMode, void **cookie)
1500  {
1501  	OVERLAY_CALL(open_attr, name, openMode, cookie)
1502  }
1503  
1504  
1505  static status_t
1506  overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie)
1507  {
1508  	OVERLAY_CALL(close_attr, cookie)
1509  }
1510  
1511  
1512  static status_t
1513  overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1514  {
1515  	OVERLAY_CALL(free_attr_cookie, cookie)
1516  }
1517  
1518  
1519  static status_t
1520  overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1521  	void *buffer, size_t *length)
1522  {
1523  	OVERLAY_CALL(read_attr, cookie, pos, buffer, length)
1524  }
1525  
1526  
1527  static status_t
1528  overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1529  	const void *buffer, size_t *length)
1530  {
1531  	OVERLAY_CALL(write_attr, cookie, pos, buffer, length)
1532  }
1533  
1534  
1535  static status_t
1536  overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
1537  	struct stat *stat)
1538  {
1539  	OVERLAY_CALL(read_attr_stat, cookie, stat)
1540  }
1541  
1542  
1543  static status_t
1544  overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
1545  	const struct stat *stat, int statMask)
1546  {
1547  	OVERLAY_CALL(write_attr_stat, cookie, stat, statMask)
1548  }
1549  
1550  
1551  static status_t
1552  overlay_rename_attr(fs_volume *volume, fs_vnode *vnode,
1553  	const char *fromName, fs_vnode *toVnode, const char *toName)
1554  {
1555  	OVERLAY_CALL(rename_attr, fromName, toVnode, toName)
1556  }
1557  
1558  
1559  static status_t
1560  overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name)
1561  {
1562  	OVERLAY_CALL(remove_attr, name)
1563  }
1564  
1565  
1566  static status_t
1567  overlay_create_special_node(fs_volume *volume, fs_vnode *vnode,
1568  	const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags,
1569  	fs_vnode *_superVnode, ino_t *nodeID)
1570  {
1571  	OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, nodeID)
1572  }
1573  
1574  
1575  static fs_vnode_ops sOverlayVnodeOps = {
1576  	&overlay_lookup,
1577  	&overlay_get_vnode_name,
1578  
1579  	&overlay_put_vnode,
1580  	&overlay_remove_vnode,
1581  
1582  	&overlay_can_page,
1583  	&overlay_read_pages,
1584  	&overlay_write_pages,
1585  
1586  	// TODO: the io scheduler uses it when available but we may simply
1587  	// return B_UNSUPPORTED and I'm not sure it then falls back correctly
1588  	NULL, //&overlay_io,
1589  	&overlay_cancel_io,
1590  
1591  	&overlay_get_file_map,
1592  
1593  	/* common */
1594  	&overlay_ioctl,
1595  	&overlay_set_flags,
1596  	&overlay_select,
1597  	&overlay_deselect,
1598  	&overlay_fsync,
1599  
1600  	&overlay_read_symlink,
1601  	&overlay_create_symlink,
1602  	&overlay_link,
1603  	&overlay_unlink,
1604  	&overlay_rename,
1605  
1606  	&overlay_access,
1607  	&overlay_read_stat,
1608  	&overlay_write_stat,
1609  
1610  	/* file */
1611  	&overlay_create,
1612  	&overlay_open,
1613  	&overlay_close,
1614  	&overlay_free_cookie,
1615  	&overlay_read,
1616  	&overlay_write,
1617  
1618  	/* directory */
1619  	&overlay_create_dir,
1620  	&overlay_remove_dir,
1621  	&overlay_open_dir,
1622  	&overlay_close_dir,
1623  	&overlay_free_dir_cookie,
1624  	&overlay_read_dir,
1625  	&overlay_rewind_dir,
1626  
1627  	/* attribute directory operations */
1628  	&overlay_open_attr_dir,
1629  	&overlay_close_attr_dir,
1630  	&overlay_free_attr_dir_cookie,
1631  	&overlay_read_attr_dir,
1632  	&overlay_rewind_attr_dir,
1633  
1634  	/* attribute operations */
1635  	&overlay_create_attr,
1636  	&overlay_open_attr,
1637  	&overlay_close_attr,
1638  	&overlay_free_attr_cookie,
1639  	&overlay_read_attr,
1640  	&overlay_write_attr,
1641  
1642  	&overlay_read_attr_stat,
1643  	&overlay_write_attr_stat,
1644  	&overlay_rename_attr,
1645  	&overlay_remove_attr,
1646  
1647  	/* support for node and FS layers */
1648  	&overlay_create_special_node,
1649  	&overlay_get_super_vnode
1650  };
1651  
1652  
1653  //	#pragma mark - volume ops
1654  
1655  
1656  #define OVERLAY_VOLUME_CALL(op, params...) \
1657  	TRACE_VOLUME("relaying volume op: " #op "\n"); \
1658  	if (volume->super_volume->ops->op != NULL) \
1659  		return volume->super_volume->ops->op(volume->super_volume, params);
1660  
1661  
1662  static status_t
1663  overlay_unmount(fs_volume *volume)
1664  {
1665  	TRACE_VOLUME("relaying volume op: unmount\n");
1666  	if (volume->super_volume != NULL
1667  		&& volume->super_volume->ops != NULL
1668  		&& volume->super_volume->ops->unmount != NULL)
1669  		volume->super_volume->ops->unmount(volume->super_volume);
1670  
1671  	delete (OverlayVolume *)volume->private_volume;
1672  	return B_OK;
1673  }
1674  
1675  
1676  static status_t
1677  overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
1678  {
1679  	TRACE_VOLUME("relaying volume op: read_fs_info\n");
1680  	status_t result = B_UNSUPPORTED;
1681  	if (volume->super_volume->ops->read_fs_info != NULL) {
1682  		result = volume->super_volume->ops->read_fs_info(volume->super_volume,
1683  			info);
1684  		if (result != B_OK)
1685  			return result;
1686  
1687  		info->flags &= ~B_FS_IS_READONLY;
1688  
1689  		// TODO: maybe calculate based on available ram
1690  		off_t available = 1024 * 1024 * 100 / info->block_size;
1691  		info->total_blocks += available;
1692  		info->free_blocks += available;
1693  		return B_OK;
1694  	}
1695  
1696  	return B_UNSUPPORTED;
1697  }
1698  
1699  
1700  static status_t
1701  overlay_write_fs_info(fs_volume *volume, const struct fs_info *info,
1702  	uint32 mask)
1703  {
1704  	OVERLAY_VOLUME_CALL(write_fs_info, info, mask)
1705  	return B_UNSUPPORTED;
1706  }
1707  
1708  
1709  static status_t
1710  overlay_sync(fs_volume *volume)
1711  {
1712  	TRACE_VOLUME("relaying volume op: sync\n");
1713  	if (volume->super_volume->ops->sync != NULL)
1714  		return volume->super_volume->ops->sync(volume->super_volume);
1715  	return B_UNSUPPORTED;
1716  }
1717  
1718  
1719  static status_t
1720  overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type,
1721  	uint32 *_flags, bool reenter)
1722  {
1723  	TRACE_VOLUME("relaying volume op: get_vnode\n");
1724  	if (volume->super_volume->ops->get_vnode != NULL) {
1725  		status_t status = volume->super_volume->ops->get_vnode(
1726  			volume->super_volume, id, vnode, _type, _flags, reenter);
1727  		if (status != B_OK)
1728  			return status;
1729  
1730  		OverlayInode *node = new(std::nothrow) OverlayInode(
1731  			(OverlayVolume *)volume->private_volume, vnode, id);
1732  		if (node == NULL) {
1733  			vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
1734  			return B_NO_MEMORY;
1735  		}
1736  
1737  		status = node->InitCheck();
1738  		if (status != B_OK) {
1739  			vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
1740  			delete node;
1741  			return status;
1742  		}
1743  
1744  		vnode->private_node = node;
1745  		vnode->ops = &sOverlayVnodeOps;
1746  		return B_OK;
1747  	}
1748  
1749  	return B_UNSUPPORTED;
1750  }
1751  
1752  
1753  static status_t
1754  overlay_open_index_dir(fs_volume *volume, void **cookie)
1755  {
1756  	OVERLAY_VOLUME_CALL(open_index_dir, cookie)
1757  	return B_UNSUPPORTED;
1758  }
1759  
1760  
1761  static status_t
1762  overlay_close_index_dir(fs_volume *volume, void *cookie)
1763  {
1764  	OVERLAY_VOLUME_CALL(close_index_dir, cookie)
1765  	return B_UNSUPPORTED;
1766  }
1767  
1768  
1769  static status_t
1770  overlay_free_index_dir_cookie(fs_volume *volume, void *cookie)
1771  {
1772  	OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie)
1773  	return B_UNSUPPORTED;
1774  }
1775  
1776  
1777  static status_t
1778  overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer,
1779  	size_t bufferSize, uint32 *_num)
1780  {
1781  	OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num)
1782  	return B_UNSUPPORTED;
1783  }
1784  
1785  
1786  static status_t
1787  overlay_rewind_index_dir(fs_volume *volume, void *cookie)
1788  {
1789  	OVERLAY_VOLUME_CALL(rewind_index_dir, cookie)
1790  	return B_UNSUPPORTED;
1791  }
1792  
1793  
1794  static status_t
1795  overlay_create_index(fs_volume *volume, const char *name, uint32 type,
1796  	uint32 flags)
1797  {
1798  	OVERLAY_VOLUME_CALL(create_index, name, type, flags)
1799  	return B_UNSUPPORTED;
1800  }
1801  
1802  
1803  static status_t
1804  overlay_remove_index(fs_volume *volume, const char *name)
1805  {
1806  	OVERLAY_VOLUME_CALL(remove_index, name)
1807  	return B_UNSUPPORTED;
1808  }
1809  
1810  
1811  static status_t
1812  overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat)
1813  {
1814  	OVERLAY_VOLUME_CALL(read_index_stat, name, stat)
1815  	return B_UNSUPPORTED;
1816  }
1817  
1818  
1819  static status_t
1820  overlay_open_query(fs_volume *volume, const char *query, uint32 flags,
1821  	port_id port, uint32 token, void **_cookie)
1822  {
1823  	OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie)
1824  	return B_UNSUPPORTED;
1825  }
1826  
1827  
1828  static status_t
1829  overlay_close_query(fs_volume *volume, void *cookie)
1830  {
1831  	OVERLAY_VOLUME_CALL(close_query, cookie)
1832  	return B_UNSUPPORTED;
1833  }
1834  
1835  
1836  static status_t
1837  overlay_free_query_cookie(fs_volume *volume, void *cookie)
1838  {
1839  	OVERLAY_VOLUME_CALL(free_query_cookie, cookie)
1840  	return B_UNSUPPORTED;
1841  }
1842  
1843  
1844  static status_t
1845  overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer,
1846  	size_t bufferSize, uint32 *_num)
1847  {
1848  	OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num)
1849  	return B_UNSUPPORTED;
1850  }
1851  
1852  
1853  static status_t
1854  overlay_rewind_query(fs_volume *volume, void *cookie)
1855  {
1856  	OVERLAY_VOLUME_CALL(rewind_query, cookie)
1857  	return B_UNSUPPORTED;
1858  }
1859  
1860  
1861  static status_t
1862  overlay_all_layers_mounted(fs_volume *volume)
1863  {
1864  	return B_OK;
1865  }
1866  
1867  
1868  static status_t
1869  overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode)
1870  {
1871  	OverlayInode *node = new(std::nothrow) OverlayInode(
1872  		(OverlayVolume *)volume->private_volume, vnode, id);
1873  	if (node == NULL)
1874  		return B_NO_MEMORY;
1875  
1876  	status_t status = node->InitCheck();
1877  	if (status != B_OK) {
1878  		delete node;
1879  		return status;
1880  	}
1881  
1882  	vnode->private_node = node;
1883  	vnode->ops = &sOverlayVnodeOps;
1884  	return B_OK;
1885  }
1886  
1887  
1888  static status_t
1889  overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode)
1890  {
1891  	delete (OverlayInode *)vnode;
1892  	return B_OK;
1893  }
1894  
1895  
1896  static fs_volume_ops sOverlayVolumeOps = {
1897  	&overlay_unmount,
1898  
1899  	&overlay_read_fs_info,
1900  	&overlay_write_fs_info,
1901  	&overlay_sync,
1902  
1903  	&overlay_get_vnode,
1904  	&overlay_open_index_dir,
1905  	&overlay_close_index_dir,
1906  	&overlay_free_index_dir_cookie,
1907  	&overlay_read_index_dir,
1908  	&overlay_rewind_index_dir,
1909  
1910  	&overlay_create_index,
1911  	&overlay_remove_index,
1912  	&overlay_read_index_stat,
1913  
1914  	&overlay_open_query,
1915  	&overlay_close_query,
1916  	&overlay_free_query_cookie,
1917  	&overlay_read_query,
1918  	&overlay_rewind_query,
1919  
1920  	&overlay_all_layers_mounted,
1921  	&overlay_create_sub_vnode,
1922  	&overlay_delete_sub_vnode
1923  };
1924  
1925  
1926  //	#pragma mark - filesystem module
1927  
1928  
1929  static status_t
1930  overlay_mount(fs_volume *volume, const char *device, uint32 flags,
1931  	const char *args, ino_t *rootID)
1932  {
1933  	TRACE_VOLUME("mounting write overlay\n");
1934  	volume->private_volume = new(std::nothrow) OverlayVolume(volume);
1935  	if (volume->private_volume == NULL)
1936  		return B_NO_MEMORY;
1937  
1938  	volume->ops = &sOverlayVolumeOps;
1939  	return B_OK;
1940  }
1941  
1942  
1943  static status_t
1944  overlay_std_ops(int32 op, ...)
1945  {
1946  	switch (op) {
1947  		case B_MODULE_INIT:
1948  		case B_MODULE_UNINIT:
1949  			return B_OK;
1950  		default:
1951  			return B_ERROR;
1952  	}
1953  }
1954  
1955  
1956  static file_system_module_info sOverlayFileSystem = {
1957  	{
1958  		"file_systems/write_overlay"B_CURRENT_FS_API_VERSION,
1959  		0,
1960  		overlay_std_ops,
1961  	},
1962  
1963  	"write_overlay",				// short_name
1964  	"Write Overlay File System",	// pretty_name
1965  	0,								// DDM flags
1966  
1967  	// scanning
1968  	NULL, // identify_partition
1969  	NULL, // scan_partition
1970  	NULL, // free_identify_partition_cookie
1971  	NULL, // free_partition_content_cookie
1972  
1973  	// general operations
1974  	&overlay_mount,
1975  
1976  	// capability querying
1977  	NULL, // get_supported_operations
1978  
1979  	NULL, // validate_resize
1980  	NULL, // validate_move
1981  	NULL, // validate_set_content_name
1982  	NULL, // validate_set_content_parameters
1983  	NULL, // validate_initialize
1984  
1985  	// shadow partition modification
1986  	NULL, // shadow_changed
1987  
1988  	// writing
1989  	NULL, // defragment
1990  	NULL, // repair
1991  	NULL, // resize
1992  	NULL, // move
1993  	NULL, // set_content_name
1994  	NULL, // set_content_parameters
1995  	NULL // initialize
1996  };
1997  
1998  
1999  status_t
2000  publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber, void *privateNode,
2001  	int type)
2002  {
2003  	return publish_vnode(volume, inodeNumber, privateNode, &sOverlayVnodeOps,
2004  		type, 0);
2005  }
2006  
2007  }	// namespace write_overlay
2008  
2009  using namespace write_overlay;
2010  
2011  module_info *modules[] = {
2012  	(module_info *)&sOverlayFileSystem,
2013  	NULL,
2014  };
2015