Bug Summary

File:src/add-ons/kernel/file_systems/ext2/Inode.cpp
Location:line 636, column 16
Description:Called C++ object pointer is null

Annotated Source Code

1/*
2 * Copyright 2011, Jérôme Duval, korli@users.berlios.de.
3 * Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
4 * This file may be used under the terms of the MIT License.
5 */
6
7
8#include "Inode.h"
9
10#include <string.h>
11#include <util/AutoLock.h>
12#include <NodeMonitor.h>
13
14#include "CachedBlock.h"
15#include "DataStream.h"
16#include "DirectoryIterator.h"
17#include "ExtentStream.h"
18#include "HTree.h"
19#include "Utility.h"
20
21
22#undef ASSERT
23//#define TRACE_EXT2
24#ifdef TRACE_EXT2
25# define TRACE(x...); dprintf("\33[34mext2:\33[0m " x)
26# define ASSERT(x); { if (!(x)) kernel_debugger("ext2: assert failed: " #x "\n"); }
27#else
28# define TRACE(x...); ;
29# define ASSERT(x); ;
30#endif
31#define ERROR(x...)dprintf("\33[34mext2:\33[0m " x...) dprintf("\33[34mext2:\33[0m " x)
32
33
34Inode::Inode(Volume* volume, ino_t id)
35 :
36 fVolume(volume),
37 fID(id),
38 fCache(NULL__null),
39 fMap(NULL__null),
40 fCached(false),
41 fHasExtraAttributes(false)
42{
43 rw_lock_init(&fLock, "ext2 inode");
44 recursive_lock_init(&fSmallDataLock, "ext2 inode small data");
45
46 TRACE("Inode::Inode(): ext2_inode: %lu, disk inode: %" B_PRIu32;
47 "\n", sizeof(ext2_inode), fVolume->InodeSize());;
48 fNodeSize = sizeof(ext2_inode) > fVolume->InodeSize()
49 ? fVolume->InodeSize() : sizeof(ext2_inode);
50
51 fInitStatus = UpdateNodeFromDisk();
52 if (fInitStatus == B_OK((int)0)) {
53 fHasExtraAttributes = (fNodeSize == sizeof(ext2_inode)
54 && fNode.ExtraInodeSize() + EXT2_INODE_NORMAL_SIZE128
55 == sizeof(ext2_inode));
56
57 if (IsDirectory() || (IsSymLink() && Size() < 60)) {
58 TRACE("Inode::Inode(): Not creating the file cache\n");;
59 fCached = false;
60
61 fInitStatus = B_OK((int)0);
62 } else
63 fInitStatus = EnableFileCache();
64 } else
65 TRACE("Inode: Failed initialization\n");;
66}
67
68
69Inode::Inode(Volume* volume)
70 :
71 fVolume(volume),
72 fID(0),
73 fCache(NULL__null),
74 fMap(NULL__null),
75 fCached(false),
76 fInitStatus(B_NO_INIT((-2147483647 - 1) + 13))
77{
78 rw_lock_init(&fLock, "ext2 inode");
79 recursive_lock_init(&fSmallDataLock, "ext2 inode small data");
80
81 TRACE("Inode::Inode(): ext2_inode: %lu, disk inode: %" B_PRIu32 "\n",;
82 sizeof(ext2_inode), fVolume->InodeSize());;
83 fNodeSize = sizeof(ext2_inode) > fVolume->InodeSize()
84 ? fVolume->InodeSize() : sizeof(ext2_inode);
85}
86
87
88Inode::~Inode()
89{
90 TRACE("Inode destructor\n");;
91
92 if (fCached) {
93 TRACE("Deleting the file cache and file map\n");;
94 file_cache_delete(FileCache());
95 file_map_delete(Map());
96 }
97
98 TRACE("Inode destructor: Done\n");;
99}
100
101
102status_t
103Inode::InitCheck()
104{
105 return fInitStatus;
106}
107
108
109void
110Inode::WriteLockInTransaction(Transaction& transaction)
111{
112 acquire_vnode(fVolume->FSVolume(), ID());
113
114 TRACE("Inode::WriteLockInTransaction(): Locking\n");;
115 rw_lock_write_lock(&fLock);
116
117 transaction.AddListener(this);
118}
119
120
121status_t
122Inode::WriteBack(Transaction& transaction)
123{
124 off_t blockNum;
125
126 status_t status = fVolume->GetInodeBlock(fID, blockNum);
127 if (status != B_OK((int)0))
128 return status;
129
130 if (Node().Size() > 0x7fffffffLL) {
131 status = fVolume->ActivateLargeFiles(transaction);
132 if (status != B_OK((int)0))
133 return status;
134 }
135
136 CachedBlock cached(fVolume);
137 uint8* inodeBlockData = cached.SetToWritable(transaction, blockNum);
138 if (inodeBlockData == NULL__null)
139 return B_IO_ERROR((-2147483647 - 1) + 1);
140
141 TRACE("Inode::WriteBack(): Inode ID: %" B_PRIdINO ", inode block: %";
142 B_PRIdOFF ", data: %p, index: %" B_PRIu32 ", inode size: %" B_PRIu32;
143 ", node size: %" B_PRIu32 ", this: %p, node: %p\n",;
144 fID, blockNum, inodeBlockData, fVolume->InodeBlockIndex(fID),;
145 fVolume->InodeSize(), fNodeSize, this, &fNode);;
146 memcpy(inodeBlockData +
147 fVolume->InodeBlockIndex(fID) * fVolume->InodeSize(),
148 (uint8*)&fNode, fNodeSize);
149
150 TRACE("Inode::WriteBack() finished %" B_PRId32 "\n", Node().stream.direct[0]);;
151
152 return B_OK((int)0);
153}
154
155
156status_t
157Inode::UpdateNodeFromDisk()
158{
159 off_t blockNum;
160
161 status_t status = fVolume->GetInodeBlock(fID, blockNum);
162 if (status != B_OK((int)0))
163 return status;
164
165 TRACE("inode %" B_PRIdINO " at block %" B_PRIdOFF "\n", fID, blockNum);;
166
167 CachedBlock cached(fVolume);
168 const uint8* inodeBlock = cached.SetTo(blockNum);
169
170 if (inodeBlock == NULL__null)
171 return B_IO_ERROR((-2147483647 - 1) + 1);
172
173 TRACE("Inode size: %" B_PRIu32 ", inode index: %" B_PRIu32 "\n",;
174 fVolume->InodeSize(), fVolume->InodeBlockIndex(fID));;
175 ext2_inode* inode = (ext2_inode*)(inodeBlock
176 + fVolume->InodeBlockIndex(fID) * fVolume->InodeSize());
177
178 TRACE("Attempting to copy inode data from %p to %p, ext2_inode ";
179 "size: %" B_PRIu32 "\n", inode, &fNode, fNodeSize);;
180
181 memcpy(&fNode, inode, fNodeSize);
182
183 uint32 numLinks = fNode.NumLinks();
184 fUnlinked = numLinks == 0 || (IsDirectory() && numLinks == 1);
185
186 return B_OK((int)0);
187}
188
189
190status_t
191Inode::CheckPermissions(int accessMode) const
192{
193 // you never have write access to a read-only volume
194 if ((accessMode & W_OK2) != 0 && fVolume->IsReadOnly())
195 return B_READ_ONLY_DEVICE(((-2147483647 - 1) + 0x6000) + 8);
196
197 // get node permissions
198 mode_t mode = Mode();
199 int userPermissions = (mode & S_IRWXU00700) >> 6;
200 int groupPermissions = (mode & S_IRWXG00070) >> 3;
201 int otherPermissions = mode & S_IRWXO00007;
202
203 // get the node permissions for this uid/gid
204 int permissions = 0;
205 uid_t uid = geteuid();
206 gid_t gid = getegid();
207
208 if (uid == 0) {
209 // user is root
210 // root has always read/write permission, but at least one of the
211 // X bits must be set for execute permission
212 permissions = userPermissions | groupPermissions | otherPermissions
213 | R_OK4 | W_OK2;
214 } else if (uid == (uid_t)fNode.UserID()) {
215 // user is node owner
216 permissions = userPermissions;
217 } else if (gid == (gid_t)fNode.GroupID()) {
218 // user is in owning group
219 permissions = groupPermissions;
220 } else {
221 // user is one of the others
222 permissions = otherPermissions;
223 }
224
225 return (accessMode & ~permissions) == 0 ? B_OK((int)0) : B_NOT_ALLOWED((-2147483647 - 1) + 15);
226}
227
228
229status_t
230Inode::FindBlock(off_t offset, fsblock_t& block, uint32 *_count)
231{
232 if (Flags() & EXT2_INODE_EXTENTS0x00080000) {
233 ExtentStream stream(fVolume, &fNode.extent_stream, Size());
234 return stream.FindBlock(offset, block, _count);
235 }
236 DataStream stream(fVolume, &fNode.stream, Size());
237 return stream.FindBlock(offset, block, _count);
238}
239
240
241status_t
242Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
243{
244 size_t length = *_length;
245
246 // set/check boundaries for pos/length
247 if (pos < 0) {
248 ERROR("inode %" B_PRIdINO ": ReadAt failed(pos %" B_PRIdOFFdprintf("\33[34mext2:\33[0m " "inode %" "ll" "d" ": ReadAt failed(pos %"
"ll" "d" ", length %" "l" "u" ")\n", ID(), pos, length)
249 ", length %" B_PRIuSIZE ")\n", ID(), pos, length)dprintf("\33[34mext2:\33[0m " "inode %" "ll" "d" ": ReadAt failed(pos %"
"ll" "d" ", length %" "l" "u" ")\n", ID(), pos, length)
;
250 return B_BAD_VALUE((-2147483647 - 1) + 5);
251 }
252
253 if (pos >= Size() || length == 0) {
254 TRACE("inode %" B_PRIdINO ": ReadAt 0 (pos %" B_PRIdOFF ", length %";
255 B_PRIuSIZE ")\n", ID(), pos, length);;
256 *_length = 0;
257 return B_NO_ERROR((int)0);
258 }
259
260 return file_cache_read(FileCache(), NULL__null, pos, buffer, _length);
261}
262
263
264status_t
265Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer,
266 size_t* _length)
267{
268 TRACE("Inode::WriteAt(%" B_PRIdOFF ", %p, *(%p) = %" B_PRIuSIZE ")\n", pos,;
269 buffer, _length, *_length);;
270 ReadLocker readLocker(fLock);
271
272 if (IsFileCacheDisabled())
273 return B_BAD_VALUE((-2147483647 - 1) + 5);
274
275 if (pos < 0)
276 return B_BAD_VALUE((-2147483647 - 1) + 5);
277
278 readLocker.Unlock();
279
280 TRACE("Inode::WriteAt(): Starting transaction\n");;
281 transaction.Start(fVolume->GetJournal());
282
283 WriteLocker writeLocker(fLock);
284
285 TRACE("Inode::WriteAt(): Updating modification time\n");;
286 struct timespec timespec;
287 _BigtimeToTimespec(real_time_clock_usecs(), &timespec);
288 SetModificationTime(&timespec);
289
290 // NOTE: Debugging info to find why sometimes resize doesn't happen
291 size_t length = *_length;
292#ifdef TRACE_EXT2
293 off_t oldEnd = pos + length;
294 TRACE("Inode::WriteAt(): Old calc for end? %x:%x\n",;
295 (int)(oldEnd >> 32), (int)(oldEnd & 0xFFFFFFFF));;
296#endif
297
298 off_t end = pos + (off_t)length;
299 off_t oldSize = Size();
300
301 TRACE("Inode::WriteAt(): Old size: %" B_PRIdOFF ":%" B_PRIdOFF;
302 ", new size: %" B_PRIdOFF ":%" B_PRIdOFF "\n",;
303 oldSize >> 32, oldSize & 0xFFFFFFFF,;
304 end >> 32, end & 0xFFFFFFFF);;
305
306 if (end > oldSize) {
307 status_t status = Resize(transaction, end);
308 if (status != B_OK((int)0)) {
309 *_length = 0;
310 WriteLockInTransaction(transaction);
311 return status;
312 }
313
314 status = WriteBack(transaction);
315 if (status != B_OK((int)0)) {
316 *_length = 0;
317 WriteLockInTransaction(transaction);
318 return status;
319 }
320 }
321
322 writeLocker.Unlock();
323
324 if (oldSize < pos)
325 FillGapWithZeros(oldSize, pos);
326
327 if (length == 0) {
328 // Probably just changed the file size with the pos parameter
329 return B_OK((int)0);
330 }
331
332 TRACE("Inode::WriteAt(): Performing write: %p, %" B_PRIdOFF ", %p, %";
333 B_PRIuSIZE "\n", FileCache(), pos, buffer, *_length);;
334 status_t status = file_cache_write(FileCache(), NULL__null, pos, buffer,
335 _length);
336
337 WriteLockInTransaction(transaction);
338
339 TRACE("Inode::WriteAt(): Done\n");;
340
341 return status;
342}
343
344
345status_t
346Inode::FillGapWithZeros(off_t start, off_t end)
347{
348 TRACE("Inode::FileGapWithZeros(%" B_PRIdOFF " - %" B_PRIdOFF ")\n", start,;
349 end);;
350
351 while (start < end) {
352 size_t size;
353
354 if (end > start + 1024 * 1024 * 1024)
355 size = 1024 * 1024 * 1024;
356 else
357 size = end - start;
358
359 TRACE("Inode::FillGapWithZeros(): Calling file_cache_write(%p, NULL, ";
360 "%" B_PRIdOFF ", NULL, &(%" B_PRIuSIZE ") = %p)\n", fCache, start,;
361 size, &size);;
362 status_t status = file_cache_write(fCache, NULL__null, start, NULL__null,
363 &size);
364 if (status != B_OK((int)0))
365 return status;
366
367 start += size;
368 }
369
370 return B_OK((int)0);
371}
372
373
374status_t
375Inode::Resize(Transaction& transaction, off_t size)
376{
377 TRACE("Inode::Resize() ID:%" B_PRIdINO " size: %" B_PRIdOFF "\n", ID(),;
378 size);;
379 if (size < 0)
380 return B_BAD_VALUE((-2147483647 - 1) + 5);
381
382 off_t oldSize = Size();
383
384 if (size == oldSize)
385 return B_OK((int)0);
386
387 TRACE("Inode::Resize(): old size: %" B_PRIdOFF ", new size: %" B_PRIdOFF;
388 "\n", oldSize, size);;
389
390 status_t status;
391 if (size > oldSize) {
392 status = _EnlargeDataStream(transaction, size);
393 if (status != B_OK((int)0)) {
394 // Restore original size
395 _ShrinkDataStream(transaction, oldSize);
396 }
397 } else
398 status = _ShrinkDataStream(transaction, size);
399
400 TRACE("Inode::Resize(): Updating file map and cache\n");;
401
402 if (status != B_OK((int)0))
403 return status;
404
405 file_cache_set_size(FileCache(), size);
406 file_map_set_size(Map(), size);
407
408 TRACE("Inode::Resize(): Writing back inode changes. Size: %" B_PRIdOFF;
409 "\n", Size());;
410
411 return WriteBack(transaction);
412}
413
414
415status_t
416Inode::InitDirectory(Transaction& transaction, Inode* parent)
417{
418 TRACE("Inode::InitDirectory()\n");;
419 uint32 blockSize = fVolume->BlockSize();
420
421 status_t status = Resize(transaction, blockSize);
422 if (status != B_OK((int)0))
423 return status;
424
425 fsblock_t blockNum;
426 if (Flags() & EXT2_INODE_EXTENTS0x00080000) {
427 ExtentStream stream(fVolume, &fNode.extent_stream, Size());
428 status = stream.FindBlock(0, blockNum);
429 } else {
430 DataStream stream(fVolume, &fNode.stream, Size());
431 status = stream.FindBlock(0, blockNum);
432 }
433 if (status != B_OK((int)0))
434 return status;
435
436 CachedBlock cached(fVolume);
437 uint8* block = cached.SetToWritable(transaction, blockNum, true);
438
439 HTreeRoot* root = (HTreeRoot*)block;
440 root->dot.inode_id = fID;
441 root->dot.entry_length = 12;
442 root->dot.name_length = 1;
443 root->dot.file_type = EXT2_TYPE_DIRECTORY2;
444 root->dot_entry_name[0] = '.';
445
446 root->dotdot.inode_id = parent == NULL__null ? fID : parent->ID();
447 root->dotdot.entry_length = blockSize - 12;
448 root->dotdot.name_length = 2;
449 root->dotdot.file_type = EXT2_TYPE_DIRECTORY2;
450 root->dotdot_entry_name[0] = '.';
451 root->dotdot_entry_name[1] = '.';
452
453 parent->IncrementNumLinks(transaction);
454
455 return parent->WriteBack(transaction);
456}
457
458
459status_t
460Inode::Unlink(Transaction& transaction)
461{
462 uint32 numLinks = fNode.NumLinks();
463 TRACE("Inode::Unlink(): Current links: %" B_PRIu32 "\n", numLinks);;
464
465 if (numLinks == 0)
466 return B_BAD_VALUE((-2147483647 - 1) + 5);
467
468 if ((IsDirectory() && numLinks == 2) || (numLinks == 1)) {
469 fUnlinked = true;
470
471 TRACE("Inode::Unlink(): Putting inode in orphan list\n");;
472 ino_t firstOrphanID;
473 status_t status = fVolume->SaveOrphan(transaction, fID, firstOrphanID);
474 if (status != B_OK((int)0))
475 return status;
476
477 if (firstOrphanID != 0) {
478 Vnode firstOrphan(fVolume, firstOrphanID);
479 Inode* nextOrphan;
480
481 status = firstOrphan.Get(&nextOrphan);
482 if (status != B_OK((int)0))
483 return status;
484
485 fNode.SetNextOrphan(nextOrphan->ID());
486 } else {
487 // Next orphan link is stored in deletion time
488 fNode.deletion_time = 0;
489 }
490
491 fNode.num_links = 0;
492
493 status = remove_vnode(fVolume->FSVolume(), fID);
494 if (status != B_OK((int)0))
495 return status;
496 } else
497 fNode.SetNumLinks(--numLinks);
498
499 return WriteBack(transaction);
500}
501
502
503/*static*/ status_t
504Inode::Create(Transaction& transaction, Inode* parent, const char* name,
505 int32 mode, int openMode, uint8 type, bool* _created, ino_t* _id,
506 Inode** _inode, fs_vnode_ops* vnodeOps, uint32 publishFlags)
507{
508 TRACE("Inode::Create()\n");;
509 Volume* volume = transaction.GetVolume();
510
511 DirectoryIterator* entries = NULL__null;
512 ObjectDeleter<DirectoryIterator> entriesDeleter;
513
514 if (parent != NULL__null) {
1
Assuming pointer value is null
2
Taking false branch
515 parent->WriteLockInTransaction(transaction);
516
517 TRACE("Inode::Create(): Looking up entry destination\n");;
518 HTree htree(volume, parent);
519
520 status_t status = htree.Lookup(name, &entries);
521 if (status == B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3)) {
522 panic("We need to add the first node.\n");
523 return B_ERROR(-1);
524 }
525 if (status != B_OK((int)0))
526 return status;
527 entriesDeleter.SetTo(entries);
528
529 TRACE("Inode::Create(): Looking up to see if file already exists\n");;
530 ino_t entryID;
531
532 status = entries->FindEntry(name, &entryID);
533 if (status == B_OK((int)0)) {
534 // File already exists
535 TRACE("Inode::Create(): File already exists\n");;
536 if (S_ISDIR(mode)(((mode) & 00000170000) == 00000040000) || S_ISLNK(mode)(((mode) & 00000170000) == 00000120000) || (openMode & O_EXCL0x0100) != 0)
537 return B_FILE_EXISTS(((-2147483647 - 1) + 0x6000) + 2);
538
539 Vnode vnode(volume, entryID);
540 Inode* inode;
541
542 status = vnode.Get(&inode);
543 if (status != B_OK((int)0)) {
544 TRACE("Inode::Create() Failed to get the inode from the ";
545 "vnode\n");;
546 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
547 }
548
549 if (inode->IsDirectory() && (openMode & O_RWMASK0x0003) != O_RDONLY0x0000)
550 return B_IS_A_DIRECTORY(((-2147483647 - 1) + 0x6000) + 9);
551 if ((openMode & O_DIRECTORY0x00200000) != 0 && !inode->IsDirectory())
552 return B_NOT_A_DIRECTORY(((-2147483647 - 1) + 0x6000) + 5);
553
554 if (inode->CheckPermissions(open_mode_to_access(openMode)
555 | ((openMode & O_TRUNC0x0400) != 0 ? W_OK2 : 0)) != B_OK((int)0))
556 return B_NOT_ALLOWED((-2147483647 - 1) + 15);
557
558 if ((openMode & O_TRUNC0x0400) != 0) {
559 // Truncate requested
560 TRACE("Inode::Create(): Truncating file\n");;
561 inode->WriteLockInTransaction(transaction);
562
563 status = inode->Resize(transaction, 0);
564 if (status != B_OK((int)0))
565 return status;
566 }
567
568 if (_created != NULL__null)
569 *_created = false;
570 if (_id != NULL__null)
571 *_id = inode->ID();
572 if (_inode != NULL__null)
573 *_inode = inode;
574
575 if (_id != NULL__null || _inode != NULL__null)
576 vnode.Keep();
577
578 TRACE("Inode::Create(): Done opening file\n");;
579 return B_OK((int)0);
580 /*} else if ((mode & S_ATTR_DIR) == 0) {
581 TRACE("Inode::Create(): (mode & S_ATTR_DIR) == 0\n");
582 return B_BAD_VALUE;*/
583 } else if ((openMode & O_DIRECTORY0x00200000) != 0) {
584 TRACE("Inode::Create(): (openMode & O_DIRECTORY) != 0\n");;
585 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
586 }
587
588 // Return to initial position
589 TRACE("Inode::Create(): Restarting iterator\n");;
590 entries->Restart();
591 }
592
593 status_t status;
594 if (parent != NULL__null) {
3
Taking false branch
595 status = parent->CheckPermissions(W_OK2);
596 if (status != B_OK((int)0))
597 return status;
598 }
599
600 TRACE("Inode::Create(): Allocating inode\n");;
601 ino_t id;
602 status = volume->AllocateInode(transaction, parent, mode, id);
603 if (status != B_OK((int)0)) {
4
Assuming 'status' is equal to 0
5
Taking false branch
604 ERROR("Inode::Create(): AllocateInode() failed\n")dprintf("\33[34mext2:\33[0m " "Inode::Create(): AllocateInode() failed\n"
)
;
605 return status;
606 }
607
608 if (entries != NULL__null) {
6
Taking false branch
609 size_t nameLength = strlen(name);
610 status = entries->AddEntry(transaction, name, nameLength, id, type);
611 if (status != B_OK((int)0)) {
612 ERROR("Inode::Create(): AddEntry() failed\n")dprintf("\33[34mext2:\33[0m " "Inode::Create(): AddEntry() failed\n"
)
;
613 return status;
614 }
615 }
616
617 TRACE("Inode::Create(): Creating inode\n");;
618 Inode* inode = new(std::nothrow) Inode(volume);
619 if (inode == NULL__null)
7
Taking false branch
620 return B_NO_MEMORY((-2147483647 - 1) + 0);
621
622 TRACE("Inode::Create(): Getting node structure\n");;
623 ext2_inode& node = inode->Node();
624 TRACE("Inode::Create(): Initializing inode data\n");;
625 memset(&node, 0, sizeof(ext2_inode));
626 node.SetMode(mode);
627 node.SetUserID(geteuid());
628 node.SetGroupID(parent != NULL__null ? parent->Node().GroupID() : getegid());
8
'?' condition is false
629 node.SetNumLinks(inode->IsDirectory() ? 2 : 1);
9
'?' condition is false
630 TRACE("Inode::Create(): Updating time\n");;
631 struct timespec timespec;
632 _BigtimeToTimespec(real_time_clock_usecs(), &timespec);
633 inode->SetAccessTime(&timespec);
634 inode->SetCreationTime(&timespec);
635 inode->SetModificationTime(&timespec);
636 node.SetFlags(parent->Flags() & EXT2_INODE_INHERITED(0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010
| 0x00000020 | 0x00000040 | 0x00000080 | 0x00000400 | 0x00004000
| 0x00008000 | 0x00010000)
);
10
Called C++ object pointer is null
637 if (volume->HasExtentsFeature()
638 && (inode->IsDirectory() || inode->IsFile())) {
639 node.SetFlag(EXT2_INODE_EXTENTS0x00080000);
640 ExtentStream stream(volume, &node.extent_stream, 0);
641 stream.Init();
642 ASSERT(stream.Check());;
643 }
644
645 if (sizeof(ext2_inode) < volume->InodeSize())
646 node.SetExtraInodeSize(sizeof(ext2_inode) - EXT2_INODE_NORMAL_SIZE128);
647
648 TRACE("Inode::Create(): Updating ID\n");;
649 inode->fID = id;
650
651 if (inode->IsDirectory()) {
652 TRACE("Inode::Create(): Initializing directory\n");;
653 status = inode->InitDirectory(transaction, parent);
654 if (status != B_OK((int)0)) {
655 ERROR("Inode::Create(): InitDirectory() failed\n")dprintf("\33[34mext2:\33[0m " "Inode::Create(): InitDirectory() failed\n"
)
;
656 delete inode;
657 return status;
658 }
659 }
660
661 // TODO: Maybe it can be better
662 /*if (volume->HasExtendedAttributes()) {
663 TRACE("Inode::Create(): Initializing extended attributes\n");
664 uint32 blockGroup = 0;
665 uint32 pos = 0;
666 uint32 allocated;
667
668 status = volume->AllocateBlocks(transaction, 1, 1, blockGroup, pos,
669 allocated);
670 if (status != B_OK)
671 return status;
672
673 // Clear the new block
674 uint32 blockNum = volume->FirstDataBlock() + pos +
675 volume->BlocksPerGroup() * blockGroup;
676 CachedBlock cached(volume);
677 cached.SetToWritable(transaction, blockNum, true);
678
679 node.SetExtendedAttributesBlock(blockNum);
680 }*/
681
682 TRACE("Inode::Create(): Saving inode\n");;
683 status = inode->WriteBack(transaction);
684 if (status != B_OK((int)0)) {
685 delete inode;
686 return status;
687 }
688
689 TRACE("Inode::Create(): Creating vnode\n");;
690
691 Vnode vnode;
692 status = vnode.Publish(transaction, inode, vnodeOps, publishFlags);
693 if (status != B_OK((int)0))
694 return status;
695
696 if (!inode->IsSymLink()) {
697 // Vnode::Publish doesn't publish symlinks
698 if (!inode->IsDirectory()) {
699 status = inode->EnableFileCache();
700 if (status != B_OK((int)0))
701 return status;
702 }
703
704 inode->WriteLockInTransaction(transaction);
705 }
706
707 if (_created)
708 *_created = true;
709 if (_id != NULL__null)
710 *_id = id;
711 if (_inode != NULL__null)
712 *_inode = inode;
713
714 if (_id != NULL__null || _inode != NULL__null)
715 vnode.Keep();
716
717 TRACE("Inode::Create(): Deleting entries iterator\n");;
718 DirectoryIterator* iterator = entriesDeleter.Detach();
719 TRACE("Inode::Create(): Entries iterator: %p\n", entries);;
720 delete iterator;
721 TRACE("Inode::Create(): Done\n");;
722
723 return B_OK((int)0);
724}
725
726
727status_t
728Inode::EnableFileCache()
729{
730 TRACE("Inode::EnableFileCache()\n");;
731
732 if (fCached)
733 return B_OK((int)0);
734 if (fCache != NULL__null) {
735 fCached = true;
736 return B_OK((int)0);
737 }
738
739 TRACE("Inode::EnableFileCache(): Creating file cache: %" B_PRIu32 ", %";
740 B_PRIdINO ", %" B_PRIdOFF "\n", fVolume->ID(), ID(), Size());;
741 fCache = file_cache_create(fVolume->ID(), ID(), Size());
742 fMap = file_map_create(fVolume->ID(), ID(), Size());
743
744 if (fCache == NULL__null) {
745 ERROR("Inode::EnableFileCache(): Failed to create file cache\n")dprintf("\33[34mext2:\33[0m " "Inode::EnableFileCache(): Failed to create file cache\n"
)
;
746 fCached = false;
747 return B_ERROR(-1);
748 }
749
750 fCached = true;
751 TRACE("Inode::EnableFileCache(): Done\n");;
752
753 return B_OK((int)0);
754}
755
756
757status_t
758Inode::DisableFileCache()
759{
760 TRACE("Inode::DisableFileCache()\n");;
761
762 if (!fCached)
763 return B_OK((int)0);
764
765 file_cache_delete(FileCache());
766 file_map_delete(Map());
767
768 fCached = false;
769
770 return B_OK((int)0);
771}
772
773
774status_t
775Inode::Sync()
776{
777 if (!IsFileCacheDisabled())
778 return file_cache_sync(fCache);
779
780 return B_OK((int)0);
781}
782
783
784void
785Inode::TransactionDone(bool success)
786{
787 if (!success) {
788 // Revert any changes to the inode
789 if (fInitStatus == B_OK((int)0) && UpdateNodeFromDisk() != B_OK((int)0))
790 panic("Failed to reload inode from disk!\n");
791 else if (fInitStatus == B_NO_INIT((-2147483647 - 1) + 13)) {
792 // TODO: Unpublish vnode?
793 panic("Failed to finish creating inode\n");
794 }
795 } else {
796 if (fInitStatus == B_NO_INIT((-2147483647 - 1) + 13)) {
797 TRACE("Inode::TransactionDone(): Inode creation succeeded\n");;
798 fInitStatus = B_OK((int)0);
799 }
800 }
801}
802
803
804void
805Inode::RemovedFromTransaction()
806{
807 TRACE("Inode::RemovedFromTransaction(): Unlocking\n");;
808 rw_lock_write_unlock(&fLock);
809
810 put_vnode(fVolume->FSVolume(), ID());
811}
812
813
814status_t
815Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
816{
817 if (size < 0)
818 return B_BAD_VALUE((-2147483647 - 1) + 5);
819
820 TRACE("Inode::_EnlargeDataStream()\n");;
821
822 uint32 blockSize = fVolume->BlockSize();
823 off_t oldSize = Size();
824 off_t maxSize = oldSize;
825 if (maxSize % blockSize != 0)
826 maxSize += blockSize - maxSize % blockSize;
827
828 if (size <= maxSize) {
829 // No need to allocate more blocks
830 TRACE("Inode::_EnlargeDataStream(): No need to allocate more blocks\n");;
831 TRACE("Inode::_EnlargeDataStream(): Setting size to %" B_PRIdOFF "\n",;
832 size);;
833 fNode.SetSize(size);
834 return B_OK((int)0);
835 }
836
837 off_t end = size == 0 ? 0 : (size - 1) / fVolume->BlockSize() + 1;
838 if (Flags() & EXT2_INODE_EXTENTS0x00080000) {
839 ExtentStream stream(fVolume, &fNode.extent_stream, Size());
840 stream.Enlarge(transaction, end);
841 ASSERT(stream.Check());;
842 } else {
843 DataStream stream(fVolume, &fNode.stream, oldSize);
844 stream.Enlarge(transaction, end);
845 }
846 TRACE("Inode::_EnlargeDataStream(): Setting size to %" B_PRIdOFF "\n",;
847 size);;
848 fNode.SetSize(size);
849 TRACE("Inode::_EnlargeDataStream(): Setting allocated block count to %";
850 B_PRIdOFF "\n", end);;
851 return _SetNumBlocks(_NumBlocks() + end * (fVolume->BlockSize() / 512));
852}
853
854
855status_t
856Inode::_ShrinkDataStream(Transaction& transaction, off_t size)
857{
858 TRACE("Inode::_ShrinkDataStream()\n");;
859
860 if (size < 0)
861 return B_BAD_VALUE((-2147483647 - 1) + 5);
862
863 uint32 blockSize = fVolume->BlockSize();
864 off_t oldSize = Size();
865 off_t lastByte = oldSize == 0 ? 0 : oldSize - 1;
866 off_t minSize = (lastByte / blockSize + 1) * blockSize;
867 // Minimum size that doesn't require freeing blocks
868
869 if (size > minSize) {
870 // No need to allocate more blocks
871 TRACE("Inode::_ShrinkDataStream(): No need to allocate more blocks\n");;
872 TRACE("Inode::_ShrinkDataStream(): Setting size to %" B_PRIdOFF "\n",;
873 size);;
874 fNode.SetSize(size);
875 return B_OK((int)0);
876 }
877
878 off_t end = size == 0 ? 0 : (size - 1) / fVolume->BlockSize() + 1;
879 if (Flags() & EXT2_INODE_EXTENTS0x00080000) {
880 ExtentStream stream(fVolume, &fNode.extent_stream, Size());
881 stream.Shrink(transaction, end);
882 ASSERT(stream.Check());;
883 } else {
884 DataStream stream(fVolume, &fNode.stream, oldSize);
885 stream.Shrink(transaction, end);
886 }
887
888 fNode.SetSize(size);
889 return _SetNumBlocks(_NumBlocks() - end * (fVolume->BlockSize() / 512));
890}
891
892
893uint64
894Inode::_NumBlocks()
895{
896 if (fVolume->HugeFiles()) {
897 if (fNode.Flags() & EXT2_INODE_HUGE_FILE0x00040000)
898 return fNode.NumBlocks64() * (fVolume->BlockSize() / 512);
899 else
900 return fNode.NumBlocks64();
901 } else
902 return fNode.NumBlocks();
903}
904
905
906status_t
907Inode::_SetNumBlocks(uint64 numBlocks)
908{
909 if (numBlocks <= 0xffffffff) {
910 fNode.SetNumBlocks(numBlocks);
911 fNode.ClearFlag(EXT2_INODE_HUGE_FILE0x00040000);
912 return B_OK((int)0);
913 }
914 if (!fVolume->HugeFiles())
915 return E2BIG(((-2147483647 - 1) + 0x7000) + 1);
916
917 if (numBlocks > 0xffffffffffffULL) {
918 fNode.SetFlag(EXT2_INODE_HUGE_FILE0x00040000);
919 numBlocks /= (fVolume->BlockSize() / 512);
920 } else
921 fNode.ClearFlag(EXT2_INODE_HUGE_FILE0x00040000);
922
923 fNode.SetNumBlocks64(numBlocks);
924 return B_OK((int)0);
925}
926
927
928void
929Inode::IncrementNumLinks(Transaction& transaction)
930{
931 fNode.SetNumLinks(fNode.NumLinks() + 1);
932 if (IsIndexed() && (fNode.NumLinks() >= EXT2_INODE_MAX_LINKS65000
933 || fNode.NumLinks() == 2)) {
934 fNode.SetNumLinks(1);
935 fVolume->ActivateDirNLink(transaction);
936 }
937}
938