3rdparty/licenseReport: Add seperate LGPL checks
[haiku.git] / src / add-ons / kernel / file_systems / layers / write_overlay / write_overlay.cpp
blob93078a8c51906d87699c5287654177efc8f8a372
1 /*
2 * Copyright 2009-2016, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 */
9 #include <new>
10 #include <stdlib.h>
11 #include <string.h>
13 #include <dirent.h>
15 #include <util/kernel_cpp.h>
16 #include <util/AutoLock.h>
18 #include <fs_cache.h>
19 #include <fs_info.h>
20 #include <fs_interface.h>
21 #include <io_requests.h>
23 #include <debug.h>
24 #include <KernelExport.h>
25 #include <NodeMonitor.h>
27 #include "IORequest.h"
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
42 namespace write_overlay {
44 status_t publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber,
45 void *privateNode, int type);
47 class OverlayInode;
49 struct open_cookie {
50 OverlayInode * node;
51 int open_mode;
52 void * super_cookie;
56 struct open_dir_cookie {
57 uint32 index;
61 struct overlay_dirent {
62 ino_t inode_number;
63 char * name;
64 OverlayInode * node; // only for attributes
66 void remove_and_dispose(fs_volume *volume, ino_t directoryInode)
68 notify_entry_removed(volume->id, directoryInode,
69 name, inode_number);
70 remove_vnode(volume, inode_number);
71 free(name);
72 free(this);
75 void dispose_attribute(fs_volume *volume, ino_t fileInode)
77 notify_attribute_changed(volume->id, -1, fileInode,
78 name, B_ATTR_REMOVED);
79 free(name);
80 free(this);
85 struct write_buffer {
86 write_buffer * next;
87 off_t position;
88 size_t length;
89 uint8 buffer[1];
93 class OverlayVolume {
94 public:
95 OverlayVolume(fs_volume *volume);
96 ~OverlayVolume();
98 fs_volume * Volume() { return fVolume; }
99 fs_volume * SuperVolume() { return fVolume->super_volume; }
101 ino_t BuildInodeNumber() { return fCurrentInodeNumber++; }
103 private:
104 fs_volume * fVolume;
105 ino_t fCurrentInodeNumber;
109 class OverlayInode {
110 public:
111 OverlayInode(OverlayVolume *volume,
112 fs_vnode *superVnode, ino_t inodeNumber,
113 OverlayInode *parentDir = NULL,
114 const char *name = NULL, mode_t mode = 0,
115 bool attribute = false,
116 type_code attributeType = 0);
117 ~OverlayInode();
119 status_t InitCheck();
121 bool Lock() { return recursive_lock_lock(&fLock) == B_OK; }
122 void Unlock() { recursive_lock_unlock(&fLock); }
124 bool IsVirtual() { return fIsVirtual; }
125 bool IsModified() { return fIsModified; }
126 bool IsDataModified() { return fIsDataModified; }
127 bool IsAttribute() { return fIsAttribute; }
129 fs_volume * Volume() { return fVolume->Volume(); }
130 fs_volume * SuperVolume() { return fVolume->SuperVolume(); }
132 void SetSuperVnode(fs_vnode *superVnode);
133 fs_vnode * SuperVnode() { return &fSuperVnode; }
135 void SetInodeNumber(ino_t inodeNumber);
136 ino_t InodeNumber() { return fInodeNumber; }
138 void SetModified();
139 void SetDataModified();
140 void CreateCache();
142 void SetParentDir(OverlayInode *parentDir);
143 OverlayInode * ParentDir() { return fParentDir; }
145 bool IsNonEmptyDirectory();
147 status_t Lookup(const char *name, ino_t *inodeNumber);
148 status_t LookupAttribute(const char *name,
149 OverlayInode **node);
151 void SetName(const char *name);
152 status_t GetName(char *buffer, size_t bufferSize);
154 status_t ReadStat(struct stat *stat);
155 status_t WriteStat(const struct stat *stat, uint32 statMask);
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);
171 status_t SynchronousIO(void *cookie, IORequest *request);
173 status_t SetFlags(void *cookie, int flags);
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);
185 status_t CreateSymlink(const char *name, const char *path,
186 int mode);
187 status_t ReadSymlink(char *buffer, size_t *bufferSize);
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);
194 private:
195 void _TrimBuffers();
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);
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;
228 // #pragma mark OverlayVolume
231 OverlayVolume::OverlayVolume(fs_volume *volume)
232 : fVolume(volume),
233 fCurrentInodeNumber((ino_t)1 << 60)
238 OverlayVolume::~OverlayVolume()
243 // #pragma mark OverlayInode
246 OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode,
247 ino_t inodeNumber, OverlayInode *parentDir, const char *name, mode_t mode,
248 bool attribute, type_code attributeType)
249 : fVolume(volume),
250 fParentDir(parentDir),
251 fName(name),
252 fInodeNumber(inodeNumber),
253 fWriteBuffers(NULL),
254 fOriginalNodeLength(-1),
255 fDirents(NULL),
256 fDirentCount(0),
257 fAttributeDirents(NULL),
258 fAttributeDirentCount(0),
259 fHasStat(false),
260 fHasDirents(false),
261 fHasAttributeDirents(false),
262 fIsVirtual(superVnode == NULL),
263 fIsAttribute(attribute),
264 fIsModified(false),
265 fIsDataModified(false),
266 fFileCache(NULL)
268 TRACE("inode created %" B_PRIdINO "\n", fInodeNumber);
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;
291 OverlayInode::~OverlayInode()
293 TRACE("inode destroyed %" B_PRIdINO "\n", fInodeNumber);
294 if (fFileCache != NULL)
295 file_cache_delete(fFileCache);
297 write_buffer *element = fWriteBuffers;
298 while (element) {
299 write_buffer *next = element->next;
300 free(element);
301 element = next;
304 for (uint32 i = 0; i < fDirentCount; i++) {
305 free(fDirents[i]->name);
306 free(fDirents[i]);
308 free(fDirents);
310 for (uint32 i = 0; i < fAttributeDirentCount; i++) {
311 free(fAttributeDirents[i]->name);
312 free(fAttributeDirents[i]);
314 free(fAttributeDirents);
316 recursive_lock_destroy(&fLock);
320 status_t
321 OverlayInode::InitCheck()
323 return B_OK;
327 void
328 OverlayInode::SetSuperVnode(fs_vnode *superVnode)
330 RecursiveLocker locker(fLock);
331 fSuperVnode = *superVnode;
335 void
336 OverlayInode::SetInodeNumber(ino_t inodeNumber)
338 RecursiveLocker locker(fLock);
339 fInodeNumber = inodeNumber;
343 void
344 OverlayInode::SetModified()
346 if (fIsAttribute) {
347 fIsModified = true;
348 return;
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;
361 void
362 OverlayInode::SetDataModified()
364 fIsDataModified = true;
365 if (!fIsModified)
366 SetModified();
370 void
371 OverlayInode::CreateCache()
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);
381 void
382 OverlayInode::SetParentDir(OverlayInode *parentDir)
384 RecursiveLocker locker(fLock);
385 fParentDir = parentDir;
386 if (fHasDirents && fDirentCount >= 2)
387 fDirents[1]->inode_number = parentDir->InodeNumber();
391 bool
392 OverlayInode::IsNonEmptyDirectory()
394 RecursiveLocker locker(fLock);
395 if (!fHasStat)
396 _PopulateStat();
398 if (!S_ISDIR(fStat.st_mode))
399 return false;
401 if (!fHasDirents)
402 _PopulateDirents();
404 return fDirentCount > 2; // accounting for "." and ".." entries
408 status_t
409 OverlayInode::Lookup(const char *name, ino_t *inodeNumber)
411 RecursiveLocker locker(fLock);
412 if (!fHasDirents)
413 _PopulateDirents();
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();
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;
429 return B_ENTRY_NOT_FOUND;
433 status_t
434 OverlayInode::LookupAttribute(const char *name, OverlayInode **node)
436 RecursiveLocker locker(fLock);
437 if (!fHasAttributeDirents)
438 _PopulateAttributeDirents();
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;
449 status_t result = newNode->InitCheck();
450 if (result != B_OK) {
451 delete newNode;
452 return result;
455 dirent->node = newNode;
458 *node = dirent->node;
459 return B_OK;
463 return B_ENTRY_NOT_FOUND;
467 void
468 OverlayInode::SetName(const char *name)
470 RecursiveLocker locker(fLock);
471 fName = name;
472 if (!fIsModified)
473 SetModified();
477 status_t
478 OverlayInode::GetName(char *buffer, size_t bufferSize)
480 RecursiveLocker locker(fLock);
481 if (fName != NULL) {
482 strlcpy(buffer, fName, bufferSize);
483 return B_OK;
486 if (fIsVirtual || fIsAttribute)
487 return B_UNSUPPORTED;
489 if (fSuperVnode.ops->get_vnode_name == NULL)
490 return B_UNSUPPORTED;
492 return fSuperVnode.ops->get_vnode_name(SuperVolume(), &fSuperVnode, buffer,
493 bufferSize);
497 status_t
498 OverlayInode::ReadStat(struct stat *stat)
500 RecursiveLocker locker(fLock);
501 if (!fHasStat)
502 _PopulateStat();
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;
510 status_t
511 OverlayInode::WriteStat(const struct stat *stat, uint32 statMask)
513 if (fIsAttribute)
514 return B_UNSUPPORTED;
516 RecursiveLocker locker(fLock);
517 if (!fHasStat)
518 _PopulateStat();
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();
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;
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;
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;
547 if (!fIsModified)
548 SetModified();
550 notify_stat_changed(SuperVolume()->id, -1, fInodeNumber, statMask);
551 return B_OK;
555 status_t
556 OverlayInode::Create(const char *name, int openMode, int perms, void **cookie,
557 ino_t *newInodeNumber, bool attribute, type_code attributeType)
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;
565 return newNode->Open(openMode, cookie);
569 status_t
570 OverlayInode::Open(int openMode, void **_cookie)
572 RecursiveLocker locker(fLock);
573 if (!fHasStat)
574 _PopulateStat();
576 open_cookie *cookie = (open_cookie *)malloc(sizeof(open_cookie));
577 if (cookie == NULL)
578 return B_NO_MEMORY;
580 cookie->open_mode = openMode;
581 cookie->node = this;
582 *_cookie = cookie;
584 if (fIsVirtual) {
585 if (openMode & O_TRUNC) {
586 fStat.st_size = 0;
587 _TrimBuffers();
590 return B_OK;
593 if ((fIsAttribute && fSuperVnode.ops->open_attr == NULL)
594 || (!fIsAttribute && fSuperVnode.ops->open == NULL))
595 return B_UNSUPPORTED;
597 if (openMode & O_TRUNC) {
598 if (fStat.st_size != 0) {
599 fStat.st_size = 0;
600 _TrimBuffers();
601 if (!fIsDataModified)
602 SetDataModified();
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);
616 if (result != B_OK) {
617 free(cookie);
618 return result;
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);
631 if (result != B_OK)
632 return result;
634 fOriginalNodeLength = stat.st_size;
637 return B_OK;
641 status_t
642 OverlayInode::Close(void *_cookie)
644 if (fIsVirtual)
645 return B_OK;
647 open_cookie *cookie = (open_cookie *)_cookie;
648 if (fIsAttribute) {
649 return fSuperVnode.ops->close_attr(SuperVolume(), &fSuperVnode,
650 cookie->super_cookie);
653 return fSuperVnode.ops->close(SuperVolume(), &fSuperVnode,
654 cookie->super_cookie);
658 status_t
659 OverlayInode::FreeCookie(void *_cookie)
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);
673 free(cookie);
674 return result;
678 status_t
679 OverlayInode::Read(void *_cookie, off_t position, void *buffer, size_t *length,
680 bool readPages, IORequest *ioRequest)
682 RecursiveLocker locker(fLock);
683 if (position >= fStat.st_size) {
684 *length = 0;
685 return B_OK;
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;
693 void *superCookie = _cookie;
694 if (!fIsVirtual && !readPages && _cookie != NULL)
695 superCookie = ((open_cookie *)_cookie)->super_cookie;
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);
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;
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;
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;
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);
743 if (result != B_OK)
744 return result;
746 pointer += readLength;
747 position += readLength;
748 bytesLeft -= readLength;
749 gapSize -= readLength;
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);
760 bytesLeft -= gapSize;
761 position += gapSize;
762 pointer += gapSize;
765 // we've reached the end
766 if (bytesLeft == 0 || element == NULL)
767 break;
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);
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
780 memcpy(pointer, source, copyLength);
782 bytesLeft -= copyLength;
783 position += copyLength;
784 pointer += copyLength;
787 element = element->next;
790 return B_OK;
794 status_t
795 OverlayInode::Write(void *_cookie, off_t position, const void *buffer,
796 size_t length, IORequest *ioRequest)
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;
805 if (!fIsDataModified)
806 SetDataModified();
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;
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;
826 if (other->position > newEnd) {
827 // other is completely past us
828 break;
831 swallowCount++;
832 if (swallow == NULL)
833 swallow = other;
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
842 memcpy(target, buffer, length);
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);
852 return B_OK;
855 newLength += newPosition - other->position;
856 newPosition = other->position;
859 if (otherEnd > newEnd)
860 newLength += otherEnd - newEnd;
862 other = other->next;
865 write_buffer *element = (write_buffer *)malloc(sizeof(write_buffer) - 1
866 + newLength);
867 if (element == NULL)
868 return B_NO_MEMORY;
870 element->next = *link;
871 element->position = newPosition;
872 element->length = newLength;
873 *link = element;
875 bool sizeChanged = false;
876 off_t newEnd = newPosition + newLength;
877 if (newEnd > fStat.st_size) {
878 fStat.st_size = newEnd;
879 sizeChanged = true;
881 if (fFileCache)
882 file_cache_set_size(fFileCache, newEnd);
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);
891 element->next = swallow->next;
892 free(swallow);
893 swallow = element->next;
897 void *target = element->buffer + (position - newPosition);
898 if (ioRequest != NULL)
899 ioRequest->CopyData(0, target, length);
900 else
901 memcpy(target, buffer, length);
903 fStat.st_mtime = time(NULL);
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));
913 return B_OK;
917 status_t
918 OverlayInode::SynchronousIO(void *cookie, IORequest *request)
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);
927 if (result == B_OK)
928 request->SetTransferredBytes(false, length);
930 request->SetStatusAndNotify(result);
931 return result;
935 status_t
936 OverlayInode::SetFlags(void *_cookie, int flags)
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;
945 status_t
946 OverlayInode::CreateDir(const char *name, int perms)
948 return _CreateCommon(name, S_IFDIR, perms, NULL, NULL, false, 0);
952 status_t
953 OverlayInode::RemoveDir(const char *name)
955 return RemoveEntry(name, NULL);
959 status_t
960 OverlayInode::OpenDir(void **cookie, bool attribute)
962 RecursiveLocker locker(fLock);
963 if (!attribute) {
964 if (!fHasStat)
965 _PopulateStat();
967 if (!S_ISDIR(fStat.st_mode))
968 return B_NOT_A_DIRECTORY;
971 if (!attribute && !fHasDirents)
972 _PopulateDirents();
973 else if (attribute && !fHasAttributeDirents)
974 _PopulateAttributeDirents();
976 open_dir_cookie *dirCookie = (open_dir_cookie *)malloc(
977 sizeof(open_dir_cookie));
978 if (dirCookie == NULL)
979 return B_NO_MEMORY;
981 dirCookie->index = 0;
982 *cookie = dirCookie;
983 return B_OK;
987 status_t
988 OverlayInode::CloseDir(void *cookie)
990 return B_OK;
994 status_t
995 OverlayInode::FreeDirCookie(void *cookie)
997 free(cookie);
998 return B_OK;
1002 status_t
1003 OverlayInode::ReadDir(void *cookie, struct dirent *buffer, size_t bufferSize,
1004 uint32 *num, bool attribute)
1006 RecursiveLocker locker(fLock);
1007 uint32 direntCount = attribute ? fAttributeDirentCount : fDirentCount;
1008 overlay_dirent **dirents = attribute ? fAttributeDirents : fDirents;
1010 open_dir_cookie *dirCookie = (open_dir_cookie *)cookie;
1011 if (dirCookie->index >= direntCount) {
1012 *num = 0;
1013 return B_OK;
1016 overlay_dirent *dirent = dirents[dirCookie->index++];
1017 size_t nameLength = MIN(strlen(dirent->name),
1018 bufferSize - sizeof(struct dirent)) + 1;
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);
1027 *num = 1;
1028 return B_OK;
1032 status_t
1033 OverlayInode::RewindDir(void *cookie)
1035 open_dir_cookie *dirCookie = (open_dir_cookie *)cookie;
1036 dirCookie->index = 0;
1037 return B_OK;
1041 status_t
1042 OverlayInode::CreateSymlink(const char *name, const char *path, int mode)
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;
1051 return newNode->Write(NULL, 0, path, strlen(path), NULL);
1055 status_t
1056 OverlayInode::ReadSymlink(char *buffer, size_t *bufferSize)
1058 if (fIsVirtual) {
1059 if (!S_ISLNK(fStat.st_mode))
1060 return B_BAD_VALUE;
1062 return Read(NULL, 0, buffer, bufferSize, false, NULL);
1065 if (fSuperVnode.ops->read_symlink == NULL)
1066 return B_UNSUPPORTED;
1068 return fSuperVnode.ops->read_symlink(SuperVolume(), &fSuperVnode, buffer,
1069 bufferSize);
1073 status_t
1074 OverlayInode::AddEntry(overlay_dirent *entry, bool attribute)
1076 RecursiveLocker locker(fLock);
1077 if (!attribute && !fHasDirents)
1078 _PopulateDirents();
1079 else if (attribute && !fHasAttributeDirents)
1080 _PopulateAttributeDirents();
1082 status_t result = RemoveEntry(entry->name, NULL, attribute);
1083 if (result != B_OK && result != B_ENTRY_NOT_FOUND)
1084 return B_FILE_EXISTS;
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;
1093 if (attribute) {
1094 fAttributeDirents = newDirents;
1095 fAttributeDirents[fAttributeDirentCount++] = entry;
1096 } else {
1097 fDirents = newDirents;
1098 fDirents[fDirentCount++] = entry;
1101 if (!fIsModified)
1102 SetModified();
1104 return B_OK;
1108 status_t
1109 OverlayInode::RemoveEntry(const char *name, overlay_dirent **_entry,
1110 bool attribute)
1112 RecursiveLocker locker(fLock);
1113 if (!attribute && !fHasDirents)
1114 _PopulateDirents();
1115 else if (attribute && !fHasAttributeDirents)
1116 _PopulateAttributeDirents();
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;
1132 if (node->IsNonEmptyDirectory())
1133 result = B_DIRECTORY_NOT_EMPTY;
1135 put_vnode(Volume(), entry->inode_number);
1136 if (result != B_OK)
1137 return result;
1140 for (uint32 j = i + 1; j < direntCount; j++)
1141 dirents[j - 1] = dirents[j];
1143 if (attribute)
1144 fAttributeDirentCount--;
1145 else
1146 fDirentCount--;
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);
1155 if (!fIsModified)
1156 SetModified();
1158 return B_OK;
1162 return B_ENTRY_NOT_FOUND;
1166 void
1167 OverlayInode::_TrimBuffers()
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;
1174 while (buffer != NULL) {
1175 off_t bufferEnd = buffer->position + buffer->length;
1176 if (bufferEnd > fStat.st_size)
1177 break;
1179 link = &buffer->next;
1180 buffer = buffer->next;
1183 if (buffer == NULL) {
1184 // didn't find anything crossing or past the end
1185 return;
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);
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
1202 buffer->length = newLength;
1203 link = &buffer->next;
1204 buffer = buffer->next;
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;
1217 status_t
1218 OverlayInode::_PopulateStat()
1220 if (fHasStat)
1221 return B_OK;
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;
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;
1235 result = fSuperVnode.ops->read_attr_stat(SuperVolume(), &fSuperVnode,
1236 cookie, &fStat);
1238 if (fSuperVnode.ops->close_attr != NULL)
1239 fSuperVnode.ops->close_attr(SuperVolume(), &fSuperVnode, cookie);
1241 if (fSuperVnode.ops->free_attr_cookie != NULL) {
1242 fSuperVnode.ops->free_attr_cookie(SuperVolume(), &fSuperVnode,
1243 cookie);
1246 return B_OK;
1249 if (fSuperVnode.ops->read_stat == NULL)
1250 return B_UNSUPPORTED;
1252 return fSuperVnode.ops->read_stat(SuperVolume(), &fSuperVnode, &fStat);
1256 status_t
1257 OverlayInode::_PopulateDirents()
1259 if (fHasDirents)
1260 return B_OK;
1262 fDirents = (overlay_dirent **)malloc(sizeof(overlay_dirent *) * 2);
1263 if (fDirents == NULL)
1264 return B_NO_MEMORY;
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;
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;
1281 fDirentCount++;
1284 fHasDirents = true;
1285 if (fIsVirtual || fSuperVnode.ops->open_dir == NULL
1286 || fSuperVnode.ops->read_dir == NULL)
1287 return B_OK;
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;
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;
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;
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;
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;
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;
1335 fDirents[fDirentCount++] = entry;
1338 dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen);
1342 free(buffer);
1344 close_dir:
1345 if (fSuperVnode.ops->close_dir != NULL)
1346 fSuperVnode.ops->close_dir(SuperVolume(), &fSuperVnode, superCookie);
1348 if (fSuperVnode.ops->free_dir_cookie != NULL) {
1349 fSuperVnode.ops->free_dir_cookie(SuperVolume(), &fSuperVnode,
1350 superCookie);
1353 return B_OK;
1357 status_t
1358 OverlayInode::_PopulateAttributeDirents()
1360 if (fHasAttributeDirents)
1361 return B_OK;
1363 fHasAttributeDirents = true;
1364 if (fIsVirtual || fSuperVnode.ops->open_attr_dir == NULL
1365 || fSuperVnode.ops->read_attr_dir == NULL)
1366 return B_OK;
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;
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;
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;
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;
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;
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;
1414 fAttributeDirents[fAttributeDirentCount++] = entry;
1415 dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen);
1419 free(buffer);
1421 close_attr_dir:
1422 if (fSuperVnode.ops->close_attr_dir != NULL) {
1423 fSuperVnode.ops->close_attr_dir(SuperVolume(), &fSuperVnode,
1424 superCookie);
1427 if (fSuperVnode.ops->free_attr_dir_cookie != NULL) {
1428 fSuperVnode.ops->free_attr_dir_cookie(SuperVolume(), &fSuperVnode,
1429 superCookie);
1432 return B_OK;
1436 status_t
1437 OverlayInode::_CreateCommon(const char *name, int type, int perms,
1438 ino_t *newInodeNumber, OverlayInode **_node, bool attribute,
1439 type_code attributeType)
1441 RecursiveLocker locker(fLock);
1442 if (!fHasStat)
1443 _PopulateStat();
1445 if (!attribute && !S_ISDIR(fStat.st_mode))
1446 return B_NOT_A_DIRECTORY;
1448 locker.Unlock();
1450 overlay_dirent *entry = (overlay_dirent *)malloc(sizeof(overlay_dirent));
1451 if (entry == NULL)
1452 return B_NO_MEMORY;
1454 entry->node = NULL;
1455 entry->name = strdup(name);
1456 if (entry->name == NULL) {
1457 free(entry);
1458 return B_NO_MEMORY;
1461 if (attribute)
1462 entry->inode_number = fInodeNumber;
1463 else
1464 entry->inode_number = fVolume->BuildInodeNumber();
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;
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;
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;
1491 } else
1492 entry->node = node;
1494 node->Lock();
1495 node->SetDataModified();
1496 if (!attribute)
1497 node->CreateCache();
1498 node->Unlock();
1500 if (newInodeNumber != NULL)
1501 *newInodeNumber = entry->inode_number;
1502 if (_node != NULL)
1503 *_node = node;
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);
1513 return B_OK;
1517 // #pragma mark - vnode ops
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;
1531 static status_t
1532 overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
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;
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);
1549 delete node;
1550 return result;
1554 static status_t
1555 overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1557 TRACE("remove_vnode\n");
1558 OverlayInode *node = (OverlayInode *)vnode->private_node;
1559 if (node->IsVirtual()) {
1560 delete node;
1561 return B_OK;
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);
1571 delete node;
1572 return result;
1576 static status_t
1577 overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode,
1578 fs_volume *superVolume, fs_vnode *_superVnode)
1580 if (volume == superVolume) {
1581 *_superVnode = *vnode;
1582 return B_OK;
1585 OverlayInode *node = (OverlayInode *)vnode->private_node;
1586 if (node->IsVirtual()) {
1587 *_superVnode = *vnode;
1588 return B_OK;
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);
1597 *_superVnode = *superVnode;
1598 return B_OK;
1602 static status_t
1603 overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id)
1605 TRACE("lookup: \"%s\"\n", name);
1606 return ((OverlayInode *)vnode->private_node)->Lookup(name, id);
1610 static status_t
1611 overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer,
1612 size_t bufferSize)
1614 return ((OverlayInode *)vnode->private_node)->GetName(buffer, bufferSize);
1618 static bool
1619 overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie)
1621 TRACE("relaying op: can_page\n");
1622 OverlayInode *node = (OverlayInode *)vnode->private_node;
1623 if (node->IsVirtual())
1624 return false;
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);
1632 return false;
1636 static status_t
1637 overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1638 const iovec *vecs, size_t count, size_t *numBytes)
1640 OverlayInode *node = (OverlayInode *)vnode->private_node;
1641 size_t bytesLeft = *numBytes;
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;
1652 bytesLeft -= transferBytes;
1653 if (bytesLeft == 0)
1654 return B_OK;
1656 if (transferBytes < vecs[i].iov_len) {
1657 *numBytes -= bytesLeft;
1658 return B_OK;
1661 pos += transferBytes;
1664 *numBytes = 0;
1665 return B_OK;
1669 static status_t
1670 overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1671 const iovec *vecs, size_t count, size_t *numBytes)
1673 OverlayInode *node = (OverlayInode *)vnode->private_node;
1674 size_t bytesLeft = *numBytes;
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;
1685 bytesLeft -= transferBytes;
1686 if (bytesLeft == 0)
1687 return B_OK;
1689 if (transferBytes < vecs[i].iov_len) {
1690 *numBytes -= bytesLeft;
1691 return B_OK;
1694 pos += transferBytes;
1697 *numBytes = 0;
1698 return B_OK;
1702 static status_t
1703 overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1704 io_request *request)
1706 OverlayInode *node = (OverlayInode *)vnode->private_node;
1707 if (io_request_is_write(request) || node->IsModified())
1708 return node->SynchronousIO(cookie, (IORequest *)request);
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);
1718 return B_UNSUPPORTED;
1722 static status_t
1723 overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1724 io_request *request)
1726 OVERLAY_CALL(cancel_io, cookie, request)
1730 static status_t
1731 overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset,
1732 size_t size, struct file_io_vec *vecs, size_t *count)
1734 OVERLAY_CALL(get_file_map, offset, size, vecs, count)
1738 static status_t
1739 overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op,
1740 void *buffer, size_t length)
1742 OVERLAY_CALL(ioctl, cookie, op, buffer, length)
1746 static status_t
1747 overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie,
1748 int flags)
1750 return ((OverlayInode *)vnode->private_node)->SetFlags(cookie, flags);
1754 static status_t
1755 overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1756 selectsync *sync)
1758 OVERLAY_CALL(select, cookie, event, sync)
1762 static status_t
1763 overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1764 selectsync *sync)
1766 OVERLAY_CALL(deselect, cookie, event, sync)
1770 static status_t
1771 overlay_fsync(fs_volume *volume, fs_vnode *vnode)
1773 return B_OK;
1777 static status_t
1778 overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer,
1779 size_t *bufferSize)
1781 TRACE("read_symlink\n");
1782 return ((OverlayInode *)vnode->private_node)->ReadSymlink(buffer,
1783 bufferSize);
1787 static status_t
1788 overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name,
1789 const char *path, int mode)
1791 TRACE("create_symlink: \"%s\" -> \"%s\"\n", name, path);
1792 return ((OverlayInode *)vnode->private_node)->CreateSymlink(name, path,
1793 mode);
1797 static status_t
1798 overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name,
1799 fs_vnode *target)
1801 return B_UNSUPPORTED;
1805 static status_t
1806 overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name)
1808 TRACE("unlink: \"%s\"\n", name);
1809 return ((OverlayInode *)vnode->private_node)->RemoveEntry(name, NULL);
1813 static status_t
1814 overlay_rename(fs_volume *volume, fs_vnode *vnode,
1815 const char *fromName, fs_vnode *toVnode, const char *toName)
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;
1822 status_t result = fromNode->RemoveEntry(fromName, &entry);
1823 if (result != B_OK)
1824 return result;
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());
1833 return B_NO_MEMORY;
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());
1843 return result;
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);
1854 free(oldName);
1855 notify_entry_moved(volume->id, fromNode->InodeNumber(), fromName,
1856 toNode->InodeNumber(), toName, entry->inode_number);
1857 return B_OK;
1861 static status_t
1862 overlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
1864 // TODO: implement
1865 return B_OK;
1869 static status_t
1870 overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat)
1872 TRACE("read_stat\n");
1873 return ((OverlayInode *)vnode->private_node)->ReadStat(stat);
1877 static status_t
1878 overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat,
1879 uint32 statMask)
1881 TRACE("write_stat\n");
1882 return ((OverlayInode *)vnode->private_node)->WriteStat(stat, statMask);
1886 static status_t
1887 overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name,
1888 int openMode, int perms, void **cookie, ino_t *newVnodeID)
1890 TRACE("create: \"%s\"\n", name);
1891 return ((OverlayInode *)vnode->private_node)->Create(name, openMode,
1892 perms, cookie, newVnodeID);
1896 static status_t
1897 overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie)
1899 TRACE("open\n");
1900 return ((OverlayInode *)vnode->private_node)->Open(openMode, cookie);
1904 static status_t
1905 overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie)
1907 TRACE("close\n");
1908 return ((OverlayInode *)vnode->private_node)->Close(cookie);
1912 static status_t
1913 overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1915 TRACE("free_cookie\n");
1916 return ((OverlayInode *)vnode->private_node)->FreeCookie(cookie);
1920 static status_t
1921 overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1922 void *buffer, size_t *length)
1924 TRACE("read\n");
1925 return ((OverlayInode *)vnode->private_node)->Read(cookie, pos, buffer,
1926 length, false, NULL);
1930 static status_t
1931 overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1932 const void *buffer, size_t *length)
1934 TRACE("write\n");
1935 return ((OverlayInode *)vnode->private_node)->Write(cookie, pos, buffer,
1936 *length, NULL);
1940 static status_t
1941 overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name,
1942 int perms)
1944 TRACE("create_dir: \"%s\"\n", name);
1945 return ((OverlayInode *)vnode->private_node)->CreateDir(name, perms);
1949 static status_t
1950 overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name)
1952 TRACE("remove_dir: \"%s\"\n", name);
1953 return ((OverlayInode *)vnode->private_node)->RemoveDir(name);
1957 static status_t
1958 overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
1960 TRACE("open_dir\n");
1961 return ((OverlayInode *)vnode->private_node)->OpenDir(cookie);
1965 static status_t
1966 overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1968 TRACE("close_dir\n");
1969 return ((OverlayInode *)vnode->private_node)->CloseDir(cookie);
1973 static status_t
1974 overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1976 TRACE("free_dir_cookie\n");
1977 return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie);
1981 static status_t
1982 overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
1983 struct dirent *buffer, size_t bufferSize, uint32 *num)
1985 TRACE("read_dir\n");
1986 return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer,
1987 bufferSize, num);
1991 static status_t
1992 overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1994 TRACE("rewind_dir\n");
1995 return ((OverlayInode *)vnode->private_node)->RewindDir(cookie);
1999 static status_t
2000 overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
2002 TRACE("open_attr_dir\n");
2003 return ((OverlayInode *)vnode->private_node)->OpenDir(cookie, true);
2007 static status_t
2008 overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
2010 TRACE("close_attr_dir\n");
2011 return ((OverlayInode *)vnode->private_node)->CloseDir(cookie);
2015 static status_t
2016 overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
2018 TRACE("free_attr_dir_cookie\n");
2019 return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie);
2023 static status_t
2024 overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
2025 struct dirent *buffer, size_t bufferSize, uint32 *num)
2027 TRACE("read_attr_dir\n");
2028 return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer,
2029 bufferSize, num, true);
2033 static status_t
2034 overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
2036 TRACE("rewind_attr_dir\n");
2037 return ((OverlayInode *)vnode->private_node)->RewindDir(cookie);
2041 static status_t
2042 overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
2043 uint32 type, int openMode, void **cookie)
2045 TRACE("create_attr\n");
2046 return ((OverlayInode *)vnode->private_node)->Create(name, openMode, 0,
2047 cookie, NULL, true, type);
2051 static status_t
2052 overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
2053 int openMode, void **cookie)
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;
2064 return node->Open(openMode, cookie);
2068 static status_t
2069 overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie)
2071 TRACE("close_attr\n");
2072 open_cookie *cookie = (open_cookie *)_cookie;
2073 return cookie->node->Close(cookie);
2077 static status_t
2078 overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *_cookie)
2080 TRACE("free_attr_cookie\n");
2081 open_cookie *cookie = (open_cookie *)_cookie;
2082 return cookie->node->FreeCookie(cookie);
2086 static status_t
2087 overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos,
2088 void *buffer, size_t *length)
2090 TRACE("read_attr\n");
2091 open_cookie *cookie = (open_cookie *)_cookie;
2092 return cookie->node->Read(cookie, pos, buffer, length, false, NULL);
2096 static status_t
2097 overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos,
2098 const void *buffer, size_t *length)
2100 TRACE("write_attr\n");
2101 open_cookie *cookie = (open_cookie *)_cookie;
2102 return cookie->node->Write(cookie, pos, buffer, *length, NULL);
2106 static status_t
2107 overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie,
2108 struct stat *stat)
2110 TRACE("read_attr_stat\n");
2111 open_cookie *cookie = (open_cookie *)_cookie;
2112 return cookie->node->ReadStat(stat);
2116 static status_t
2117 overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie,
2118 const struct stat *stat, int statMask)
2120 TRACE("write_attr_stat\n");
2121 open_cookie *cookie = (open_cookie *)_cookie;
2122 return cookie->node->WriteStat(stat, statMask);
2126 static status_t
2127 overlay_rename_attr(fs_volume *volume, fs_vnode *vnode,
2128 const char *fromName, fs_vnode *toVnode, const char *toName)
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;
2135 status_t result = fromNode->RemoveEntry(fromName, &entry, true);
2136 if (result != B_OK)
2137 return result;
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());
2146 return B_NO_MEMORY;
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());
2156 return result;
2159 OverlayInode *node = entry->node;
2160 if (node == NULL)
2161 return B_ERROR;
2163 node->SetName(entry->name);
2164 node->SetSuperVnode(toNode->SuperVnode());
2165 node->SetInodeNumber(toNode->InodeNumber());
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);
2172 free(oldName);
2173 return B_OK;
2177 static status_t
2178 overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name)
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;
2186 notify_attribute_changed(volume->id, -1, node->InodeNumber(), name,
2187 B_ATTR_REMOVED);
2188 return result;
2192 static status_t
2193 overlay_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)
2197 OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, nodeID)
2201 static fs_vnode_ops sOverlayVnodeOps = {
2202 &overlay_lookup,
2203 &overlay_get_vnode_name,
2205 &overlay_put_vnode,
2206 &overlay_remove_vnode,
2208 &overlay_can_page,
2209 &overlay_read_pages,
2210 &overlay_write_pages,
2212 &overlay_io,
2213 &overlay_cancel_io,
2215 &overlay_get_file_map,
2217 /* common */
2218 &overlay_ioctl,
2219 &overlay_set_flags,
2220 &overlay_select,
2221 &overlay_deselect,
2222 &overlay_fsync,
2224 &overlay_read_symlink,
2225 &overlay_create_symlink,
2226 &overlay_link,
2227 &overlay_unlink,
2228 &overlay_rename,
2230 &overlay_access,
2231 &overlay_read_stat,
2232 &overlay_write_stat,
2233 NULL, // fs_preallocate
2235 /* file */
2236 &overlay_create,
2237 &overlay_open,
2238 &overlay_close,
2239 &overlay_free_cookie,
2240 &overlay_read,
2241 &overlay_write,
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,
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,
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,
2267 &overlay_read_attr_stat,
2268 &overlay_write_attr_stat,
2269 &overlay_rename_attr,
2270 &overlay_remove_attr,
2272 /* support for node and FS layers */
2273 &overlay_create_special_node,
2274 &overlay_get_super_vnode
2278 // #pragma mark - volume ops
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);
2287 static status_t
2288 overlay_unmount(fs_volume *volume)
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);
2296 delete (OverlayVolume *)volume->private_volume;
2297 return B_OK;
2301 static status_t
2302 overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
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;
2312 info->flags &= ~B_FS_IS_READONLY;
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;
2321 return B_UNSUPPORTED;
2325 static status_t
2326 overlay_write_fs_info(fs_volume *volume, const struct fs_info *info,
2327 uint32 mask)
2329 OVERLAY_VOLUME_CALL(write_fs_info, info, mask)
2330 return B_UNSUPPORTED;
2334 static status_t
2335 overlay_sync(fs_volume *volume)
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;
2344 static status_t
2345 overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type,
2346 uint32 *_flags, bool reenter)
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;
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;
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;
2369 vnode->private_node = node;
2370 vnode->ops = &sOverlayVnodeOps;
2371 return B_OK;
2374 return B_UNSUPPORTED;
2378 static status_t
2379 overlay_open_index_dir(fs_volume *volume, void **cookie)
2381 OVERLAY_VOLUME_CALL(open_index_dir, cookie)
2382 return B_UNSUPPORTED;
2386 static status_t
2387 overlay_close_index_dir(fs_volume *volume, void *cookie)
2389 OVERLAY_VOLUME_CALL(close_index_dir, cookie)
2390 return B_UNSUPPORTED;
2394 static status_t
2395 overlay_free_index_dir_cookie(fs_volume *volume, void *cookie)
2397 OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie)
2398 return B_UNSUPPORTED;
2402 static status_t
2403 overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer,
2404 size_t bufferSize, uint32 *_num)
2406 OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num)
2407 return B_UNSUPPORTED;
2411 static status_t
2412 overlay_rewind_index_dir(fs_volume *volume, void *cookie)
2414 OVERLAY_VOLUME_CALL(rewind_index_dir, cookie)
2415 return B_UNSUPPORTED;
2419 static status_t
2420 overlay_create_index(fs_volume *volume, const char *name, uint32 type,
2421 uint32 flags)
2423 OVERLAY_VOLUME_CALL(create_index, name, type, flags)
2424 return B_UNSUPPORTED;
2428 static status_t
2429 overlay_remove_index(fs_volume *volume, const char *name)
2431 OVERLAY_VOLUME_CALL(remove_index, name)
2432 return B_UNSUPPORTED;
2436 static status_t
2437 overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat)
2439 OVERLAY_VOLUME_CALL(read_index_stat, name, stat)
2440 return B_UNSUPPORTED;
2444 static status_t
2445 overlay_open_query(fs_volume *volume, const char *query, uint32 flags,
2446 port_id port, uint32 token, void **_cookie)
2448 OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie)
2449 return B_UNSUPPORTED;
2453 static status_t
2454 overlay_close_query(fs_volume *volume, void *cookie)
2456 OVERLAY_VOLUME_CALL(close_query, cookie)
2457 return B_UNSUPPORTED;
2461 static status_t
2462 overlay_free_query_cookie(fs_volume *volume, void *cookie)
2464 OVERLAY_VOLUME_CALL(free_query_cookie, cookie)
2465 return B_UNSUPPORTED;
2469 static status_t
2470 overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer,
2471 size_t bufferSize, uint32 *_num)
2473 OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num)
2474 return B_UNSUPPORTED;
2478 static status_t
2479 overlay_rewind_query(fs_volume *volume, void *cookie)
2481 OVERLAY_VOLUME_CALL(rewind_query, cookie)
2482 return B_UNSUPPORTED;
2486 static status_t
2487 overlay_all_layers_mounted(fs_volume *volume)
2489 return B_OK;
2493 static status_t
2494 overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode)
2496 OverlayInode *node = new(std::nothrow) OverlayInode(
2497 (OverlayVolume *)volume->private_volume, vnode, id);
2498 if (node == NULL)
2499 return B_NO_MEMORY;
2501 status_t status = node->InitCheck();
2502 if (status != B_OK) {
2503 delete node;
2504 return status;
2507 vnode->private_node = node;
2508 vnode->ops = &sOverlayVnodeOps;
2509 return B_OK;
2513 static status_t
2514 overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode)
2516 delete (OverlayInode *)vnode->private_node;
2517 return B_OK;
2521 static fs_volume_ops sOverlayVolumeOps = {
2522 &overlay_unmount,
2524 &overlay_read_fs_info,
2525 &overlay_write_fs_info,
2526 &overlay_sync,
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,
2535 &overlay_create_index,
2536 &overlay_remove_index,
2537 &overlay_read_index_stat,
2539 &overlay_open_query,
2540 &overlay_close_query,
2541 &overlay_free_query_cookie,
2542 &overlay_read_query,
2543 &overlay_rewind_query,
2545 &overlay_all_layers_mounted,
2546 &overlay_create_sub_vnode,
2547 &overlay_delete_sub_vnode
2551 // #pragma mark - filesystem module
2554 static status_t
2555 overlay_mount(fs_volume *volume, const char *device, uint32 flags,
2556 const char *args, ino_t *rootID)
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;
2563 volume->ops = &sOverlayVolumeOps;
2564 return B_OK;
2568 static status_t
2569 overlay_std_ops(int32 op, ...)
2571 switch (op) {
2572 case B_MODULE_INIT:
2573 case B_MODULE_UNINIT:
2574 return B_OK;
2575 default:
2576 return B_ERROR;
2581 static file_system_module_info sOverlayFileSystem = {
2583 "file_systems/write_overlay" B_CURRENT_FS_API_VERSION,
2585 overlay_std_ops,
2588 "write_overlay", // short_name
2589 "Write Overlay File System", // pretty_name
2590 0, // DDM flags
2592 // scanning
2593 NULL, // identify_partition
2594 NULL, // scan_partition
2595 NULL, // free_identify_partition_cookie
2596 NULL, // free_partition_content_cookie
2598 // general operations
2599 &overlay_mount,
2601 // capability querying
2602 NULL, // get_supported_operations
2604 NULL, // validate_resize
2605 NULL, // validate_move
2606 NULL, // validate_set_content_name
2607 NULL, // validate_set_content_parameters
2608 NULL, // validate_initialize
2610 // shadow partition modification
2611 NULL, // shadow_changed
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
2624 status_t
2625 publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber, void *privateNode,
2626 int type)
2628 return publish_vnode(volume, inodeNumber, privateNode, &sOverlayVnodeOps,
2629 type, 0);
2632 } // namespace write_overlay
2634 using namespace write_overlay;
2636 module_info *modules[] = {
2637 (module_info *)&sOverlayFileSystem,
2638 NULL,