1 /*
2 * Copyright 2009-2016, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 */
8
9 #include <new>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include <dirent.h>
14
15 #include <util/kernel_cpp.h>
16 #include <util/AutoLock.h>
17
18 #include <fs_cache.h>
19 #include <fs_info.h>
20 #include <fs_interface.h>
21 #include <io_requests.h>
22
23 #include <debug.h>
24 #include <KernelExport.h>
25 #include <NodeMonitor.h>
26
27 #include "IORequest.h"
28
29
30 //#define TRACE_OVERLAY
31 #ifdef TRACE_OVERLAY
32 #define TRACE(x...) dprintf("write_overlay: " x)
33 #define TRACE_VOLUME(x...) dprintf("write_overlay: " x)
34 #define TRACE_ALWAYS(x...) dprintf("write_overlay: " x)
35 #else
36 #define TRACE(x...) /* nothing */
37 #define TRACE_VOLUME(x...) /* nothing */
38 #define TRACE_ALWAYS(x...) dprintf("write_overlay: " x)
39 #endif
40
41
42 namespace write_overlay {
43
44 status_t publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber,
45 void *privateNode, int type);
46
47 class OverlayInode;
48
49 struct open_cookie {
50 OverlayInode * node;
51 int open_mode;
52 void * super_cookie;
53 };
54
55
56 struct open_dir_cookie {
57 uint32 index;
58 };
59
60
61 struct overlay_dirent {
62 ino_t inode_number;
63 char * name;
64 OverlayInode * node; // only for attributes
65
remove_and_disposewrite_overlay::overlay_dirent66 void remove_and_dispose(fs_volume *volume, ino_t directoryInode)
67 {
68 notify_entry_removed(volume->id, directoryInode,
69 name, inode_number);
70 remove_vnode(volume, inode_number);
71 free(name);
72 free(this);
73 }
74
dispose_attributewrite_overlay::overlay_dirent75 void dispose_attribute(fs_volume *volume, ino_t fileInode)
76 {
77 notify_attribute_changed(volume->id, -1, fileInode,
78 name, B_ATTR_REMOVED);
79 free(name);
80 free(this);
81 }
82 };
83
84
85 struct write_buffer {
86 write_buffer * next;
87 off_t position;
88 size_t length;
89 uint8 buffer[1];
90 };
91
92
93 class OverlayVolume {
94 public:
95 OverlayVolume(fs_volume *volume);
96 ~OverlayVolume();
97
Volume()98 fs_volume * Volume() { return fVolume; }
SuperVolume()99 fs_volume * SuperVolume() { return fVolume->super_volume; }
100
BuildInodeNumber()101 ino_t BuildInodeNumber() { return fCurrentInodeNumber++; }
102
103 private:
104 fs_volume * fVolume;
105 ino_t fCurrentInodeNumber;
106 };
107
108
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();
118
119 status_t InitCheck();
120
Lock()121 bool Lock() { return recursive_lock_lock(&fLock) == B_OK; }
Unlock()122 void Unlock() { recursive_lock_unlock(&fLock); }
123
IsVirtual()124 bool IsVirtual() { return fIsVirtual; }
IsModified()125 bool IsModified() { return fIsModified; }
IsDataModified()126 bool IsDataModified() { return fIsDataModified; }
IsAttribute()127 bool IsAttribute() { return fIsAttribute; }
128
Volume()129 fs_volume * Volume() { return fVolume->Volume(); }
SuperVolume()130 fs_volume * SuperVolume() { return fVolume->SuperVolume(); }
131
132 void SetSuperVnode(fs_vnode *superVnode);
SuperVnode()133 fs_vnode * SuperVnode() { return &fSuperVnode; }
134
135 void SetInodeNumber(ino_t inodeNumber);
InodeNumber()136 ino_t InodeNumber() { return fInodeNumber; }
137
138 void SetModified();
139 void SetDataModified();
140 void CreateCache();
141
142 void SetParentDir(OverlayInode *parentDir);
ParentDir()143 OverlayInode * ParentDir() { return fParentDir; }
144
145 bool IsNonEmptyDirectory();
146
147 status_t Lookup(const char *name, ino_t *inodeNumber);
148 status_t LookupAttribute(const char *name,
149 OverlayInode **node);
150
151 void SetName(const char *name);
152 status_t GetName(char *buffer, size_t bufferSize);
153
154 status_t ReadStat(struct stat *stat);
155 status_t WriteStat(const struct stat *stat, uint32 statMask);
156
157 status_t Create(const char *name, int openMode, int perms,
158 void **cookie, ino_t *newInodeNumber,
159 bool attribute = false,
160 type_code attributeType = 0);
161 status_t Open(int openMode, void **cookie);
162 status_t Close(void *cookie);
163 status_t FreeCookie(void *cookie);
164 status_t Read(void *cookie, off_t position, void *buffer,
165 size_t *length, bool readPages,
166 IORequest *ioRequest);
167 status_t Write(void *cookie, off_t position,
168 const void *buffer, size_t length,
169 IORequest *request);
170
171 status_t SynchronousIO(void *cookie, IORequest *request);
172
173 status_t SetFlags(void *cookie, int flags);
174
175 status_t CreateDir(const char *name, int perms);
176 status_t RemoveDir(const char *name);
177 status_t OpenDir(void **cookie, bool attribute = false);
178 status_t CloseDir(void *cookie);
179 status_t FreeDirCookie(void *cookie);
180 status_t ReadDir(void *cookie, struct dirent *buffer,
181 size_t bufferSize, uint32 *num,
182 bool attribute = false);
183 status_t RewindDir(void *cookie);
184
185 status_t CreateSymlink(const char *name, const char *path,
186 int mode);
187 status_t ReadSymlink(char *buffer, size_t *bufferSize);
188
189 status_t AddEntry(overlay_dirent *entry,
190 bool attribute = false);
191 status_t RemoveEntry(const char *name,
192 overlay_dirent **entry, bool attribute = false);
193
194 private:
195 void _TrimBuffers();
196
197 status_t _PopulateStat();
198 status_t _PopulateDirents();
199 status_t _PopulateAttributeDirents();
200 status_t _CreateCommon(const char *name, int type, int perms,
201 ino_t *newInodeNumber, OverlayInode **node,
202 bool attribute, type_code attributeType);
203
204 recursive_lock fLock;
205 OverlayVolume * fVolume;
206 OverlayInode * fParentDir;
207 const char * fName;
208 fs_vnode fSuperVnode;
209 ino_t fInodeNumber;
210 write_buffer * fWriteBuffers;
211 off_t fOriginalNodeLength;
212 overlay_dirent ** fDirents;
213 uint32 fDirentCount;
214 overlay_dirent ** fAttributeDirents;
215 uint32 fAttributeDirentCount;
216 struct stat fStat;
217 bool fHasStat;
218 bool fHasDirents;
219 bool fHasAttributeDirents;
220 bool fIsVirtual;
221 bool fIsAttribute;
222 bool fIsModified;
223 bool fIsDataModified;
224 void * fFileCache;
225 };
226
227
228 // #pragma mark OverlayVolume
229
230
OverlayVolume(fs_volume * volume)231 OverlayVolume::OverlayVolume(fs_volume *volume)
232 : fVolume(volume),
233 fCurrentInodeNumber((ino_t)1 << 60)
234 {
235 }
236
237
~OverlayVolume()238 OverlayVolume::~OverlayVolume()
239 {
240 }
241
242
243 // #pragma mark OverlayInode
244
245
OverlayInode(OverlayVolume * volume,fs_vnode * superVnode,ino_t inodeNumber,OverlayInode * parentDir,const char * name,mode_t mode,bool attribute,type_code attributeType)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)
267 {
268 TRACE("inode created %" B_PRIdINO "\n", fInodeNumber);
269
270 recursive_lock_init(&fLock, "write overlay inode lock");
271 if (superVnode != NULL)
272 fSuperVnode = *superVnode;
273 else {
274 fStat.st_dev = SuperVolume()->id;
275 fStat.st_ino = fInodeNumber;
276 fStat.st_mode = mode;
277 fStat.st_nlink = 1;
278 fStat.st_uid = 0;
279 fStat.st_gid = 0;
280 fStat.st_size = 0;
281 fStat.st_rdev = 0;
282 fStat.st_blksize = 1024;
283 fStat.st_atime = fStat.st_mtime = fStat.st_ctime = fStat.st_crtime
284 = time(NULL);
285 fStat.st_type = attributeType;
286 fHasStat = true;
287 }
288 }
289
290
~OverlayInode()291 OverlayInode::~OverlayInode()
292 {
293 TRACE("inode destroyed %" B_PRIdINO "\n", fInodeNumber);
294 if (fFileCache != NULL)
295 file_cache_delete(fFileCache);
296
297 write_buffer *element = fWriteBuffers;
298 while (element) {
299 write_buffer *next = element->next;
300 free(element);
301 element = next;
302 }
303
304 for (uint32 i = 0; i < fDirentCount; i++) {
305 free(fDirents[i]->name);
306 free(fDirents[i]);
307 }
308 free(fDirents);
309
310 for (uint32 i = 0; i < fAttributeDirentCount; i++) {
311 free(fAttributeDirents[i]->name);
312 free(fAttributeDirents[i]);
313 }
314 free(fAttributeDirents);
315
316 recursive_lock_destroy(&fLock);
317 }
318
319
320 status_t
InitCheck()321 OverlayInode::InitCheck()
322 {
323 return B_OK;
324 }
325
326
327 void
SetSuperVnode(fs_vnode * superVnode)328 OverlayInode::SetSuperVnode(fs_vnode *superVnode)
329 {
330 RecursiveLocker locker(fLock);
331 fSuperVnode = *superVnode;
332 }
333
334
335 void
SetInodeNumber(ino_t inodeNumber)336 OverlayInode::SetInodeNumber(ino_t inodeNumber)
337 {
338 RecursiveLocker locker(fLock);
339 fInodeNumber = inodeNumber;
340 }
341
342
343 void
SetModified()344 OverlayInode::SetModified()
345 {
346 if (fIsAttribute) {
347 fIsModified = true;
348 return;
349 }
350
351 // we must ensure that a modified node never get's put, as we cannot get it
352 // from the underlying filesystem, so we get an additional reference here
353 // and deliberately leak it
354 // TODO: what about non-force unmounting then?
355 void *unused = NULL;
356 get_vnode(Volume(), fInodeNumber, &unused);
357 fIsModified = true;
358 }
359
360
361 void
SetDataModified()362 OverlayInode::SetDataModified()
363 {
364 fIsDataModified = true;
365 if (!fIsModified)
366 SetModified();
367 }
368
369
370 void
CreateCache()371 OverlayInode::CreateCache()
372 {
373 if (!S_ISDIR(fStat.st_mode) && !S_ISLNK(fStat.st_mode)) {
374 fFileCache = file_cache_create(fStat.st_dev, fStat.st_ino, 0);
375 if (fFileCache != NULL)
376 file_cache_disable(fFileCache);
377 }
378 }
379
380
381 void
SetParentDir(OverlayInode * parentDir)382 OverlayInode::SetParentDir(OverlayInode *parentDir)
383 {
384 RecursiveLocker locker(fLock);
385 fParentDir = parentDir;
386 if (fHasDirents && fDirentCount >= 2)
387 fDirents[1]->inode_number = parentDir->InodeNumber();
388 }
389
390
391 bool
IsNonEmptyDirectory()392 OverlayInode::IsNonEmptyDirectory()
393 {
394 RecursiveLocker locker(fLock);
395 if (!fHasStat)
396 _PopulateStat();
397
398 if (!S_ISDIR(fStat.st_mode))
399 return false;
400
401 if (!fHasDirents)
402 _PopulateDirents();
403
404 return fDirentCount > 2; // accounting for "." and ".." entries
405 }
406
407
408 status_t
Lookup(const char * name,ino_t * inodeNumber)409 OverlayInode::Lookup(const char *name, ino_t *inodeNumber)
410 {
411 RecursiveLocker locker(fLock);
412 if (!fHasDirents)
413 _PopulateDirents();
414
415 for (uint32 i = 0; i < fDirentCount; i++) {
416 if (strcmp(fDirents[i]->name, name) == 0) {
417 *inodeNumber = fDirents[i]->inode_number;
418 locker.Unlock();
419
420 OverlayInode *node = NULL;
421 status_t result = get_vnode(Volume(), *inodeNumber,
422 (void **)&node);
423 if (result == B_OK && node != NULL && i >= 2)
424 node->SetParentDir(this);
425 return result;
426 }
427 }
428
429 return B_ENTRY_NOT_FOUND;
430 }
431
432
433 status_t
LookupAttribute(const char * name,OverlayInode ** node)434 OverlayInode::LookupAttribute(const char *name, OverlayInode **node)
435 {
436 RecursiveLocker locker(fLock);
437 if (!fHasAttributeDirents)
438 _PopulateAttributeDirents();
439
440 for (uint32 i = 0; i < fAttributeDirentCount; i++) {
441 overlay_dirent *dirent = fAttributeDirents[i];
442 if (strcmp(dirent->name, name) == 0) {
443 if (dirent->node == NULL) {
444 OverlayInode *newNode = new(std::nothrow) OverlayInode(fVolume,
445 SuperVnode(), fInodeNumber, NULL, dirent->name, 0, true, 0);
446 if (newNode == NULL)
447 return B_NO_MEMORY;
448
449 status_t result = newNode->InitCheck();
450 if (result != B_OK) {
451 delete newNode;
452 return result;
453 }
454
455 dirent->node = newNode;
456 }
457
458 *node = dirent->node;
459 return B_OK;
460 }
461 }
462
463 return B_ENTRY_NOT_FOUND;
464 }
465
466
467 void
SetName(const char * name)468 OverlayInode::SetName(const char *name)
469 {
470 RecursiveLocker locker(fLock);
471 fName = name;
472 if (!fIsModified)
473 SetModified();
474 }
475
476
477 status_t
GetName(char * buffer,size_t bufferSize)478 OverlayInode::GetName(char *buffer, size_t bufferSize)
479 {
480 RecursiveLocker locker(fLock);
481 if (fName != NULL) {
482 strlcpy(buffer, fName, bufferSize);
483 return B_OK;
484 }
485
486 if (fIsVirtual || fIsAttribute)
487 return B_UNSUPPORTED;
488
489 if (fSuperVnode.ops->get_vnode_name == NULL)
490 return B_UNSUPPORTED;
491
492 return fSuperVnode.ops->get_vnode_name(SuperVolume(), &fSuperVnode, buffer,
493 bufferSize);
494 }
495
496
497 status_t
ReadStat(struct stat * stat)498 OverlayInode::ReadStat(struct stat *stat)
499 {
500 RecursiveLocker locker(fLock);
501 if (!fHasStat)
502 _PopulateStat();
503
504 memcpy(stat, &fStat, sizeof(struct stat));
505 stat->st_blocks = (stat->st_size + stat->st_blksize - 1) / stat->st_blksize;
506 return B_OK;
507 }
508
509
510 status_t
WriteStat(const struct stat * stat,uint32 statMask)511 OverlayInode::WriteStat(const struct stat *stat, uint32 statMask)
512 {
513 if (fIsAttribute)
514 return B_UNSUPPORTED;
515
516 RecursiveLocker locker(fLock);
517 if (!fHasStat)
518 _PopulateStat();
519
520 if (statMask & B_STAT_SIZE) {
521 if (fStat.st_size != stat->st_size) {
522 fStat.st_size = stat->st_size;
523 if (!fIsDataModified)
524 SetDataModified();
525 _TrimBuffers();
526 }
527 }
528
529 if (statMask & B_STAT_MODE)
530 fStat.st_mode = (fStat.st_mode & ~S_IUMSK) | (stat->st_mode & S_IUMSK);
531 if (statMask & B_STAT_UID)
532 fStat.st_uid = stat->st_uid;
533 if (statMask & B_STAT_GID)
534 fStat.st_gid = stat->st_gid;
535
536 if (statMask & B_STAT_MODIFICATION_TIME)
537 fStat.st_mtime = stat->st_mtime;
538 if (statMask & B_STAT_CREATION_TIME)
539 fStat.st_crtime = stat->st_crtime;
540
541 if ((statMask & (B_STAT_MODE | B_STAT_UID | B_STAT_GID)) != 0
542 && (statMask & B_STAT_MODIFICATION_TIME) == 0) {
543 fStat.st_mtime = time(NULL);
544 statMask |= B_STAT_MODIFICATION_TIME;
545 }
546
547 if (!fIsModified)
548 SetModified();
549
550 notify_stat_changed(SuperVolume()->id, -1, fInodeNumber, statMask);
551 return B_OK;
552 }
553
554
555 status_t
Create(const char * name,int openMode,int perms,void ** cookie,ino_t * newInodeNumber,bool attribute,type_code attributeType)556 OverlayInode::Create(const char *name, int openMode, int perms, void **cookie,
557 ino_t *newInodeNumber, bool attribute, type_code attributeType)
558 {
559 OverlayInode *newNode = NULL;
560 status_t result = _CreateCommon(name, attribute ? S_ATTR : S_IFREG, perms,
561 newInodeNumber, &newNode, attribute, attributeType);
562 if (result != B_OK)
563 return result;
564
565 return newNode->Open(openMode, cookie);
566 }
567
568
569 status_t
Open(int openMode,void ** _cookie)570 OverlayInode::Open(int openMode, void **_cookie)
571 {
572 RecursiveLocker locker(fLock);
573 if (!fHasStat)
574 _PopulateStat();
575
576 open_cookie *cookie = (open_cookie *)malloc(sizeof(open_cookie));
577 if (cookie == NULL)
578 return B_NO_MEMORY;
579
580 cookie->open_mode = openMode;
581 cookie->node = this;
582 *_cookie = cookie;
583
584 if (fIsVirtual) {
585 if (openMode & O_TRUNC) {
586 fStat.st_size = 0;
587 _TrimBuffers();
588 }
589
590 return B_OK;
591 }
592
593 if ((fIsAttribute && fSuperVnode.ops->open_attr == NULL)
594 || (!fIsAttribute && fSuperVnode.ops->open == NULL))
595 return B_UNSUPPORTED;
596
597 if (openMode & O_TRUNC) {
598 if (fStat.st_size != 0) {
599 fStat.st_size = 0;
600 _TrimBuffers();
601 if (!fIsDataModified)
602 SetDataModified();
603 }
604 }
605
606 openMode &= ~(O_RDWR | O_WRONLY | O_TRUNC | O_CREAT);
607 status_t result;
608 if (fIsAttribute) {
609 result = fSuperVnode.ops->open_attr(SuperVolume(), &fSuperVnode,
610 fName, openMode, &cookie->super_cookie);
611 } else {
612 result = fSuperVnode.ops->open(SuperVolume(), &fSuperVnode,
613 openMode, &cookie->super_cookie);
614 }
615
616 if (result != B_OK) {
617 free(cookie);
618 return result;
619 }
620
621 if (fOriginalNodeLength < 0) {
622 struct stat stat;
623 if (fIsAttribute) {
624 result = fSuperVnode.ops->read_attr_stat(SuperVolume(),
625 &fSuperVnode, cookie->super_cookie, &stat);
626 } else {
627 result = fSuperVnode.ops->read_stat(SuperVolume(),
628 &fSuperVnode, &stat);
629 }
630
631 if (result != B_OK)
632 return result;
633
634 fOriginalNodeLength = stat.st_size;
635 }
636
637 return B_OK;
638 }
639
640
641 status_t
Close(void * _cookie)642 OverlayInode::Close(void *_cookie)
643 {
644 if (fIsVirtual)
645 return B_OK;
646
647 open_cookie *cookie = (open_cookie *)_cookie;
648 if (fIsAttribute) {
649 return fSuperVnode.ops->close_attr(SuperVolume(), &fSuperVnode,
650 cookie->super_cookie);
651 }
652
653 return fSuperVnode.ops->close(SuperVolume(), &fSuperVnode,
654 cookie->super_cookie);
655 }
656
657
658 status_t
FreeCookie(void * _cookie)659 OverlayInode::FreeCookie(void *_cookie)
660 {
661 status_t result = B_OK;
662 open_cookie *cookie = (open_cookie *)_cookie;
663 if (!fIsVirtual) {
664 if (fIsAttribute) {
665 result = fSuperVnode.ops->free_attr_cookie(SuperVolume(),
666 &fSuperVnode, cookie->super_cookie);
667 } else {
668 result = fSuperVnode.ops->free_cookie(SuperVolume(),
669 &fSuperVnode, cookie->super_cookie);
670 }
671 }
672
673 free(cookie);
674 return result;
675 }
676
677
678 status_t
Read(void * _cookie,off_t position,void * buffer,size_t * length,bool readPages,IORequest * ioRequest)679 OverlayInode::Read(void *_cookie, off_t position, void *buffer, size_t *length,
680 bool readPages, IORequest *ioRequest)
681 {
682 RecursiveLocker locker(fLock);
683 if (position >= fStat.st_size) {
684 *length = 0;
685 return B_OK;
686 }
687
688 uint8 *pointer = (uint8 *)buffer;
689 write_buffer *element = fWriteBuffers;
690 size_t bytesLeft = (size_t)MIN(fStat.st_size - position, (off_t)*length);
691 *length = bytesLeft;
692
693 void *superCookie = _cookie;
694 if (!fIsVirtual && !readPages && _cookie != NULL)
695 superCookie = ((open_cookie *)_cookie)->super_cookie;
696
697 while (bytesLeft > 0) {
698 size_t gapSize = bytesLeft;
699 if (element != NULL) {
700 gapSize = (size_t)MIN((off_t)bytesLeft, element->position > position ?
701 element->position - position : 0);
702 }
703
704 if (gapSize > 0 && !fIsVirtual && position < fOriginalNodeLength) {
705 // there's a part missing between the read position and our
706 // next position, fill the gap with original file content
707 size_t readLength = (size_t)MIN(fOriginalNodeLength - position,
708 (off_t)gapSize);
709 status_t result = B_ERROR;
710 if (readPages) {
711 iovec vector;
712 vector.iov_base = pointer;
713 vector.iov_len = readLength;
714
715 result = fSuperVnode.ops->read_pages(SuperVolume(),
716 &fSuperVnode, superCookie, position, &vector, 1,
717 &readLength);
718 } else if (ioRequest != NULL) {
719 IORequest *subRequest;
720 result = ioRequest->CreateSubRequest(position, position,
721 readLength, subRequest);
722 if (result != B_OK)
723 return result;
724
725 bool wereSuppressed = ioRequest->SuppressChildNotifications();
726 ioRequest->SetSuppressChildNotifications(true);
727 result = fSuperVnode.ops->io(SuperVolume(), &fSuperVnode,
728 superCookie, subRequest);
729 if (result != B_OK)
730 return result;
731
732 result = subRequest->Wait(0, 0);
733 readLength = subRequest->TransferredBytes();
734 ioRequest->SetSuppressChildNotifications(wereSuppressed);
735 } else if (fIsAttribute) {
736 result = fSuperVnode.ops->read_attr(SuperVolume(), &fSuperVnode,
737 superCookie, position, pointer, &readLength);
738 } else {
739 result = fSuperVnode.ops->read(SuperVolume(), &fSuperVnode,
740 superCookie, position, pointer, &readLength);
741 }
742
743 if (result != B_OK)
744 return result;
745
746 pointer += readLength;
747 position += readLength;
748 bytesLeft -= readLength;
749 gapSize -= readLength;
750 }
751
752 if (gapSize > 0) {
753 // there's a gap before our next position which we cannot
754 // fill with original file content, zero it out
755 if (ioRequest != NULL)
756 ;// TODO: handle this case
757 else
758 user_memset(pointer, 0, gapSize);
759
760 bytesLeft -= gapSize;
761 position += gapSize;
762 pointer += gapSize;
763 }
764
765 // we've reached the end
766 if (bytesLeft == 0 || element == NULL)
767 break;
768
769 off_t elementEnd = element->position + element->length;
770 if (elementEnd > position) {
771 size_t copyLength = (size_t)MIN(elementEnd - position,
772 (off_t)bytesLeft);
773
774 const void *source = element->buffer + (position
775 - element->position);
776 if (ioRequest != NULL) {
777 ioRequest->CopyData(source, ioRequest->Offset()
778 + ((addr_t)pointer - (addr_t)buffer), copyLength);
779 } else if (user_memcpy(pointer, source, copyLength) < B_OK)
780 return B_BAD_ADDRESS;
781
782 bytesLeft -= copyLength;
783 position += copyLength;
784 pointer += copyLength;
785 }
786
787 element = element->next;
788 }
789
790 return B_OK;
791 }
792
793
794 status_t
Write(void * _cookie,off_t position,const void * buffer,size_t length,IORequest * ioRequest)795 OverlayInode::Write(void *_cookie, off_t position, const void *buffer,
796 size_t length, IORequest *ioRequest)
797 {
798 RecursiveLocker locker(fLock);
799 if (_cookie != NULL) {
800 open_cookie *cookie = (open_cookie *)_cookie;
801 if (cookie->open_mode & O_APPEND)
802 position = fStat.st_size;
803 }
804
805 if (!fIsDataModified)
806 SetDataModified();
807
808 // find insertion point
809 write_buffer **link = &fWriteBuffers;
810 write_buffer *other = fWriteBuffers;
811 write_buffer *swallow = NULL;
812 off_t newPosition = position;
813 size_t newLength = length;
814 uint32 swallowCount = 0;
815
816 while (other) {
817 off_t newEnd = newPosition + newLength;
818 off_t otherEnd = other->position + other->length;
819 if (otherEnd < newPosition) {
820 // other is completely before us
821 link = &other->next;
822 other = other->next;
823 continue;
824 }
825
826 if (other->position > newEnd) {
827 // other is completely past us
828 break;
829 }
830
831 swallowCount++;
832 if (swallow == NULL)
833 swallow = other;
834
835 if (other->position <= newPosition) {
836 if (swallowCount == 1 && otherEnd >= newEnd) {
837 // other chunk completely covers us, just copy
838 void *target = other->buffer + (newPosition - other->position);
839 if (ioRequest != NULL)
840 ioRequest->CopyData(ioRequest->Offset(), target, length);
841 else if (user_memcpy(target, buffer, length) < B_OK)
842 return B_BAD_ADDRESS;
843
844 fStat.st_mtime = time(NULL);
845 if (fIsAttribute) {
846 notify_attribute_changed(SuperVolume()->id, -1,
847 fInodeNumber, fName, B_ATTR_CHANGED);
848 } else {
849 notify_stat_changed(SuperVolume()->id, -1, fInodeNumber,
850 B_STAT_MODIFICATION_TIME);
851 }
852 return B_OK;
853 }
854
855 newLength += newPosition - other->position;
856 newPosition = other->position;
857 }
858
859 if (otherEnd > newEnd)
860 newLength += otherEnd - newEnd;
861
862 other = other->next;
863 }
864
865 write_buffer *element = (write_buffer *)malloc(sizeof(write_buffer) - 1
866 + newLength);
867 if (element == NULL)
868 return B_NO_MEMORY;
869
870 element->next = *link;
871 element->position = newPosition;
872 element->length = newLength;
873 *link = element;
874
875 bool sizeChanged = false;
876 off_t newEnd = newPosition + newLength;
877 if (newEnd > fStat.st_size) {
878 fStat.st_size = newEnd;
879 sizeChanged = true;
880
881 if (fFileCache)
882 file_cache_set_size(fFileCache, newEnd);
883 }
884
885 // populate the buffer with the existing chunks
886 if (swallowCount > 0) {
887 while (swallowCount-- > 0) {
888 memcpy(element->buffer + (swallow->position - newPosition),
889 swallow->buffer, swallow->length);
890
891 element->next = swallow->next;
892 free(swallow);
893 swallow = element->next;
894 }
895 }
896
897 void *target = element->buffer + (position - newPosition);
898 if (ioRequest != NULL)
899 ioRequest->CopyData(0, target, length);
900 else if (user_memcpy(target, buffer, length) < B_OK)
901 return B_BAD_ADDRESS;
902
903 fStat.st_mtime = time(NULL);
904
905 if (fIsAttribute) {
906 notify_attribute_changed(SuperVolume()->id, -1, fInodeNumber, fName,
907 B_ATTR_CHANGED);
908 } else {
909 notify_stat_changed(SuperVolume()->id, -1, fInodeNumber,
910 B_STAT_MODIFICATION_TIME | (sizeChanged ? B_STAT_SIZE : 0));
911 }
912
913 return B_OK;
914 }
915
916
917 status_t
SynchronousIO(void * cookie,IORequest * request)918 OverlayInode::SynchronousIO(void *cookie, IORequest *request)
919 {
920 status_t result;
921 size_t length = request->Length();
922 if (request->IsWrite())
923 result = Write(cookie, request->Offset(), NULL, length, request);
924 else
925 result = Read(cookie, request->Offset(), NULL, &length, false, request);
926
927 if (result == B_OK)
928 request->SetTransferredBytes(false, length);
929
930 request->SetStatusAndNotify(result);
931 return result;
932 }
933
934
935 status_t
SetFlags(void * _cookie,int flags)936 OverlayInode::SetFlags(void *_cookie, int flags)
937 {
938 // we can only handle O_APPEND, O_NONBLOCK is ignored.
939 open_cookie *cookie = (open_cookie *)_cookie;
940 cookie->open_mode = (cookie->open_mode & ~O_APPEND) | (flags & ~O_APPEND);
941 return B_OK;
942 }
943
944
945 status_t
CreateDir(const char * name,int perms)946 OverlayInode::CreateDir(const char *name, int perms)
947 {
948 return _CreateCommon(name, S_IFDIR, perms, NULL, NULL, false, 0);
949 }
950
951
952 status_t
RemoveDir(const char * name)953 OverlayInode::RemoveDir(const char *name)
954 {
955 return RemoveEntry(name, NULL);
956 }
957
958
959 status_t
OpenDir(void ** cookie,bool attribute)960 OverlayInode::OpenDir(void **cookie, bool attribute)
961 {
962 RecursiveLocker locker(fLock);
963 if (!attribute) {
964 if (!fHasStat)
965 _PopulateStat();
966
967 if (!S_ISDIR(fStat.st_mode))
968 return B_NOT_A_DIRECTORY;
969 }
970
971 if (!attribute && !fHasDirents)
972 _PopulateDirents();
973 else if (attribute && !fHasAttributeDirents)
974 _PopulateAttributeDirents();
975
976 open_dir_cookie *dirCookie = (open_dir_cookie *)malloc(
977 sizeof(open_dir_cookie));
978 if (dirCookie == NULL)
979 return B_NO_MEMORY;
980
981 dirCookie->index = 0;
982 *cookie = dirCookie;
983 return B_OK;
984 }
985
986
987 status_t
CloseDir(void * cookie)988 OverlayInode::CloseDir(void *cookie)
989 {
990 return B_OK;
991 }
992
993
994 status_t
FreeDirCookie(void * cookie)995 OverlayInode::FreeDirCookie(void *cookie)
996 {
997 free(cookie);
998 return B_OK;
999 }
1000
1001
1002 status_t
ReadDir(void * cookie,struct dirent * buffer,size_t bufferSize,uint32 * num,bool attribute)1003 OverlayInode::ReadDir(void *cookie, struct dirent *buffer, size_t bufferSize,
1004 uint32 *num, bool attribute)
1005 {
1006 RecursiveLocker locker(fLock);
1007 uint32 direntCount = attribute ? fAttributeDirentCount : fDirentCount;
1008 overlay_dirent **dirents = attribute ? fAttributeDirents : fDirents;
1009
1010 open_dir_cookie *dirCookie = (open_dir_cookie *)cookie;
1011 if (dirCookie->index >= direntCount) {
1012 *num = 0;
1013 return B_OK;
1014 }
1015
1016 overlay_dirent *dirent = dirents[dirCookie->index++];
1017 size_t nameLength = MIN(strlen(dirent->name),
1018 bufferSize - offsetof(struct dirent, d_name)) + 1;
1019
1020 buffer->d_dev = SuperVolume()->id;
1021 buffer->d_pdev = 0;
1022 buffer->d_ino = dirent->inode_number;
1023 buffer->d_pino = 0;
1024 buffer->d_reclen = offsetof(struct dirent, d_name) + nameLength;
1025 strlcpy(buffer->d_name, dirent->name, nameLength);
1026
1027 *num = 1;
1028 return B_OK;
1029 }
1030
1031
1032 status_t
RewindDir(void * cookie)1033 OverlayInode::RewindDir(void *cookie)
1034 {
1035 open_dir_cookie *dirCookie = (open_dir_cookie *)cookie;
1036 dirCookie->index = 0;
1037 return B_OK;
1038 }
1039
1040
1041 status_t
CreateSymlink(const char * name,const char * path,int mode)1042 OverlayInode::CreateSymlink(const char *name, const char *path, int mode)
1043 {
1044 OverlayInode *newNode = NULL;
1045 // TODO: find out why mode is ignored
1046 status_t result = _CreateCommon(name, S_IFLNK, 0777, NULL, &newNode,
1047 false, 0);
1048 if (result != B_OK)
1049 return result;
1050
1051 return newNode->Write(NULL, 0, path, strlen(path), NULL);
1052 }
1053
1054
1055 status_t
ReadSymlink(char * buffer,size_t * bufferSize)1056 OverlayInode::ReadSymlink(char *buffer, size_t *bufferSize)
1057 {
1058 if (fIsVirtual) {
1059 if (!S_ISLNK(fStat.st_mode))
1060 return B_BAD_VALUE;
1061
1062 status_t result = Read(NULL, 0, buffer, bufferSize, false, NULL);
1063 *bufferSize = fStat.st_size;
1064 return result;
1065 }
1066
1067 if (fSuperVnode.ops->read_symlink == NULL)
1068 return B_UNSUPPORTED;
1069
1070 return fSuperVnode.ops->read_symlink(SuperVolume(), &fSuperVnode, buffer,
1071 bufferSize);
1072 }
1073
1074
1075 status_t
AddEntry(overlay_dirent * entry,bool attribute)1076 OverlayInode::AddEntry(overlay_dirent *entry, bool attribute)
1077 {
1078 RecursiveLocker locker(fLock);
1079 if (!attribute && !fHasDirents)
1080 _PopulateDirents();
1081 else if (attribute && !fHasAttributeDirents)
1082 _PopulateAttributeDirents();
1083
1084 status_t result = RemoveEntry(entry->name, NULL, attribute);
1085 if (result != B_OK && result != B_ENTRY_NOT_FOUND)
1086 return B_FILE_EXISTS;
1087
1088 overlay_dirent **newDirents = (overlay_dirent **)realloc(
1089 attribute ? fAttributeDirents : fDirents,
1090 sizeof(overlay_dirent *)
1091 * ((attribute ? fAttributeDirentCount : fDirentCount) + 1));
1092 if (newDirents == NULL)
1093 return B_NO_MEMORY;
1094
1095 if (attribute) {
1096 fAttributeDirents = newDirents;
1097 fAttributeDirents[fAttributeDirentCount++] = entry;
1098 } else {
1099 fDirents = newDirents;
1100 fDirents[fDirentCount++] = entry;
1101 }
1102
1103 if (!fIsModified)
1104 SetModified();
1105
1106 return B_OK;
1107 }
1108
1109
1110 status_t
RemoveEntry(const char * name,overlay_dirent ** _entry,bool attribute)1111 OverlayInode::RemoveEntry(const char *name, overlay_dirent **_entry,
1112 bool attribute)
1113 {
1114 RecursiveLocker locker(fLock);
1115 if (!attribute && !fHasDirents)
1116 _PopulateDirents();
1117 else if (attribute && !fHasAttributeDirents)
1118 _PopulateAttributeDirents();
1119
1120 uint32 direntCount = attribute ? fAttributeDirentCount : fDirentCount;
1121 overlay_dirent **dirents = attribute ? fAttributeDirents : fDirents;
1122 for (uint32 i = 0; i < direntCount; i++) {
1123 overlay_dirent *entry = dirents[i];
1124 if (strcmp(entry->name, name) == 0) {
1125 if (_entry == NULL && !attribute) {
1126 // check for non-empty directories when trying
1127 // to dispose the entry
1128 OverlayInode *node = NULL;
1129 status_t result = get_vnode(Volume(), entry->inode_number,
1130 (void **)&node);
1131 if (result != B_OK)
1132 return result;
1133
1134 if (node->IsNonEmptyDirectory())
1135 result = B_DIRECTORY_NOT_EMPTY;
1136
1137 put_vnode(Volume(), entry->inode_number);
1138 if (result != B_OK)
1139 return result;
1140 }
1141
1142 for (uint32 j = i + 1; j < direntCount; j++)
1143 dirents[j - 1] = dirents[j];
1144
1145 if (attribute)
1146 fAttributeDirentCount--;
1147 else
1148 fDirentCount--;
1149
1150 if (_entry != NULL)
1151 *_entry = entry;
1152 else if (attribute)
1153 entry->dispose_attribute(Volume(), fInodeNumber);
1154 else
1155 entry->remove_and_dispose(Volume(), fInodeNumber);
1156
1157 if (!fIsModified)
1158 SetModified();
1159
1160 return B_OK;
1161 }
1162 }
1163
1164 return B_ENTRY_NOT_FOUND;
1165 }
1166
1167
1168 void
_TrimBuffers()1169 OverlayInode::_TrimBuffers()
1170 {
1171 // the file size has been changed and we want to trim
1172 // off everything that goes beyond the new size
1173 write_buffer **link = &fWriteBuffers;
1174 write_buffer *buffer = fWriteBuffers;
1175
1176 while (buffer != NULL) {
1177 off_t bufferEnd = buffer->position + buffer->length;
1178 if (bufferEnd > fStat.st_size)
1179 break;
1180
1181 link = &buffer->next;
1182 buffer = buffer->next;
1183 }
1184
1185 if (buffer == NULL) {
1186 // didn't find anything crossing or past the end
1187 return;
1188 }
1189
1190 if (buffer->position < fStat.st_size) {
1191 // got a crossing buffer to resize
1192 size_t newLength = fStat.st_size - buffer->position;
1193 write_buffer *newBuffer = (write_buffer *)realloc(buffer,
1194 sizeof(write_buffer) - 1 + newLength);
1195
1196 if (newBuffer != NULL) {
1197 buffer = newBuffer;
1198 *link = newBuffer;
1199 } else {
1200 // we don't really care if it worked, if it didn't we simply
1201 // keep the old buffer and reset it's size
1202 }
1203
1204 buffer->length = newLength;
1205 link = &buffer->next;
1206 buffer = buffer->next;
1207 }
1208
1209 // everything else we can throw away
1210 *link = NULL;
1211 while (buffer != NULL) {
1212 write_buffer *next = buffer->next;
1213 free(buffer);
1214 buffer = next;
1215 }
1216 }
1217
1218
1219 status_t
_PopulateStat()1220 OverlayInode::_PopulateStat()
1221 {
1222 if (fHasStat)
1223 return B_OK;
1224
1225 fHasStat = true;
1226 if (fIsAttribute) {
1227 if (fName == NULL || fSuperVnode.ops->open_attr == NULL
1228 || fSuperVnode.ops->read_attr_stat == NULL)
1229 return B_UNSUPPORTED;
1230
1231 void *cookie = NULL;
1232 status_t result = fSuperVnode.ops->open_attr(SuperVolume(),
1233 &fSuperVnode, fName, O_RDONLY, &cookie);
1234 if (result != B_OK)
1235 return result;
1236
1237 result = fSuperVnode.ops->read_attr_stat(SuperVolume(), &fSuperVnode,
1238 cookie, &fStat);
1239
1240 if (fSuperVnode.ops->close_attr != NULL)
1241 fSuperVnode.ops->close_attr(SuperVolume(), &fSuperVnode, cookie);
1242
1243 if (fSuperVnode.ops->free_attr_cookie != NULL) {
1244 fSuperVnode.ops->free_attr_cookie(SuperVolume(), &fSuperVnode,
1245 cookie);
1246 }
1247
1248 return B_OK;
1249 }
1250
1251 if (fSuperVnode.ops->read_stat == NULL)
1252 return B_UNSUPPORTED;
1253
1254 return fSuperVnode.ops->read_stat(SuperVolume(), &fSuperVnode, &fStat);
1255 }
1256
1257
1258 status_t
_PopulateDirents()1259 OverlayInode::_PopulateDirents()
1260 {
1261 if (fHasDirents)
1262 return B_OK;
1263
1264 fDirents = (overlay_dirent **)malloc(sizeof(overlay_dirent *) * 2);
1265 if (fDirents == NULL)
1266 return B_NO_MEMORY;
1267
1268 const char *names[] = { ".", ".." };
1269 ino_t inodes[] = { fInodeNumber,
1270 fParentDir != NULL ? fParentDir->InodeNumber() : 0 };
1271 for (uint32 i = 0; i < 2; i++) {
1272 fDirents[i] = (overlay_dirent *)malloc(sizeof(overlay_dirent));
1273 if (fDirents[i] == NULL)
1274 return B_NO_MEMORY;
1275
1276 fDirents[i]->inode_number = inodes[i];
1277 fDirents[i]->name = strdup(names[i]);
1278 if (fDirents[i]->name == NULL) {
1279 free(fDirents[i]);
1280 return B_NO_MEMORY;
1281 }
1282
1283 fDirentCount++;
1284 }
1285
1286 fHasDirents = true;
1287 if (fIsVirtual || fSuperVnode.ops->open_dir == NULL
1288 || fSuperVnode.ops->read_dir == NULL)
1289 return B_OK;
1290
1291 // we don't really care about errors from here on
1292 void *superCookie = NULL;
1293 status_t result = fSuperVnode.ops->open_dir(SuperVolume(),
1294 &fSuperVnode, &superCookie);
1295 if (result != B_OK)
1296 return B_OK;
1297
1298 size_t bufferSize = offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH;
1299 struct dirent *buffer = (struct dirent *)malloc(bufferSize);
1300 if (buffer == NULL)
1301 goto close_dir;
1302
1303 while (true) {
1304 uint32 num = 1;
1305 result = fSuperVnode.ops->read_dir(SuperVolume(),
1306 &fSuperVnode, superCookie, buffer, bufferSize, &num);
1307 if (result != B_OK || num == 0)
1308 break;
1309
1310 overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents,
1311 sizeof(overlay_dirent *) * (fDirentCount + num));
1312 if (newDirents == NULL) {
1313 TRACE_ALWAYS("failed to allocate storage for dirents\n");
1314 break;
1315 }
1316
1317 fDirents = newDirents;
1318 struct dirent *dirent = buffer;
1319 for (uint32 i = 0; i < num; i++) {
1320 if (strcmp(dirent->d_name, ".") != 0
1321 && strcmp(dirent->d_name, "..") != 0) {
1322 overlay_dirent *entry = (overlay_dirent *)malloc(
1323 sizeof(overlay_dirent));
1324 if (entry == NULL) {
1325 TRACE_ALWAYS("failed to allocate storage for dirent\n");
1326 break;
1327 }
1328
1329 entry->inode_number = dirent->d_ino;
1330 entry->name = strdup(dirent->d_name);
1331 if (entry->name == NULL) {
1332 TRACE_ALWAYS("failed to duplicate dirent entry name\n");
1333 free(entry);
1334 break;
1335 }
1336
1337 fDirents[fDirentCount++] = entry;
1338 }
1339
1340 dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen);
1341 }
1342 }
1343
1344 free(buffer);
1345
1346 close_dir:
1347 if (fSuperVnode.ops->close_dir != NULL)
1348 fSuperVnode.ops->close_dir(SuperVolume(), &fSuperVnode, superCookie);
1349
1350 if (fSuperVnode.ops->free_dir_cookie != NULL) {
1351 fSuperVnode.ops->free_dir_cookie(SuperVolume(), &fSuperVnode,
1352 superCookie);
1353 }
1354
1355 return B_OK;
1356 }
1357
1358
1359 status_t
_PopulateAttributeDirents()1360 OverlayInode::_PopulateAttributeDirents()
1361 {
1362 if (fHasAttributeDirents)
1363 return B_OK;
1364
1365 fHasAttributeDirents = true;
1366 if (fIsVirtual || fSuperVnode.ops->open_attr_dir == NULL
1367 || fSuperVnode.ops->read_attr_dir == NULL)
1368 return B_OK;
1369
1370 // we don't really care about errors from here on
1371 void *superCookie = NULL;
1372 status_t result = fSuperVnode.ops->open_attr_dir(SuperVolume(),
1373 &fSuperVnode, &superCookie);
1374 if (result != B_OK)
1375 return B_OK;
1376
1377 size_t bufferSize = offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH;
1378 struct dirent *buffer = (struct dirent *)malloc(bufferSize);
1379 if (buffer == NULL)
1380 goto close_attr_dir;
1381
1382 while (true) {
1383 uint32 num = 1;
1384 result = fSuperVnode.ops->read_attr_dir(SuperVolume(),
1385 &fSuperVnode, superCookie, buffer, bufferSize, &num);
1386 if (result != B_OK || num == 0)
1387 break;
1388
1389 overlay_dirent **newDirents = (overlay_dirent **)realloc(
1390 fAttributeDirents, sizeof(overlay_dirent *)
1391 * (fAttributeDirentCount + num));
1392 if (newDirents == NULL) {
1393 TRACE_ALWAYS("failed to allocate storage for attribute dirents\n");
1394 break;
1395 }
1396
1397 fAttributeDirents = newDirents;
1398 struct dirent *dirent = buffer;
1399 for (uint32 i = 0; i < num; i++) {
1400 overlay_dirent *entry = (overlay_dirent *)malloc(
1401 sizeof(overlay_dirent));
1402 if (entry == NULL) {
1403 TRACE_ALWAYS("failed to allocate storage for attr dirent\n");
1404 break;
1405 }
1406
1407 entry->node = NULL;
1408 entry->inode_number = fInodeNumber;
1409 entry->name = strdup(dirent->d_name);
1410 if (entry->name == NULL) {
1411 TRACE_ALWAYS("failed to duplicate dirent entry name\n");
1412 free(entry);
1413 break;
1414 }
1415
1416 fAttributeDirents[fAttributeDirentCount++] = entry;
1417 dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen);
1418 }
1419 }
1420
1421 free(buffer);
1422
1423 close_attr_dir:
1424 if (fSuperVnode.ops->close_attr_dir != NULL) {
1425 fSuperVnode.ops->close_attr_dir(SuperVolume(), &fSuperVnode,
1426 superCookie);
1427 }
1428
1429 if (fSuperVnode.ops->free_attr_dir_cookie != NULL) {
1430 fSuperVnode.ops->free_attr_dir_cookie(SuperVolume(), &fSuperVnode,
1431 superCookie);
1432 }
1433
1434 return B_OK;
1435 }
1436
1437
1438 status_t
_CreateCommon(const char * name,int type,int perms,ino_t * newInodeNumber,OverlayInode ** _node,bool attribute,type_code attributeType)1439 OverlayInode::_CreateCommon(const char *name, int type, int perms,
1440 ino_t *newInodeNumber, OverlayInode **_node, bool attribute,
1441 type_code attributeType)
1442 {
1443 RecursiveLocker locker(fLock);
1444 if (!fHasStat)
1445 _PopulateStat();
1446
1447 if (!attribute && !S_ISDIR(fStat.st_mode))
1448 return B_NOT_A_DIRECTORY;
1449
1450 locker.Unlock();
1451
1452 overlay_dirent *entry = (overlay_dirent *)malloc(sizeof(overlay_dirent));
1453 if (entry == NULL)
1454 return B_NO_MEMORY;
1455
1456 entry->node = NULL;
1457 entry->name = strdup(name);
1458 if (entry->name == NULL) {
1459 free(entry);
1460 return B_NO_MEMORY;
1461 }
1462
1463 if (attribute)
1464 entry->inode_number = fInodeNumber;
1465 else
1466 entry->inode_number = fVolume->BuildInodeNumber();
1467
1468 OverlayInode *node = new(std::nothrow) OverlayInode(fVolume, NULL,
1469 entry->inode_number, this, entry->name, (perms & S_IUMSK) | type
1470 | (attribute ? S_ATTR : 0), attribute, attributeType);
1471 if (node == NULL) {
1472 free(entry->name);
1473 free(entry);
1474 return B_NO_MEMORY;
1475 }
1476
1477 status_t result = AddEntry(entry, attribute);
1478 if (result != B_OK) {
1479 free(entry->name);
1480 free(entry);
1481 delete node;
1482 return result;
1483 }
1484
1485 if (!attribute) {
1486 result = publish_overlay_vnode(fVolume->Volume(), entry->inode_number,
1487 node, type);
1488 if (result != B_OK) {
1489 RemoveEntry(entry->name, NULL);
1490 delete node;
1491 return result;
1492 }
1493 } else
1494 entry->node = node;
1495
1496 node->Lock();
1497 node->SetDataModified();
1498 if (!attribute)
1499 node->CreateCache();
1500 node->Unlock();
1501
1502 if (newInodeNumber != NULL)
1503 *newInodeNumber = entry->inode_number;
1504 if (_node != NULL)
1505 *_node = node;
1506
1507 if (attribute) {
1508 notify_attribute_changed(SuperVolume()->id, -1, fInodeNumber,
1509 entry->name, B_ATTR_CREATED);
1510 } else {
1511 notify_entry_created(SuperVolume()->id, fInodeNumber, entry->name,
1512 entry->inode_number);
1513 }
1514
1515 return B_OK;
1516 }
1517
1518
1519 // #pragma mark - vnode ops
1520
1521
1522 #define OVERLAY_CALL(op, params...) \
1523 TRACE("relaying op: " #op "\n"); \
1524 OverlayInode *node = (OverlayInode *)vnode->private_node; \
1525 if (node->IsVirtual()) \
1526 return B_UNSUPPORTED; \
1527 fs_vnode *superVnode = node->SuperVnode(); \
1528 if (superVnode->ops->op != NULL) \
1529 return superVnode->ops->op(volume->super_volume, superVnode, params); \
1530 return B_UNSUPPORTED;
1531
1532
1533 static status_t
overlay_put_vnode(fs_volume * volume,fs_vnode * vnode,bool reenter)1534 overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1535 {
1536 TRACE("put_vnode\n");
1537 OverlayInode *node = (OverlayInode *)vnode->private_node;
1538 if (node->IsVirtual() || node->IsModified()) {
1539 panic("loosing virtual/modified node\n");
1540 delete node;
1541 return B_OK;
1542 }
1543
1544 status_t result = B_OK;
1545 fs_vnode *superVnode = node->SuperVnode();
1546 if (superVnode->ops->put_vnode != NULL) {
1547 result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
1548 reenter);
1549 }
1550
1551 delete node;
1552 return result;
1553 }
1554
1555
1556 static status_t
overlay_remove_vnode(fs_volume * volume,fs_vnode * vnode,bool reenter)1557 overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
1558 {
1559 TRACE("remove_vnode\n");
1560 OverlayInode *node = (OverlayInode *)vnode->private_node;
1561 if (node->IsVirtual()) {
1562 delete node;
1563 return B_OK;
1564 }
1565
1566 status_t result = B_OK;
1567 fs_vnode *superVnode = node->SuperVnode();
1568 if (superVnode->ops->put_vnode != NULL) {
1569 result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
1570 reenter);
1571 }
1572
1573 delete node;
1574 return result;
1575 }
1576
1577
1578 static status_t
overlay_get_super_vnode(fs_volume * volume,fs_vnode * vnode,fs_volume * superVolume,fs_vnode * _superVnode)1579 overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode,
1580 fs_volume *superVolume, fs_vnode *_superVnode)
1581 {
1582 if (volume == superVolume) {
1583 *_superVnode = *vnode;
1584 return B_OK;
1585 }
1586
1587 OverlayInode *node = (OverlayInode *)vnode->private_node;
1588 if (node->IsVirtual()) {
1589 *_superVnode = *vnode;
1590 return B_OK;
1591 }
1592
1593 fs_vnode *superVnode = node->SuperVnode();
1594 if (superVnode->ops->get_super_vnode != NULL) {
1595 return superVnode->ops->get_super_vnode(volume->super_volume,
1596 superVnode, superVolume, _superVnode);
1597 }
1598
1599 *_superVnode = *superVnode;
1600 return B_OK;
1601 }
1602
1603
1604 static status_t
overlay_lookup(fs_volume * volume,fs_vnode * vnode,const char * name,ino_t * id)1605 overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id)
1606 {
1607 TRACE("lookup: \"%s\"\n", name);
1608 return ((OverlayInode *)vnode->private_node)->Lookup(name, id);
1609 }
1610
1611
1612 static status_t
overlay_get_vnode_name(fs_volume * volume,fs_vnode * vnode,char * buffer,size_t bufferSize)1613 overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer,
1614 size_t bufferSize)
1615 {
1616 return ((OverlayInode *)vnode->private_node)->GetName(buffer, bufferSize);
1617 }
1618
1619
1620 static bool
overlay_can_page(fs_volume * volume,fs_vnode * vnode,void * cookie)1621 overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie)
1622 {
1623 TRACE("relaying op: can_page\n");
1624 OverlayInode *node = (OverlayInode *)vnode->private_node;
1625 if (node->IsVirtual())
1626 return false;
1627
1628 fs_vnode *superVnode = node->SuperVnode();
1629 if (superVnode->ops->can_page != NULL) {
1630 return superVnode->ops->can_page(volume->super_volume, superVnode,
1631 cookie);
1632 }
1633
1634 return false;
1635 }
1636
1637
1638 static status_t
overlay_read_pages(fs_volume * volume,fs_vnode * vnode,void * cookie,off_t pos,const iovec * vecs,size_t count,size_t * numBytes)1639 overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1640 const iovec *vecs, size_t count, size_t *numBytes)
1641 {
1642 OverlayInode *node = (OverlayInode *)vnode->private_node;
1643 size_t bytesLeft = *numBytes;
1644
1645 for (size_t i = 0; i < count; i++) {
1646 size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft);
1647 status_t result = node->Read(cookie, pos, vecs[i].iov_base,
1648 &transferBytes, true, NULL);
1649 if (result != B_OK) {
1650 *numBytes -= bytesLeft;
1651 return result;
1652 }
1653
1654 bytesLeft -= transferBytes;
1655 if (bytesLeft == 0)
1656 return B_OK;
1657
1658 if (transferBytes < vecs[i].iov_len) {
1659 *numBytes -= bytesLeft;
1660 return B_OK;
1661 }
1662
1663 pos += transferBytes;
1664 }
1665
1666 *numBytes = 0;
1667 return B_OK;
1668 }
1669
1670
1671 static status_t
overlay_write_pages(fs_volume * volume,fs_vnode * vnode,void * cookie,off_t pos,const iovec * vecs,size_t count,size_t * numBytes)1672 overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1673 const iovec *vecs, size_t count, size_t *numBytes)
1674 {
1675 OverlayInode *node = (OverlayInode *)vnode->private_node;
1676 size_t bytesLeft = *numBytes;
1677
1678 for (size_t i = 0; i < count; i++) {
1679 size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft);
1680 status_t result = node->Write(cookie, pos, vecs[i].iov_base,
1681 transferBytes, NULL);
1682 if (result != B_OK) {
1683 *numBytes -= bytesLeft;
1684 return result;
1685 }
1686
1687 bytesLeft -= transferBytes;
1688 if (bytesLeft == 0)
1689 return B_OK;
1690
1691 if (transferBytes < vecs[i].iov_len) {
1692 *numBytes -= bytesLeft;
1693 return B_OK;
1694 }
1695
1696 pos += transferBytes;
1697 }
1698
1699 *numBytes = 0;
1700 return B_OK;
1701 }
1702
1703
1704 static status_t
overlay_io(fs_volume * volume,fs_vnode * vnode,void * cookie,io_request * request)1705 overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1706 io_request *request)
1707 {
1708 OverlayInode *node = (OverlayInode *)vnode->private_node;
1709 if (io_request_is_write(request) || node->IsModified())
1710 return node->SynchronousIO(cookie, (IORequest *)request);
1711
1712 TRACE("relaying op: io\n");
1713 fs_vnode *superVnode = node->SuperVnode();
1714 if (superVnode->ops->io != NULL) {
1715 return superVnode->ops->io(volume->super_volume, superVnode,
1716 cookie != NULL ? ((open_cookie *)cookie)->super_cookie : NULL,
1717 request);
1718 }
1719
1720 return B_UNSUPPORTED;
1721 }
1722
1723
1724 static status_t
overlay_cancel_io(fs_volume * volume,fs_vnode * vnode,void * cookie,io_request * request)1725 overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
1726 io_request *request)
1727 {
1728 OVERLAY_CALL(cancel_io, cookie, request)
1729 }
1730
1731
1732 static status_t
overlay_get_file_map(fs_volume * volume,fs_vnode * vnode,off_t offset,size_t size,struct file_io_vec * vecs,size_t * count)1733 overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset,
1734 size_t size, struct file_io_vec *vecs, size_t *count)
1735 {
1736 OVERLAY_CALL(get_file_map, offset, size, vecs, count)
1737 }
1738
1739
1740 static status_t
overlay_ioctl(fs_volume * volume,fs_vnode * vnode,void * cookie,uint32 op,void * buffer,size_t length)1741 overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op,
1742 void *buffer, size_t length)
1743 {
1744 OVERLAY_CALL(ioctl, cookie, op, buffer, length)
1745 }
1746
1747
1748 static status_t
overlay_set_flags(fs_volume * volume,fs_vnode * vnode,void * cookie,int flags)1749 overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie,
1750 int flags)
1751 {
1752 return ((OverlayInode *)vnode->private_node)->SetFlags(cookie, flags);
1753 }
1754
1755
1756 static status_t
overlay_select(fs_volume * volume,fs_vnode * vnode,void * cookie,uint8 event,selectsync * sync)1757 overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1758 selectsync *sync)
1759 {
1760 OVERLAY_CALL(select, cookie, event, sync)
1761 }
1762
1763
1764 static status_t
overlay_deselect(fs_volume * volume,fs_vnode * vnode,void * cookie,uint8 event,selectsync * sync)1765 overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
1766 selectsync *sync)
1767 {
1768 OVERLAY_CALL(deselect, cookie, event, sync)
1769 }
1770
1771
1772 static status_t
overlay_fsync(fs_volume * volume,fs_vnode * vnode)1773 overlay_fsync(fs_volume *volume, fs_vnode *vnode)
1774 {
1775 return B_OK;
1776 }
1777
1778
1779 static status_t
overlay_read_symlink(fs_volume * volume,fs_vnode * vnode,char * buffer,size_t * bufferSize)1780 overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer,
1781 size_t *bufferSize)
1782 {
1783 TRACE("read_symlink\n");
1784 return ((OverlayInode *)vnode->private_node)->ReadSymlink(buffer,
1785 bufferSize);
1786 }
1787
1788
1789 static status_t
overlay_create_symlink(fs_volume * volume,fs_vnode * vnode,const char * name,const char * path,int mode)1790 overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name,
1791 const char *path, int mode)
1792 {
1793 TRACE("create_symlink: \"%s\" -> \"%s\"\n", name, path);
1794 return ((OverlayInode *)vnode->private_node)->CreateSymlink(name, path,
1795 mode);
1796 }
1797
1798
1799 static status_t
overlay_link(fs_volume * volume,fs_vnode * vnode,const char * name,fs_vnode * target)1800 overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name,
1801 fs_vnode *target)
1802 {
1803 return B_UNSUPPORTED;
1804 }
1805
1806
1807 static status_t
overlay_unlink(fs_volume * volume,fs_vnode * vnode,const char * name)1808 overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name)
1809 {
1810 TRACE("unlink: \"%s\"\n", name);
1811 return ((OverlayInode *)vnode->private_node)->RemoveEntry(name, NULL);
1812 }
1813
1814
1815 static status_t
overlay_rename(fs_volume * volume,fs_vnode * vnode,const char * fromName,fs_vnode * toVnode,const char * toName)1816 overlay_rename(fs_volume *volume, fs_vnode *vnode,
1817 const char *fromName, fs_vnode *toVnode, const char *toName)
1818 {
1819 TRACE("rename: \"%s\" -> \"%s\"\n", fromName, toName);
1820 OverlayInode *fromNode = (OverlayInode *)vnode->private_node;
1821 OverlayInode *toNode = (OverlayInode *)toVnode->private_node;
1822 overlay_dirent *entry = NULL;
1823
1824 status_t result = fromNode->RemoveEntry(fromName, &entry);
1825 if (result != B_OK)
1826 return result;
1827
1828 char *oldName = entry->name;
1829 entry->name = strdup(toName);
1830 if (entry->name == NULL) {
1831 entry->name = oldName;
1832 if (fromNode->AddEntry(entry) != B_OK)
1833 entry->remove_and_dispose(volume, fromNode->InodeNumber());
1834
1835 return B_NO_MEMORY;
1836 }
1837
1838 result = toNode->AddEntry(entry);
1839 if (result != B_OK) {
1840 free(entry->name);
1841 entry->name = oldName;
1842 if (fromNode->AddEntry(entry) != B_OK)
1843 entry->remove_and_dispose(volume, fromNode->InodeNumber());
1844
1845 return result;
1846 }
1847
1848 OverlayInode *node = NULL;
1849 result = get_vnode(volume, entry->inode_number, (void **)&node);
1850 if (result == B_OK && node != NULL) {
1851 node->SetName(entry->name);
1852 node->SetParentDir(toNode);
1853 put_vnode(volume, entry->inode_number);
1854 }
1855
1856 free(oldName);
1857 notify_entry_moved(volume->id, fromNode->InodeNumber(), fromName,
1858 toNode->InodeNumber(), toName, entry->inode_number);
1859 return B_OK;
1860 }
1861
1862
1863 static status_t
overlay_access(fs_volume * volume,fs_vnode * vnode,int mode)1864 overlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
1865 {
1866 // TODO: implement
1867 return B_OK;
1868 }
1869
1870
1871 static status_t
overlay_read_stat(fs_volume * volume,fs_vnode * vnode,struct stat * stat)1872 overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat)
1873 {
1874 TRACE("read_stat\n");
1875 return ((OverlayInode *)vnode->private_node)->ReadStat(stat);
1876 }
1877
1878
1879 static status_t
overlay_write_stat(fs_volume * volume,fs_vnode * vnode,const struct stat * stat,uint32 statMask)1880 overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat,
1881 uint32 statMask)
1882 {
1883 TRACE("write_stat\n");
1884 return ((OverlayInode *)vnode->private_node)->WriteStat(stat, statMask);
1885 }
1886
1887
1888 static status_t
overlay_create(fs_volume * volume,fs_vnode * vnode,const char * name,int openMode,int perms,void ** cookie,ino_t * newVnodeID)1889 overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name,
1890 int openMode, int perms, void **cookie, ino_t *newVnodeID)
1891 {
1892 TRACE("create: \"%s\"\n", name);
1893 return ((OverlayInode *)vnode->private_node)->Create(name, openMode,
1894 perms, cookie, newVnodeID);
1895 }
1896
1897
1898 static status_t
overlay_open(fs_volume * volume,fs_vnode * vnode,int openMode,void ** cookie)1899 overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie)
1900 {
1901 TRACE("open\n");
1902 return ((OverlayInode *)vnode->private_node)->Open(openMode, cookie);
1903 }
1904
1905
1906 static status_t
overlay_close(fs_volume * volume,fs_vnode * vnode,void * cookie)1907 overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie)
1908 {
1909 TRACE("close\n");
1910 return ((OverlayInode *)vnode->private_node)->Close(cookie);
1911 }
1912
1913
1914 static status_t
overlay_free_cookie(fs_volume * volume,fs_vnode * vnode,void * cookie)1915 overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1916 {
1917 TRACE("free_cookie\n");
1918 return ((OverlayInode *)vnode->private_node)->FreeCookie(cookie);
1919 }
1920
1921
1922 static status_t
overlay_read(fs_volume * volume,fs_vnode * vnode,void * cookie,off_t pos,void * buffer,size_t * length)1923 overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1924 void *buffer, size_t *length)
1925 {
1926 TRACE("read\n");
1927 return ((OverlayInode *)vnode->private_node)->Read(cookie, pos, buffer,
1928 length, false, NULL);
1929 }
1930
1931
1932 static status_t
overlay_write(fs_volume * volume,fs_vnode * vnode,void * cookie,off_t pos,const void * buffer,size_t * length)1933 overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
1934 const void *buffer, size_t *length)
1935 {
1936 TRACE("write\n");
1937 return ((OverlayInode *)vnode->private_node)->Write(cookie, pos, buffer,
1938 *length, NULL);
1939 }
1940
1941
1942 static status_t
overlay_create_dir(fs_volume * volume,fs_vnode * vnode,const char * name,int perms)1943 overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name,
1944 int perms)
1945 {
1946 TRACE("create_dir: \"%s\"\n", name);
1947 return ((OverlayInode *)vnode->private_node)->CreateDir(name, perms);
1948 }
1949
1950
1951 static status_t
overlay_remove_dir(fs_volume * volume,fs_vnode * vnode,const char * name)1952 overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name)
1953 {
1954 TRACE("remove_dir: \"%s\"\n", name);
1955 return ((OverlayInode *)vnode->private_node)->RemoveDir(name);
1956 }
1957
1958
1959 static status_t
overlay_open_dir(fs_volume * volume,fs_vnode * vnode,void ** cookie)1960 overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
1961 {
1962 TRACE("open_dir\n");
1963 return ((OverlayInode *)vnode->private_node)->OpenDir(cookie);
1964 }
1965
1966
1967 static status_t
overlay_close_dir(fs_volume * volume,fs_vnode * vnode,void * cookie)1968 overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1969 {
1970 TRACE("close_dir\n");
1971 return ((OverlayInode *)vnode->private_node)->CloseDir(cookie);
1972 }
1973
1974
1975 static status_t
overlay_free_dir_cookie(fs_volume * volume,fs_vnode * vnode,void * cookie)1976 overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
1977 {
1978 TRACE("free_dir_cookie\n");
1979 return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie);
1980 }
1981
1982
1983 static status_t
overlay_read_dir(fs_volume * volume,fs_vnode * vnode,void * cookie,struct dirent * buffer,size_t bufferSize,uint32 * num)1984 overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
1985 struct dirent *buffer, size_t bufferSize, uint32 *num)
1986 {
1987 TRACE("read_dir\n");
1988 return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer,
1989 bufferSize, num);
1990 }
1991
1992
1993 static status_t
overlay_rewind_dir(fs_volume * volume,fs_vnode * vnode,void * cookie)1994 overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
1995 {
1996 TRACE("rewind_dir\n");
1997 return ((OverlayInode *)vnode->private_node)->RewindDir(cookie);
1998 }
1999
2000
2001 static status_t
overlay_open_attr_dir(fs_volume * volume,fs_vnode * vnode,void ** cookie)2002 overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
2003 {
2004 TRACE("open_attr_dir\n");
2005 return ((OverlayInode *)vnode->private_node)->OpenDir(cookie, true);
2006 }
2007
2008
2009 static status_t
overlay_close_attr_dir(fs_volume * volume,fs_vnode * vnode,void * cookie)2010 overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
2011 {
2012 TRACE("close_attr_dir\n");
2013 return ((OverlayInode *)vnode->private_node)->CloseDir(cookie);
2014 }
2015
2016
2017 static status_t
overlay_free_attr_dir_cookie(fs_volume * volume,fs_vnode * vnode,void * cookie)2018 overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
2019 {
2020 TRACE("free_attr_dir_cookie\n");
2021 return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie);
2022 }
2023
2024
2025 static status_t
overlay_read_attr_dir(fs_volume * volume,fs_vnode * vnode,void * cookie,struct dirent * buffer,size_t bufferSize,uint32 * num)2026 overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
2027 struct dirent *buffer, size_t bufferSize, uint32 *num)
2028 {
2029 TRACE("read_attr_dir\n");
2030 return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer,
2031 bufferSize, num, true);
2032 }
2033
2034
2035 static status_t
overlay_rewind_attr_dir(fs_volume * volume,fs_vnode * vnode,void * cookie)2036 overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
2037 {
2038 TRACE("rewind_attr_dir\n");
2039 return ((OverlayInode *)vnode->private_node)->RewindDir(cookie);
2040 }
2041
2042
2043 static status_t
overlay_create_attr(fs_volume * volume,fs_vnode * vnode,const char * name,uint32 type,int openMode,void ** cookie)2044 overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
2045 uint32 type, int openMode, void **cookie)
2046 {
2047 TRACE("create_attr\n");
2048 return ((OverlayInode *)vnode->private_node)->Create(name, openMode, 0,
2049 cookie, NULL, true, type);
2050 }
2051
2052
2053 static status_t
overlay_open_attr(fs_volume * volume,fs_vnode * vnode,const char * name,int openMode,void ** cookie)2054 overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
2055 int openMode, void **cookie)
2056 {
2057 TRACE("open_attr\n");
2058 OverlayInode *node = NULL;
2059 OverlayInode *parentNode = (OverlayInode *)vnode->private_node;
2060 status_t result = parentNode->LookupAttribute(name, &node);
2061 if (result != B_OK)
2062 return result;
2063 if (node == NULL)
2064 return B_ERROR;
2065
2066 return node->Open(openMode, cookie);
2067 }
2068
2069
2070 static status_t
overlay_close_attr(fs_volume * volume,fs_vnode * vnode,void * _cookie)2071 overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie)
2072 {
2073 TRACE("close_attr\n");
2074 open_cookie *cookie = (open_cookie *)_cookie;
2075 return cookie->node->Close(cookie);
2076 }
2077
2078
2079 static status_t
overlay_free_attr_cookie(fs_volume * volume,fs_vnode * vnode,void * _cookie)2080 overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *_cookie)
2081 {
2082 TRACE("free_attr_cookie\n");
2083 open_cookie *cookie = (open_cookie *)_cookie;
2084 return cookie->node->FreeCookie(cookie);
2085 }
2086
2087
2088 static status_t
overlay_read_attr(fs_volume * volume,fs_vnode * vnode,void * _cookie,off_t pos,void * buffer,size_t * length)2089 overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos,
2090 void *buffer, size_t *length)
2091 {
2092 TRACE("read_attr\n");
2093 open_cookie *cookie = (open_cookie *)_cookie;
2094 return cookie->node->Read(cookie, pos, buffer, length, false, NULL);
2095 }
2096
2097
2098 static status_t
overlay_write_attr(fs_volume * volume,fs_vnode * vnode,void * _cookie,off_t pos,const void * buffer,size_t * length)2099 overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos,
2100 const void *buffer, size_t *length)
2101 {
2102 TRACE("write_attr\n");
2103 open_cookie *cookie = (open_cookie *)_cookie;
2104 return cookie->node->Write(cookie, pos, buffer, *length, NULL);
2105 }
2106
2107
2108 static status_t
overlay_read_attr_stat(fs_volume * volume,fs_vnode * vnode,void * _cookie,struct stat * stat)2109 overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie,
2110 struct stat *stat)
2111 {
2112 TRACE("read_attr_stat\n");
2113 open_cookie *cookie = (open_cookie *)_cookie;
2114 return cookie->node->ReadStat(stat);
2115 }
2116
2117
2118 static status_t
overlay_write_attr_stat(fs_volume * volume,fs_vnode * vnode,void * _cookie,const struct stat * stat,int statMask)2119 overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie,
2120 const struct stat *stat, int statMask)
2121 {
2122 TRACE("write_attr_stat\n");
2123 open_cookie *cookie = (open_cookie *)_cookie;
2124 return cookie->node->WriteStat(stat, statMask);
2125 }
2126
2127
2128 static status_t
overlay_rename_attr(fs_volume * volume,fs_vnode * vnode,const char * fromName,fs_vnode * toVnode,const char * toName)2129 overlay_rename_attr(fs_volume *volume, fs_vnode *vnode,
2130 const char *fromName, fs_vnode *toVnode, const char *toName)
2131 {
2132 TRACE("rename attr: \"%s\" -> \"%s\"\n", fromName, toName);
2133 OverlayInode *fromNode = (OverlayInode *)vnode->private_node;
2134 OverlayInode *toNode = (OverlayInode *)toVnode->private_node;
2135 overlay_dirent *entry = NULL;
2136
2137 status_t result = fromNode->RemoveEntry(fromName, &entry, true);
2138 if (result != B_OK)
2139 return result;
2140
2141 char *oldName = entry->name;
2142 entry->name = strdup(toName);
2143 if (entry->name == NULL) {
2144 entry->name = oldName;
2145 if (fromNode->AddEntry(entry, true) != B_OK)
2146 entry->dispose_attribute(volume, fromNode->InodeNumber());
2147
2148 return B_NO_MEMORY;
2149 }
2150
2151 result = toNode->AddEntry(entry, true);
2152 if (result != B_OK) {
2153 free(entry->name);
2154 entry->name = oldName;
2155 if (fromNode->AddEntry(entry, true) != B_OK)
2156 entry->dispose_attribute(volume, fromNode->InodeNumber());
2157
2158 return result;
2159 }
2160
2161 OverlayInode *node = entry->node;
2162 if (node == NULL)
2163 return B_ERROR;
2164
2165 node->SetName(entry->name);
2166 node->SetSuperVnode(toNode->SuperVnode());
2167 node->SetInodeNumber(toNode->InodeNumber());
2168
2169 notify_attribute_changed(volume->id, -1, fromNode->InodeNumber(), fromName,
2170 B_ATTR_REMOVED);
2171 notify_attribute_changed(volume->id, -1, toNode->InodeNumber(), toName,
2172 B_ATTR_CREATED);
2173
2174 free(oldName);
2175 return B_OK;
2176 }
2177
2178
2179 static status_t
overlay_remove_attr(fs_volume * volume,fs_vnode * vnode,const char * name)2180 overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name)
2181 {
2182 TRACE("remove_attr\n");
2183 OverlayInode *node = (OverlayInode *)vnode->private_node;
2184 status_t result = node->RemoveEntry(name, NULL, true);
2185 if (result != B_OK)
2186 return result;
2187
2188 notify_attribute_changed(volume->id, -1, node->InodeNumber(), name,
2189 B_ATTR_REMOVED);
2190 return result;
2191 }
2192
2193
2194 static status_t
overlay_create_special_node(fs_volume * volume,fs_vnode * vnode,const char * name,fs_vnode * subVnode,mode_t mode,uint32 flags,fs_vnode * _superVnode,ino_t * nodeID)2195 overlay_create_special_node(fs_volume *volume, fs_vnode *vnode,
2196 const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags,
2197 fs_vnode *_superVnode, ino_t *nodeID)
2198 {
2199 OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, nodeID)
2200 }
2201
2202
2203 static fs_vnode_ops sOverlayVnodeOps = {
2204 &overlay_lookup,
2205 &overlay_get_vnode_name,
2206
2207 &overlay_put_vnode,
2208 &overlay_remove_vnode,
2209
2210 &overlay_can_page,
2211 &overlay_read_pages,
2212 &overlay_write_pages,
2213
2214 &overlay_io,
2215 &overlay_cancel_io,
2216
2217 &overlay_get_file_map,
2218
2219 /* common */
2220 &overlay_ioctl,
2221 &overlay_set_flags,
2222 &overlay_select,
2223 &overlay_deselect,
2224 &overlay_fsync,
2225
2226 &overlay_read_symlink,
2227 &overlay_create_symlink,
2228 &overlay_link,
2229 &overlay_unlink,
2230 &overlay_rename,
2231
2232 &overlay_access,
2233 &overlay_read_stat,
2234 &overlay_write_stat,
2235 NULL, // fs_preallocate
2236
2237 /* file */
2238 &overlay_create,
2239 &overlay_open,
2240 &overlay_close,
2241 &overlay_free_cookie,
2242 &overlay_read,
2243 &overlay_write,
2244
2245 /* directory */
2246 &overlay_create_dir,
2247 &overlay_remove_dir,
2248 &overlay_open_dir,
2249 &overlay_close_dir,
2250 &overlay_free_dir_cookie,
2251 &overlay_read_dir,
2252 &overlay_rewind_dir,
2253
2254 /* attribute directory operations */
2255 &overlay_open_attr_dir,
2256 &overlay_close_attr_dir,
2257 &overlay_free_attr_dir_cookie,
2258 &overlay_read_attr_dir,
2259 &overlay_rewind_attr_dir,
2260
2261 /* attribute operations */
2262 &overlay_create_attr,
2263 &overlay_open_attr,
2264 &overlay_close_attr,
2265 &overlay_free_attr_cookie,
2266 &overlay_read_attr,
2267 &overlay_write_attr,
2268
2269 &overlay_read_attr_stat,
2270 &overlay_write_attr_stat,
2271 &overlay_rename_attr,
2272 &overlay_remove_attr,
2273
2274 /* support for node and FS layers */
2275 &overlay_create_special_node,
2276 &overlay_get_super_vnode
2277 };
2278
2279
2280 // #pragma mark - volume ops
2281
2282
2283 #define OVERLAY_VOLUME_CALL(op, params...) \
2284 TRACE_VOLUME("relaying volume op: " #op "\n"); \
2285 if (volume->super_volume->ops->op != NULL) \
2286 return volume->super_volume->ops->op(volume->super_volume, params);
2287
2288
2289 static status_t
overlay_unmount(fs_volume * volume)2290 overlay_unmount(fs_volume *volume)
2291 {
2292 TRACE_VOLUME("relaying volume op: unmount\n");
2293 if (volume->super_volume != NULL
2294 && volume->super_volume->ops != NULL
2295 && volume->super_volume->ops->unmount != NULL)
2296 volume->super_volume->ops->unmount(volume->super_volume);
2297
2298 delete (OverlayVolume *)volume->private_volume;
2299 return B_OK;
2300 }
2301
2302
2303 static status_t
overlay_read_fs_info(fs_volume * volume,struct fs_info * info)2304 overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
2305 {
2306 TRACE_VOLUME("relaying volume op: read_fs_info\n");
2307 status_t result = B_UNSUPPORTED;
2308 if (volume->super_volume->ops->read_fs_info != NULL) {
2309 result = volume->super_volume->ops->read_fs_info(volume->super_volume,
2310 info);
2311 if (result != B_OK)
2312 return result;
2313
2314 info->flags &= ~B_FS_IS_READONLY;
2315
2316 // TODO: maybe calculate based on available ram
2317 off_t available = 1024 * 1024 * 100 / info->block_size;
2318 info->total_blocks += available;
2319 info->free_blocks += available;
2320 return B_OK;
2321 }
2322
2323 return B_UNSUPPORTED;
2324 }
2325
2326
2327 static status_t
overlay_write_fs_info(fs_volume * volume,const struct fs_info * info,uint32 mask)2328 overlay_write_fs_info(fs_volume *volume, const struct fs_info *info,
2329 uint32 mask)
2330 {
2331 OVERLAY_VOLUME_CALL(write_fs_info, info, mask)
2332 return B_UNSUPPORTED;
2333 }
2334
2335
2336 static status_t
overlay_sync(fs_volume * volume)2337 overlay_sync(fs_volume *volume)
2338 {
2339 TRACE_VOLUME("relaying volume op: sync\n");
2340 if (volume->super_volume->ops->sync != NULL)
2341 return volume->super_volume->ops->sync(volume->super_volume);
2342 return B_UNSUPPORTED;
2343 }
2344
2345
2346 static status_t
overlay_get_vnode(fs_volume * volume,ino_t id,fs_vnode * vnode,int * _type,uint32 * _flags,bool reenter)2347 overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type,
2348 uint32 *_flags, bool reenter)
2349 {
2350 TRACE_VOLUME("relaying volume op: get_vnode\n");
2351 if (volume->super_volume->ops->get_vnode != NULL) {
2352 status_t status = volume->super_volume->ops->get_vnode(
2353 volume->super_volume, id, vnode, _type, _flags, reenter);
2354 if (status != B_OK)
2355 return status;
2356
2357 OverlayInode *node = new(std::nothrow) OverlayInode(
2358 (OverlayVolume *)volume->private_volume, vnode, id);
2359 if (node == NULL) {
2360 vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
2361 return B_NO_MEMORY;
2362 }
2363
2364 status = node->InitCheck();
2365 if (status != B_OK) {
2366 vnode->ops->put_vnode(volume->super_volume, vnode, reenter);
2367 delete node;
2368 return status;
2369 }
2370
2371 vnode->private_node = node;
2372 vnode->ops = &sOverlayVnodeOps;
2373 return B_OK;
2374 }
2375
2376 return B_UNSUPPORTED;
2377 }
2378
2379
2380 static status_t
overlay_open_index_dir(fs_volume * volume,void ** cookie)2381 overlay_open_index_dir(fs_volume *volume, void **cookie)
2382 {
2383 OVERLAY_VOLUME_CALL(open_index_dir, cookie)
2384 return B_UNSUPPORTED;
2385 }
2386
2387
2388 static status_t
overlay_close_index_dir(fs_volume * volume,void * cookie)2389 overlay_close_index_dir(fs_volume *volume, void *cookie)
2390 {
2391 OVERLAY_VOLUME_CALL(close_index_dir, cookie)
2392 return B_UNSUPPORTED;
2393 }
2394
2395
2396 static status_t
overlay_free_index_dir_cookie(fs_volume * volume,void * cookie)2397 overlay_free_index_dir_cookie(fs_volume *volume, void *cookie)
2398 {
2399 OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie)
2400 return B_UNSUPPORTED;
2401 }
2402
2403
2404 static status_t
overlay_read_index_dir(fs_volume * volume,void * cookie,struct dirent * buffer,size_t bufferSize,uint32 * _num)2405 overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer,
2406 size_t bufferSize, uint32 *_num)
2407 {
2408 OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num)
2409 return B_UNSUPPORTED;
2410 }
2411
2412
2413 static status_t
overlay_rewind_index_dir(fs_volume * volume,void * cookie)2414 overlay_rewind_index_dir(fs_volume *volume, void *cookie)
2415 {
2416 OVERLAY_VOLUME_CALL(rewind_index_dir, cookie)
2417 return B_UNSUPPORTED;
2418 }
2419
2420
2421 static status_t
overlay_create_index(fs_volume * volume,const char * name,uint32 type,uint32 flags)2422 overlay_create_index(fs_volume *volume, const char *name, uint32 type,
2423 uint32 flags)
2424 {
2425 OVERLAY_VOLUME_CALL(create_index, name, type, flags)
2426 return B_UNSUPPORTED;
2427 }
2428
2429
2430 static status_t
overlay_remove_index(fs_volume * volume,const char * name)2431 overlay_remove_index(fs_volume *volume, const char *name)
2432 {
2433 OVERLAY_VOLUME_CALL(remove_index, name)
2434 return B_UNSUPPORTED;
2435 }
2436
2437
2438 static status_t
overlay_read_index_stat(fs_volume * volume,const char * name,struct stat * stat)2439 overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat)
2440 {
2441 OVERLAY_VOLUME_CALL(read_index_stat, name, stat)
2442 return B_UNSUPPORTED;
2443 }
2444
2445
2446 static status_t
overlay_open_query(fs_volume * volume,const char * query,uint32 flags,port_id port,uint32 token,void ** _cookie)2447 overlay_open_query(fs_volume *volume, const char *query, uint32 flags,
2448 port_id port, uint32 token, void **_cookie)
2449 {
2450 OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie)
2451 return B_UNSUPPORTED;
2452 }
2453
2454
2455 static status_t
overlay_close_query(fs_volume * volume,void * cookie)2456 overlay_close_query(fs_volume *volume, void *cookie)
2457 {
2458 OVERLAY_VOLUME_CALL(close_query, cookie)
2459 return B_UNSUPPORTED;
2460 }
2461
2462
2463 static status_t
overlay_free_query_cookie(fs_volume * volume,void * cookie)2464 overlay_free_query_cookie(fs_volume *volume, void *cookie)
2465 {
2466 OVERLAY_VOLUME_CALL(free_query_cookie, cookie)
2467 return B_UNSUPPORTED;
2468 }
2469
2470
2471 static status_t
overlay_read_query(fs_volume * volume,void * cookie,struct dirent * buffer,size_t bufferSize,uint32 * _num)2472 overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer,
2473 size_t bufferSize, uint32 *_num)
2474 {
2475 OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num)
2476 return B_UNSUPPORTED;
2477 }
2478
2479
2480 static status_t
overlay_rewind_query(fs_volume * volume,void * cookie)2481 overlay_rewind_query(fs_volume *volume, void *cookie)
2482 {
2483 OVERLAY_VOLUME_CALL(rewind_query, cookie)
2484 return B_UNSUPPORTED;
2485 }
2486
2487
2488 static status_t
overlay_all_layers_mounted(fs_volume * volume)2489 overlay_all_layers_mounted(fs_volume *volume)
2490 {
2491 return B_OK;
2492 }
2493
2494
2495 static status_t
overlay_create_sub_vnode(fs_volume * volume,ino_t id,fs_vnode * vnode)2496 overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode)
2497 {
2498 OverlayInode *node = new(std::nothrow) OverlayInode(
2499 (OverlayVolume *)volume->private_volume, vnode, id);
2500 if (node == NULL)
2501 return B_NO_MEMORY;
2502
2503 status_t status = node->InitCheck();
2504 if (status != B_OK) {
2505 delete node;
2506 return status;
2507 }
2508
2509 vnode->private_node = node;
2510 vnode->ops = &sOverlayVnodeOps;
2511 return B_OK;
2512 }
2513
2514
2515 static status_t
overlay_delete_sub_vnode(fs_volume * volume,fs_vnode * vnode)2516 overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode)
2517 {
2518 delete (OverlayInode *)vnode->private_node;
2519 return B_OK;
2520 }
2521
2522
2523 static fs_volume_ops sOverlayVolumeOps = {
2524 &overlay_unmount,
2525
2526 &overlay_read_fs_info,
2527 &overlay_write_fs_info,
2528 &overlay_sync,
2529
2530 &overlay_get_vnode,
2531 &overlay_open_index_dir,
2532 &overlay_close_index_dir,
2533 &overlay_free_index_dir_cookie,
2534 &overlay_read_index_dir,
2535 &overlay_rewind_index_dir,
2536
2537 &overlay_create_index,
2538 &overlay_remove_index,
2539 &overlay_read_index_stat,
2540
2541 &overlay_open_query,
2542 &overlay_close_query,
2543 &overlay_free_query_cookie,
2544 &overlay_read_query,
2545 &overlay_rewind_query,
2546
2547 &overlay_all_layers_mounted,
2548 &overlay_create_sub_vnode,
2549 &overlay_delete_sub_vnode
2550 };
2551
2552
2553 // #pragma mark - filesystem module
2554
2555
2556 static status_t
overlay_mount(fs_volume * volume,const char * device,uint32 flags,const char * args,ino_t * rootID)2557 overlay_mount(fs_volume *volume, const char *device, uint32 flags,
2558 const char *args, ino_t *rootID)
2559 {
2560 TRACE_VOLUME("mounting write overlay\n");
2561 volume->private_volume = new(std::nothrow) OverlayVolume(volume);
2562 if (volume->private_volume == NULL)
2563 return B_NO_MEMORY;
2564
2565 volume->ops = &sOverlayVolumeOps;
2566 return B_OK;
2567 }
2568
2569
2570 static status_t
overlay_std_ops(int32 op,...)2571 overlay_std_ops(int32 op, ...)
2572 {
2573 switch (op) {
2574 case B_MODULE_INIT:
2575 case B_MODULE_UNINIT:
2576 return B_OK;
2577 default:
2578 return B_ERROR;
2579 }
2580 }
2581
2582
2583 static file_system_module_info sOverlayFileSystem = {
2584 {
2585 "file_systems/write_overlay" B_CURRENT_FS_API_VERSION,
2586 0,
2587 overlay_std_ops,
2588 },
2589
2590 "write_overlay", // short_name
2591 "Write Overlay File System", // pretty_name
2592 0, // DDM flags
2593
2594 // scanning
2595 NULL, // identify_partition
2596 NULL, // scan_partition
2597 NULL, // free_identify_partition_cookie
2598 NULL, // free_partition_content_cookie
2599
2600 // general operations
2601 &overlay_mount,
2602
2603 // capability querying
2604 NULL, // get_supported_operations
2605
2606 NULL, // validate_resize
2607 NULL, // validate_move
2608 NULL, // validate_set_content_name
2609 NULL, // validate_set_content_parameters
2610 NULL, // validate_initialize
2611
2612 // shadow partition modification
2613 NULL, // shadow_changed
2614
2615 // writing
2616 NULL, // defragment
2617 NULL, // repair
2618 NULL, // resize
2619 NULL, // move
2620 NULL, // set_content_name
2621 NULL, // set_content_parameters
2622 NULL // initialize
2623 };
2624
2625
2626 status_t
publish_overlay_vnode(fs_volume * volume,ino_t inodeNumber,void * privateNode,int type)2627 publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber, void *privateNode,
2628 int type)
2629 {
2630 return publish_vnode(volume, inodeNumber, privateNode, &sOverlayVnodeOps,
2631 type, 0);
2632 }
2633
2634 } // namespace write_overlay
2635
2636 using namespace write_overlay;
2637
2638 module_info *modules[] = {
2639 (module_info *)&sOverlayFileSystem,
2640 NULL,
2641 };
2642