2 * Copyright 2009-2016, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Michael Lotz <mmlr@mlotz.ch>
15 #include <util/kernel_cpp.h>
16 #include <util/AutoLock.h>
20 #include <fs_interface.h>
21 #include <io_requests.h>
24 #include <KernelExport.h>
25 #include <NodeMonitor.h>
27 #include "IORequest.h"
30 //#define 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)
36 #define TRACE(x...) /* nothing */
37 #define TRACE_VOLUME(x...) /* nothing */
38 #define TRACE_ALWAYS(x...) dprintf("write_overlay: " x)
42 namespace write_overlay
{
44 status_t
publish_overlay_vnode(fs_volume
*volume
, ino_t inodeNumber
,
45 void *privateNode
, int type
);
56 struct open_dir_cookie
{
61 struct overlay_dirent
{
64 OverlayInode
* node
; // only for attributes
66 void remove_and_dispose(fs_volume
*volume
, ino_t directoryInode
)
68 notify_entry_removed(volume
->id
, directoryInode
,
70 remove_vnode(volume
, inode_number
);
75 void dispose_attribute(fs_volume
*volume
, ino_t fileInode
)
77 notify_attribute_changed(volume
->id
, -1, fileInode
,
78 name
, B_ATTR_REMOVED
);
95 OverlayVolume(fs_volume
*volume
);
98 fs_volume
* Volume() { return fVolume
; }
99 fs_volume
* SuperVolume() { return fVolume
->super_volume
; }
101 ino_t
BuildInodeNumber() { return fCurrentInodeNumber
++; }
105 ino_t fCurrentInodeNumber
;
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);
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
; }
139 void SetDataModified();
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
,
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
,
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);
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
;
208 fs_vnode fSuperVnode
;
210 write_buffer
* fWriteBuffers
;
211 off_t fOriginalNodeLength
;
212 overlay_dirent
** fDirents
;
214 overlay_dirent
** fAttributeDirents
;
215 uint32 fAttributeDirentCount
;
219 bool fHasAttributeDirents
;
223 bool fIsDataModified
;
228 // #pragma mark OverlayVolume
231 OverlayVolume::OverlayVolume(fs_volume
*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
)
250 fParentDir(parentDir
),
252 fInodeNumber(inodeNumber
),
254 fOriginalNodeLength(-1),
257 fAttributeDirents(NULL
),
258 fAttributeDirentCount(0),
261 fHasAttributeDirents(false),
262 fIsVirtual(superVnode
== NULL
),
263 fIsAttribute(attribute
),
265 fIsDataModified(false),
268 TRACE("inode created %" B_PRIdINO
"\n", fInodeNumber
);
270 recursive_lock_init(&fLock
, "write overlay inode lock");
271 if (superVnode
!= NULL
)
272 fSuperVnode
= *superVnode
;
274 fStat
.st_dev
= SuperVolume()->id
;
275 fStat
.st_ino
= fInodeNumber
;
276 fStat
.st_mode
= mode
;
282 fStat
.st_blksize
= 1024;
283 fStat
.st_atime
= fStat
.st_mtime
= fStat
.st_ctime
= fStat
.st_crtime
285 fStat
.st_type
= attributeType
;
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
;
299 write_buffer
*next
= element
->next
;
304 for (uint32 i
= 0; i
< fDirentCount
; i
++) {
305 free(fDirents
[i
]->name
);
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
);
321 OverlayInode::InitCheck()
328 OverlayInode::SetSuperVnode(fs_vnode
*superVnode
)
330 RecursiveLocker
locker(fLock
);
331 fSuperVnode
= *superVnode
;
336 OverlayInode::SetInodeNumber(ino_t inodeNumber
)
338 RecursiveLocker
locker(fLock
);
339 fInodeNumber
= inodeNumber
;
344 OverlayInode::SetModified()
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?
356 get_vnode(Volume(), fInodeNumber
, &unused
);
362 OverlayInode::SetDataModified()
364 fIsDataModified
= true;
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
);
382 OverlayInode::SetParentDir(OverlayInode
*parentDir
)
384 RecursiveLocker
locker(fLock
);
385 fParentDir
= parentDir
;
386 if (fHasDirents
&& fDirentCount
>= 2)
387 fDirents
[1]->inode_number
= parentDir
->InodeNumber();
392 OverlayInode::IsNonEmptyDirectory()
394 RecursiveLocker
locker(fLock
);
398 if (!S_ISDIR(fStat
.st_mode
))
404 return fDirentCount
> 2; // accounting for "." and ".." entries
409 OverlayInode::Lookup(const char *name
, ino_t
*inodeNumber
)
411 RecursiveLocker
locker(fLock
);
415 for (uint32 i
= 0; i
< fDirentCount
; i
++) {
416 if (strcmp(fDirents
[i
]->name
, name
) == 0) {
417 *inodeNumber
= fDirents
[i
]->inode_number
;
420 OverlayInode
*node
= NULL
;
421 status_t result
= get_vnode(Volume(), *inodeNumber
,
423 if (result
== B_OK
&& node
!= NULL
&& i
>= 2)
424 node
->SetParentDir(this);
429 return B_ENTRY_NOT_FOUND
;
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);
449 status_t result
= newNode
->InitCheck();
450 if (result
!= B_OK
) {
455 dirent
->node
= newNode
;
458 *node
= dirent
->node
;
463 return B_ENTRY_NOT_FOUND
;
468 OverlayInode::SetName(const char *name
)
470 RecursiveLocker
locker(fLock
);
478 OverlayInode::GetName(char *buffer
, size_t bufferSize
)
480 RecursiveLocker
locker(fLock
);
482 strlcpy(buffer
, fName
, bufferSize
);
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
,
498 OverlayInode::ReadStat(struct stat
*stat
)
500 RecursiveLocker
locker(fLock
);
504 memcpy(stat
, &fStat
, sizeof(struct stat
));
505 stat
->st_blocks
= (stat
->st_size
+ stat
->st_blksize
- 1) / stat
->st_blksize
;
511 OverlayInode::WriteStat(const struct stat
*stat
, uint32 statMask
)
514 return B_UNSUPPORTED
;
516 RecursiveLocker
locker(fLock
);
520 if (statMask
& B_STAT_SIZE
) {
521 if (fStat
.st_size
!= stat
->st_size
) {
522 fStat
.st_size
= stat
->st_size
;
523 if (!fIsDataModified
)
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
;
550 notify_stat_changed(SuperVolume()->id
, -1, fInodeNumber
, statMask
);
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
);
565 return newNode
->Open(openMode
, cookie
);
570 OverlayInode::Open(int openMode
, void **_cookie
)
572 RecursiveLocker
locker(fLock
);
576 open_cookie
*cookie
= (open_cookie
*)malloc(sizeof(open_cookie
));
580 cookie
->open_mode
= openMode
;
585 if (openMode
& O_TRUNC
) {
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) {
601 if (!fIsDataModified
)
606 openMode
&= ~(O_RDWR
| O_WRONLY
| O_TRUNC
| O_CREAT
);
609 result
= fSuperVnode
.ops
->open_attr(SuperVolume(), &fSuperVnode
,
610 fName
, openMode
, &cookie
->super_cookie
);
612 result
= fSuperVnode
.ops
->open(SuperVolume(), &fSuperVnode
,
613 openMode
, &cookie
->super_cookie
);
616 if (result
!= B_OK
) {
621 if (fOriginalNodeLength
< 0) {
624 result
= fSuperVnode
.ops
->read_attr_stat(SuperVolume(),
625 &fSuperVnode
, cookie
->super_cookie
, &stat
);
627 result
= fSuperVnode
.ops
->read_stat(SuperVolume(),
628 &fSuperVnode
, &stat
);
634 fOriginalNodeLength
= stat
.st_size
;
642 OverlayInode::Close(void *_cookie
)
647 open_cookie
*cookie
= (open_cookie
*)_cookie
;
649 return fSuperVnode
.ops
->close_attr(SuperVolume(), &fSuperVnode
,
650 cookie
->super_cookie
);
653 return fSuperVnode
.ops
->close(SuperVolume(), &fSuperVnode
,
654 cookie
->super_cookie
);
659 OverlayInode::FreeCookie(void *_cookie
)
661 status_t result
= B_OK
;
662 open_cookie
*cookie
= (open_cookie
*)_cookie
;
665 result
= fSuperVnode
.ops
->free_attr_cookie(SuperVolume(),
666 &fSuperVnode
, cookie
->super_cookie
);
668 result
= fSuperVnode
.ops
->free_cookie(SuperVolume(),
669 &fSuperVnode
, cookie
->super_cookie
);
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
) {
688 uint8
*pointer
= (uint8
*)buffer
;
689 write_buffer
*element
= fWriteBuffers
;
690 size_t bytesLeft
= (size_t)MIN(fStat
.st_size
- position
, (off_t
)*length
);
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
,
709 status_t result
= B_ERROR
;
712 vector
.iov_base
= pointer
;
713 vector
.iov_len
= readLength
;
715 result
= fSuperVnode
.ops
->read_pages(SuperVolume(),
716 &fSuperVnode
, superCookie
, position
, &vector
, 1,
718 } else if (ioRequest
!= NULL
) {
719 IORequest
*subRequest
;
720 result
= ioRequest
->CreateSubRequest(position
, position
,
721 readLength
, subRequest
);
725 bool wereSuppressed
= ioRequest
->SuppressChildNotifications();
726 ioRequest
->SetSuppressChildNotifications(true);
727 result
= fSuperVnode
.ops
->io(SuperVolume(), &fSuperVnode
,
728 superCookie
, subRequest
);
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
);
739 result
= fSuperVnode
.ops
->read(SuperVolume(), &fSuperVnode
,
740 superCookie
, position
, pointer
, &readLength
);
746 pointer
+= readLength
;
747 position
+= readLength
;
748 bytesLeft
-= readLength
;
749 gapSize
-= readLength
;
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
758 memset(pointer
, 0, gapSize
);
760 bytesLeft
-= gapSize
;
765 // we've reached the end
766 if (bytesLeft
== 0 || element
== NULL
)
769 off_t elementEnd
= element
->position
+ element
->length
;
770 if (elementEnd
> position
) {
771 size_t copyLength
= (size_t)MIN(elementEnd
- position
,
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
);
780 memcpy(pointer
, source
, copyLength
);
782 bytesLeft
-= copyLength
;
783 position
+= copyLength
;
784 pointer
+= copyLength
;
787 element
= element
->next
;
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
)
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;
817 off_t newEnd
= newPosition
+ newLength
;
818 off_t otherEnd
= other
->position
+ other
->length
;
819 if (otherEnd
< newPosition
) {
820 // other is completely before us
826 if (other
->position
> newEnd
) {
827 // other is completely past us
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
);
842 memcpy(target
, buffer
, length
);
844 fStat
.st_mtime
= time(NULL
);
846 notify_attribute_changed(SuperVolume()->id
, -1,
847 fInodeNumber
, fName
, B_ATTR_CHANGED
);
849 notify_stat_changed(SuperVolume()->id
, -1, fInodeNumber
,
850 B_STAT_MODIFICATION_TIME
);
855 newLength
+= newPosition
- other
->position
;
856 newPosition
= other
->position
;
859 if (otherEnd
> newEnd
)
860 newLength
+= otherEnd
- newEnd
;
865 write_buffer
*element
= (write_buffer
*)malloc(sizeof(write_buffer
) - 1
870 element
->next
= *link
;
871 element
->position
= newPosition
;
872 element
->length
= newLength
;
875 bool sizeChanged
= false;
876 off_t newEnd
= newPosition
+ newLength
;
877 if (newEnd
> fStat
.st_size
) {
878 fStat
.st_size
= newEnd
;
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
;
893 swallow
= element
->next
;
897 void *target
= element
->buffer
+ (position
- newPosition
);
898 if (ioRequest
!= NULL
)
899 ioRequest
->CopyData(0, target
, length
);
901 memcpy(target
, buffer
, length
);
903 fStat
.st_mtime
= time(NULL
);
906 notify_attribute_changed(SuperVolume()->id
, -1, fInodeNumber
, fName
,
909 notify_stat_changed(SuperVolume()->id
, -1, fInodeNumber
,
910 B_STAT_MODIFICATION_TIME
| (sizeChanged
? B_STAT_SIZE
: 0));
918 OverlayInode::SynchronousIO(void *cookie
, IORequest
*request
)
921 size_t length
= request
->Length();
922 if (request
->IsWrite())
923 result
= Write(cookie
, request
->Offset(), NULL
, length
, request
);
925 result
= Read(cookie
, request
->Offset(), NULL
, &length
, false, request
);
928 request
->SetTransferredBytes(false, length
);
930 request
->SetStatusAndNotify(result
);
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
);
946 OverlayInode::CreateDir(const char *name
, int perms
)
948 return _CreateCommon(name
, S_IFDIR
, perms
, NULL
, NULL
, false, 0);
953 OverlayInode::RemoveDir(const char *name
)
955 return RemoveEntry(name
, NULL
);
960 OverlayInode::OpenDir(void **cookie
, bool attribute
)
962 RecursiveLocker
locker(fLock
);
967 if (!S_ISDIR(fStat
.st_mode
))
968 return B_NOT_A_DIRECTORY
;
971 if (!attribute
&& !fHasDirents
)
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
)
981 dirCookie
->index
= 0;
988 OverlayInode::CloseDir(void *cookie
)
995 OverlayInode::FreeDirCookie(void *cookie
)
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
) {
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
;
1022 buffer
->d_ino
= dirent
->inode_number
;
1024 buffer
->d_reclen
= sizeof(struct dirent
) + nameLength
;
1025 strlcpy(buffer
->d_name
, dirent
->name
, nameLength
);
1033 OverlayInode::RewindDir(void *cookie
)
1035 open_dir_cookie
*dirCookie
= (open_dir_cookie
*)cookie
;
1036 dirCookie
->index
= 0;
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
,
1051 return newNode
->Write(NULL
, 0, path
, strlen(path
), NULL
);
1056 OverlayInode::ReadSymlink(char *buffer
, size_t *bufferSize
)
1059 if (!S_ISLNK(fStat
.st_mode
))
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
,
1074 OverlayInode::AddEntry(overlay_dirent
*entry
, bool attribute
)
1076 RecursiveLocker
locker(fLock
);
1077 if (!attribute
&& !fHasDirents
)
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
)
1094 fAttributeDirents
= newDirents
;
1095 fAttributeDirents
[fAttributeDirentCount
++] = entry
;
1097 fDirents
= newDirents
;
1098 fDirents
[fDirentCount
++] = entry
;
1109 OverlayInode::RemoveEntry(const char *name
, overlay_dirent
**_entry
,
1112 RecursiveLocker
locker(fLock
);
1113 if (!attribute
&& !fHasDirents
)
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
,
1132 if (node
->IsNonEmptyDirectory())
1133 result
= B_DIRECTORY_NOT_EMPTY
;
1135 put_vnode(Volume(), entry
->inode_number
);
1140 for (uint32 j
= i
+ 1; j
< direntCount
; j
++)
1141 dirents
[j
- 1] = dirents
[j
];
1144 fAttributeDirentCount
--;
1151 entry
->dispose_attribute(Volume(), fInodeNumber
);
1153 entry
->remove_and_dispose(Volume(), fInodeNumber
);
1162 return B_ENTRY_NOT_FOUND
;
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
)
1179 link
= &buffer
->next
;
1180 buffer
= buffer
->next
;
1183 if (buffer
== NULL
) {
1184 // didn't find anything crossing or past the end
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
) {
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
1209 while (buffer
!= NULL
) {
1210 write_buffer
*next
= buffer
->next
;
1218 OverlayInode::_PopulateStat()
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
);
1235 result
= fSuperVnode
.ops
->read_attr_stat(SuperVolume(), &fSuperVnode
,
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
,
1249 if (fSuperVnode
.ops
->read_stat
== NULL
)
1250 return B_UNSUPPORTED
;
1252 return fSuperVnode
.ops
->read_stat(SuperVolume(), &fSuperVnode
, &fStat
);
1257 OverlayInode::_PopulateDirents()
1262 fDirents
= (overlay_dirent
**)malloc(sizeof(overlay_dirent
*) * 2);
1263 if (fDirents
== NULL
)
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
)
1274 fDirents
[i
]->inode_number
= inodes
[i
];
1275 fDirents
[i
]->name
= strdup(names
[i
]);
1276 if (fDirents
[i
]->name
== NULL
) {
1285 if (fIsVirtual
|| fSuperVnode
.ops
->open_dir
== NULL
1286 || fSuperVnode
.ops
->read_dir
== NULL
)
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
);
1296 size_t bufferSize
= sizeof(struct dirent
) + B_FILE_NAME_LENGTH
;
1297 struct dirent
*buffer
= (struct dirent
*)malloc(bufferSize
);
1303 result
= fSuperVnode
.ops
->read_dir(SuperVolume(),
1304 &fSuperVnode
, superCookie
, buffer
, bufferSize
, &num
);
1305 if (result
!= B_OK
|| num
== 0)
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");
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");
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");
1335 fDirents
[fDirentCount
++] = entry
;
1338 dirent
= (struct dirent
*)((uint8
*)dirent
+ dirent
->d_reclen
);
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
,
1358 OverlayInode::_PopulateAttributeDirents()
1360 if (fHasAttributeDirents
)
1363 fHasAttributeDirents
= true;
1364 if (fIsVirtual
|| fSuperVnode
.ops
->open_attr_dir
== NULL
1365 || fSuperVnode
.ops
->read_attr_dir
== NULL
)
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
);
1375 size_t bufferSize
= sizeof(struct dirent
) + B_FILE_NAME_LENGTH
;
1376 struct dirent
*buffer
= (struct dirent
*)malloc(bufferSize
);
1378 goto close_attr_dir
;
1382 result
= fSuperVnode
.ops
->read_attr_dir(SuperVolume(),
1383 &fSuperVnode
, superCookie
, buffer
, bufferSize
, &num
);
1384 if (result
!= B_OK
|| num
== 0)
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");
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");
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");
1414 fAttributeDirents
[fAttributeDirentCount
++] = entry
;
1415 dirent
= (struct dirent
*)((uint8
*)dirent
+ dirent
->d_reclen
);
1422 if (fSuperVnode
.ops
->close_attr_dir
!= NULL
) {
1423 fSuperVnode
.ops
->close_attr_dir(SuperVolume(), &fSuperVnode
,
1427 if (fSuperVnode
.ops
->free_attr_dir_cookie
!= NULL
) {
1428 fSuperVnode
.ops
->free_attr_dir_cookie(SuperVolume(), &fSuperVnode
,
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
);
1445 if (!attribute
&& !S_ISDIR(fStat
.st_mode
))
1446 return B_NOT_A_DIRECTORY
;
1450 overlay_dirent
*entry
= (overlay_dirent
*)malloc(sizeof(overlay_dirent
));
1455 entry
->name
= strdup(name
);
1456 if (entry
->name
== NULL
) {
1462 entry
->inode_number
= fInodeNumber
;
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
);
1475 status_t result
= AddEntry(entry
, attribute
);
1476 if (result
!= B_OK
) {
1484 result
= publish_overlay_vnode(fVolume
->Volume(), entry
->inode_number
,
1486 if (result
!= B_OK
) {
1487 RemoveEntry(entry
->name
, NULL
);
1495 node
->SetDataModified();
1497 node
->CreateCache();
1500 if (newInodeNumber
!= NULL
)
1501 *newInodeNumber
= entry
->inode_number
;
1506 notify_attribute_changed(SuperVolume()->id
, -1, fInodeNumber
,
1507 entry
->name
, B_ATTR_CREATED
);
1509 notify_entry_created(SuperVolume()->id
, fInodeNumber
, entry
->name
,
1510 entry
->inode_number
);
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;
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");
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
,
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()) {
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
,
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
;
1585 OverlayInode
*node
= (OverlayInode
*)vnode
->private_node
;
1586 if (node
->IsVirtual()) {
1587 *_superVnode
= *vnode
;
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
;
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
);
1611 overlay_get_vnode_name(fs_volume
*volume
, fs_vnode
*vnode
, char *buffer
,
1614 return ((OverlayInode
*)vnode
->private_node
)->GetName(buffer
, bufferSize
);
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())
1626 fs_vnode
*superVnode
= node
->SuperVnode();
1627 if (superVnode
->ops
->can_page
!= NULL
) {
1628 return superVnode
->ops
->can_page(volume
->super_volume
, superVnode
,
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
;
1652 bytesLeft
-= transferBytes
;
1656 if (transferBytes
< vecs
[i
].iov_len
) {
1657 *numBytes
-= bytesLeft
;
1661 pos
+= transferBytes
;
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
;
1685 bytesLeft
-= transferBytes
;
1689 if (transferBytes
< vecs
[i
].iov_len
) {
1690 *numBytes
-= bytesLeft
;
1694 pos
+= transferBytes
;
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
,
1718 return B_UNSUPPORTED
;
1723 overlay_cancel_io(fs_volume
*volume
, fs_vnode
*vnode
, void *cookie
,
1724 io_request
*request
)
1726 OVERLAY_CALL(cancel_io
, cookie
, request
)
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
)
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
)
1747 overlay_set_flags(fs_volume
*volume
, fs_vnode
*vnode
, void *cookie
,
1750 return ((OverlayInode
*)vnode
->private_node
)->SetFlags(cookie
, flags
);
1755 overlay_select(fs_volume
*volume
, fs_vnode
*vnode
, void *cookie
, uint8 event
,
1758 OVERLAY_CALL(select
, cookie
, event
, sync
)
1763 overlay_deselect(fs_volume
*volume
, fs_vnode
*vnode
, void *cookie
, uint8 event
,
1766 OVERLAY_CALL(deselect
, cookie
, event
, sync
)
1771 overlay_fsync(fs_volume
*volume
, fs_vnode
*vnode
)
1778 overlay_read_symlink(fs_volume
*volume
, fs_vnode
*vnode
, char *buffer
,
1781 TRACE("read_symlink\n");
1782 return ((OverlayInode
*)vnode
->private_node
)->ReadSymlink(buffer
,
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
,
1798 overlay_link(fs_volume
*volume
, fs_vnode
*vnode
, const char *name
,
1801 return B_UNSUPPORTED
;
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
);
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
);
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());
1836 result
= toNode
->AddEntry(entry
);
1837 if (result
!= B_OK
) {
1839 entry
->name
= oldName
;
1840 if (fromNode
->AddEntry(entry
) != B_OK
)
1841 entry
->remove_and_dispose(volume
, fromNode
->InodeNumber());
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
);
1855 notify_entry_moved(volume
->id
, fromNode
->InodeNumber(), fromName
,
1856 toNode
->InodeNumber(), toName
, entry
->inode_number
);
1862 overlay_access(fs_volume
*volume
, fs_vnode
*vnode
, int mode
)
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
);
1878 overlay_write_stat(fs_volume
*volume
, fs_vnode
*vnode
, const struct stat
*stat
,
1881 TRACE("write_stat\n");
1882 return ((OverlayInode
*)vnode
->private_node
)->WriteStat(stat
, statMask
);
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
);
1897 overlay_open(fs_volume
*volume
, fs_vnode
*vnode
, int openMode
, void **cookie
)
1900 return ((OverlayInode
*)vnode
->private_node
)->Open(openMode
, cookie
);
1905 overlay_close(fs_volume
*volume
, fs_vnode
*vnode
, void *cookie
)
1908 return ((OverlayInode
*)vnode
->private_node
)->Close(cookie
);
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
);
1921 overlay_read(fs_volume
*volume
, fs_vnode
*vnode
, void *cookie
, off_t pos
,
1922 void *buffer
, size_t *length
)
1925 return ((OverlayInode
*)vnode
->private_node
)->Read(cookie
, pos
, buffer
,
1926 length
, false, NULL
);
1931 overlay_write(fs_volume
*volume
, fs_vnode
*vnode
, void *cookie
, off_t pos
,
1932 const void *buffer
, size_t *length
)
1935 return ((OverlayInode
*)vnode
->private_node
)->Write(cookie
, pos
, buffer
,
1941 overlay_create_dir(fs_volume
*volume
, fs_vnode
*vnode
, const char *name
,
1944 TRACE("create_dir: \"%s\"\n", name
);
1945 return ((OverlayInode
*)vnode
->private_node
)->CreateDir(name
, perms
);
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
);
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
);
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
);
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
);
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
,
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
);
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);
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
);
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
);
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);
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
);
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
);
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
);
2064 return node
->Open(openMode
, cookie
);
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
);
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
);
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
);
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
);
2107 overlay_read_attr_stat(fs_volume
*volume
, fs_vnode
*vnode
, void *_cookie
,
2110 TRACE("read_attr_stat\n");
2111 open_cookie
*cookie
= (open_cookie
*)_cookie
;
2112 return cookie
->node
->ReadStat(stat
);
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
);
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);
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());
2149 result
= toNode
->AddEntry(entry
, true);
2150 if (result
!= B_OK
) {
2152 entry
->name
= oldName
;
2153 if (fromNode
->AddEntry(entry
, true) != B_OK
)
2154 entry
->dispose_attribute(volume
, fromNode
->InodeNumber());
2159 OverlayInode
*node
= entry
->node
;
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
,
2169 notify_attribute_changed(volume
->id
, -1, toNode
->InodeNumber(), toName
,
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);
2186 notify_attribute_changed(volume
->id
, -1, node
->InodeNumber(), name
,
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
= {
2203 &overlay_get_vnode_name
,
2206 &overlay_remove_vnode
,
2209 &overlay_read_pages
,
2210 &overlay_write_pages
,
2215 &overlay_get_file_map
,
2224 &overlay_read_symlink
,
2225 &overlay_create_symlink
,
2232 &overlay_write_stat
,
2233 NULL
, // fs_preallocate
2239 &overlay_free_cookie
,
2244 &overlay_create_dir
,
2245 &overlay_remove_dir
,
2248 &overlay_free_dir_cookie
,
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
,
2262 &overlay_close_attr
,
2263 &overlay_free_attr_cookie
,
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);
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
;
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
,
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
;
2321 return B_UNSUPPORTED
;
2326 overlay_write_fs_info(fs_volume
*volume
, const struct fs_info
*info
,
2329 OVERLAY_VOLUME_CALL(write_fs_info
, info
, mask
)
2330 return B_UNSUPPORTED
;
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
;
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
);
2355 OverlayInode
*node
= new(std::nothrow
) OverlayInode(
2356 (OverlayVolume
*)volume
->private_volume
, vnode
, id
);
2358 vnode
->ops
->put_vnode(volume
->super_volume
, vnode
, reenter
);
2362 status
= node
->InitCheck();
2363 if (status
!= B_OK
) {
2364 vnode
->ops
->put_vnode(volume
->super_volume
, vnode
, reenter
);
2369 vnode
->private_node
= node
;
2370 vnode
->ops
= &sOverlayVnodeOps
;
2374 return B_UNSUPPORTED
;
2379 overlay_open_index_dir(fs_volume
*volume
, void **cookie
)
2381 OVERLAY_VOLUME_CALL(open_index_dir
, cookie
)
2382 return B_UNSUPPORTED
;
2387 overlay_close_index_dir(fs_volume
*volume
, void *cookie
)
2389 OVERLAY_VOLUME_CALL(close_index_dir
, cookie
)
2390 return B_UNSUPPORTED
;
2395 overlay_free_index_dir_cookie(fs_volume
*volume
, void *cookie
)
2397 OVERLAY_VOLUME_CALL(free_index_dir_cookie
, cookie
)
2398 return B_UNSUPPORTED
;
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
;
2412 overlay_rewind_index_dir(fs_volume
*volume
, void *cookie
)
2414 OVERLAY_VOLUME_CALL(rewind_index_dir
, cookie
)
2415 return B_UNSUPPORTED
;
2420 overlay_create_index(fs_volume
*volume
, const char *name
, uint32 type
,
2423 OVERLAY_VOLUME_CALL(create_index
, name
, type
, flags
)
2424 return B_UNSUPPORTED
;
2429 overlay_remove_index(fs_volume
*volume
, const char *name
)
2431 OVERLAY_VOLUME_CALL(remove_index
, name
)
2432 return B_UNSUPPORTED
;
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
;
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
;
2454 overlay_close_query(fs_volume
*volume
, void *cookie
)
2456 OVERLAY_VOLUME_CALL(close_query
, cookie
)
2457 return B_UNSUPPORTED
;
2462 overlay_free_query_cookie(fs_volume
*volume
, void *cookie
)
2464 OVERLAY_VOLUME_CALL(free_query_cookie
, cookie
)
2465 return B_UNSUPPORTED
;
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
;
2479 overlay_rewind_query(fs_volume
*volume
, void *cookie
)
2481 OVERLAY_VOLUME_CALL(rewind_query
, cookie
)
2482 return B_UNSUPPORTED
;
2487 overlay_all_layers_mounted(fs_volume
*volume
)
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
);
2501 status_t status
= node
->InitCheck();
2502 if (status
!= B_OK
) {
2507 vnode
->private_node
= node
;
2508 vnode
->ops
= &sOverlayVnodeOps
;
2514 overlay_delete_sub_vnode(fs_volume
*volume
, fs_vnode
*vnode
)
2516 delete (OverlayInode
*)vnode
->private_node
;
2521 static fs_volume_ops sOverlayVolumeOps
= {
2524 &overlay_read_fs_info
,
2525 &overlay_write_fs_info
,
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
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
)
2563 volume
->ops
= &sOverlayVolumeOps
;
2569 overlay_std_ops(int32 op
, ...)
2573 case B_MODULE_UNINIT
:
2581 static file_system_module_info sOverlayFileSystem
= {
2583 "file_systems/write_overlay" B_CURRENT_FS_API_VERSION
,
2588 "write_overlay", // short_name
2589 "Write Overlay File System", // pretty_name
2593 NULL
, // identify_partition
2594 NULL
, // scan_partition
2595 NULL
, // free_identify_partition_cookie
2596 NULL
, // free_partition_content_cookie
2598 // general operations
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
2618 NULL
, // set_content_name
2619 NULL
, // set_content_parameters
2625 publish_overlay_vnode(fs_volume
*volume
, ino_t inodeNumber
, void *privateNode
,
2628 return publish_vnode(volume
, inodeNumber
, privateNode
, &sOverlayVnodeOps
,
2632 } // namespace write_overlay
2634 using namespace write_overlay
;
2636 module_info
*modules
[] = {
2637 (module_info
*)&sOverlayFileSystem
,