Bug Summary

File:/boot/home/haiku/haiku/src/bin/bfs_tools/lib/Inode.cpp
Location:line 627, column 2
Description:Called C++ object pointer is null

Annotated Source Code

1/*
2 * Copyright 2001-2008 pinc Software. All Rights Reserved.
3 */
4
5//! BFS Inode classes
6
7
8#include "Inode.h"
9#include "BPlusTree.h"
10
11#include <Directory.h>
12#include <SymLink.h>
13#include <Entry.h>
14#include <Path.h>
15#include <String.h>
16
17#include <new>
18#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21
22
23class NodeGetter {
24 public:
25 NodeGetter(Inode* inode)
26 :
27 fInode(inode)
28 {
29 fInode->AcquireBuffer();
30 }
31
32 ~NodeGetter()
33 {
34 fInode->ReleaseBuffer();
35 }
36
37 private:
38 Inode* fInode;
39};
40
41
42// #pragma mark -
43
44
45Inode::Inode(Disk* disk, bfs_inode* inode, bool ownBuffer)
46 :
47 fDisk(disk),
48 fInode(inode),
49 fOwnBuffer(ownBuffer),
50 fPath(NULL__null),
51 fRefCount(1),
52 fCurrentSmallData(NULL__null),
53 fAttributes(NULL__null),
54 fAttributeBuffer(NULL__null)
55{
56 if (inode != NULL__null)
57 fBlockRun = inode->inode_num;
58}
59
60
61Inode::Inode(const Inode& inode)
62 :
63 fDisk(inode.fDisk),
64 fInode(inode.fInode),
65 fOwnBuffer(false),
66 fPath(NULL__null),
67 fBlockRun(inode.fBlockRun),
68 fRefCount(1),
69 fCurrentSmallData(NULL__null),
70 fAttributes(NULL__null),
71 fAttributeBuffer(NULL__null)
72{
73}
74
75
76Inode::~Inode()
77{
78 _Unset();
79}
80
81
82void
83Inode::_Unset()
84{
85 if (fOwnBuffer)
86 free(fInode);
87
88 fInode = NULL__null;
89 fBlockRun.SetTo(0, 0, 0);
90
91 free(fPath);
92 fPath = NULL__null;
93
94 delete fAttributes;
95 fAttributes = NULL__null;
96}
97
98
99status_t
100Inode::SetTo(bfs_inode *inode)
101{
102 _Unset();
103
104 fInode = inode;
105 fBlockRun = inode->inode_num;
106 return B_OK((int)0);
107}
108
109
110status_t
111Inode::InitCheck()
112{
113 if (!fInode)
114 return B_ERROR(-1);
115
116 // test inode magic and flags
117 if (fInode->magic1 != INODE_MAGIC10x3bbe0ad9
118 || !(fInode->flags & INODE_IN_USE)
119 || fInode->inode_num.length != 1)
120 return B_ERROR(-1);
121
122 if (fDisk->BlockSize()) {
123 // matches known block size?
124 if (fInode->inode_size != fDisk->SuperBlock()->inode_size
125 // parent resides on disk?
126 || fInode->parent.allocation_group > fDisk->SuperBlock()->num_ags
127 || fInode->parent.allocation_group < 0
128 || fInode->parent.start > (1L << fDisk->SuperBlock()->ag_shift)
129 || fInode->parent.length != 1
130 // attributes, too?
131 || fInode->attributes.allocation_group > fDisk->SuperBlock()->num_ags
132 || fInode->attributes.allocation_group < 0
133 || fInode->attributes.start > (1L << fDisk->SuperBlock()->ag_shift))
134 return B_ERROR(-1);
135 } else {
136 // is inode size one of the valid values?
137 switch (fInode->inode_size) {
138 case 1024:
139 case 2048:
140 case 4096:
141 case 8192:
142 break;
143 default:
144 return B_ERROR(-1);
145 }
146 }
147 return B_OK((int)0);
148 // is inode on a boundary matching it's size?
149 //return (Offset() % fInode->inode_size) == 0 ? B_OK : B_ERROR;
150}
151
152
153status_t
154Inode::CopyBuffer()
155{
156 if (!fInode)
157 return B_ERROR(-1);
158
159 bfs_inode *buffer = (bfs_inode *)malloc(fInode->inode_size);
160 if (!buffer)
161 return B_NO_MEMORY((-2147483647 - 1) + 0);
162
163 memcpy(buffer, fInode, fInode->inode_size);
164 fInode = buffer;
165 fOwnBuffer = true;
166 BufferClobbered();
167 // this must not be deleted anymore
168
169 return B_OK((int)0);
170}
171
172
173/*static*/ bool
174Inode::_LowMemory()
175{
176 static bigtime_t lastChecked;
177 static int32 percentUsed;
178
179 if (system_time() > lastChecked + 1000000LL) {
180 system_info info;
181 get_system_info(&info)_get_system_info((&info), sizeof(*(&info)));
182 percentUsed = 100 * info.used_pages / info.max_pages;
183 }
184
185 return percentUsed > 75;
186}
187
188
189void
190Inode::ReleaseBuffer()
191{
192 if (atomic_add(&fRefCount, -1)__sync_fetch_and_add(&fRefCount, -1) != 1)
193 return;
194
195 if (fOwnBuffer) {
196 if (!_LowMemory())
197 return;
198
199 free(fInode);
200 fInode = NULL__null;
201 }
202}
203
204
205status_t
206Inode::AcquireBuffer()
207{
208 if (atomic_add(&fRefCount, 1)__sync_fetch_and_add(&fRefCount, 1) != 0)
209 return B_OK((int)0);
210
211 if (!fOwnBuffer || fInode != NULL__null)
212 return B_OK((int)0);
213
214 fInode = (bfs_inode*)malloc(fDisk->BlockSize());
215 if (fInode == NULL__null)
216 return B_NO_MEMORY((-2147483647 - 1) + 0);
217
218 ssize_t bytesRead = fDisk->ReadAt(Offset(), fInode, fDisk->BlockSize());
219 if (bytesRead < B_OK((int)0))
220 return bytesRead;
221
222 return B_OK((int)0);
223}
224
225
226void
227Inode::BufferClobbered()
228{
229 AcquireBuffer();
230}
231
232
233void
234Inode::SetParent(const block_run& run)
235{
236 fInode->parent = run;
237 BufferClobbered();
238}
239
240
241void
242Inode::SetBlockRun(const block_run& run)
243{
244 fInode->inode_num = run;
245 fBlockRun = run;
246 BufferClobbered();
247}
248
249
250void
251Inode::SetMode(uint32 mode)
252{
253 fInode->mode = mode;
254 BufferClobbered();
255}
256
257
258status_t
259Inode::SetName(const char *name)
260{
261 if (name == NULL__null || *name == '\0')
262 return B_BAD_VALUE((-2147483647 - 1) + 5);
263
264 small_data *data = fInode->small_data_start, *nameData = NULL__null;
265 BufferClobbered();
266
267 while (!data->IsLast(fInode)) {
268 if (data->type == FILE_NAME_TYPE'CSTR'
269 && data->name_size == FILE_NAME_NAME_LENGTH1
270 && *data->Name() == FILE_NAME_NAME0x13)
271 nameData = data;
272
273 data = data->Next();
274 }
275
276 int32 oldLength = nameData == NULL__null ? 0 : nameData->data_size;
277 int32 newLength = strlen(name) + (nameData == NULL__null ? sizeof(small_data) + 5 : 0);
278
279 if ((addr_t)data + newLength - oldLength >= (addr_t)(fInode
280 + fDisk->BlockSize()))
281 return B_NO_MEMORY((-2147483647 - 1) + 0);
282
283 if (nameData == NULL__null) {
284 memmove(newLength + (uint8 *)fInode->small_data_start,
285 fInode->small_data_start,
286 (addr_t)data - (addr_t)fInode->small_data_start);
287 nameData = fInode->small_data_start;
288 } else {
289 memmove(newLength + (uint8 *)nameData, nameData,
290 (addr_t)data - (addr_t)fInode->small_data_start);
291 }
292
293 memset(nameData, 0, sizeof(small_data) + 5 + strlen(name));
294 nameData->type = FILE_NAME_TYPE'CSTR';
295 nameData->name_size = FILE_NAME_NAME_LENGTH1;
296 nameData->data_size = strlen(name);
297 *nameData->Name() = FILE_NAME_NAME0x13;
298 strcpy((char *)nameData->Data(),name);
299
300 return B_OK((int)0);
301}
302
303
304const char *
305Inode::Name() const
306{
307 small_data *data = fInode->small_data_start;
308 while (!data->IsLast(fInode)) {
309 if (data->type == FILE_NAME_TYPE'CSTR'
310 && data->name_size == FILE_NAME_NAME_LENGTH1
311 && *data->Name() == FILE_NAME_NAME0x13)
312 return (const char *)data->Data();
313
314 data = data->Next();
315 }
316 return NULL__null;
317}
318
319
320status_t
321Inode::GetNextSmallData(small_data **smallData)
322{
323 if (!fInode)
324 return B_ERROR(-1);
325
326 small_data *data = *smallData;
327
328 // begin from the start?
329 if (data == NULL__null)
330 data = fInode->small_data_start;
331 else
332 data = data->Next();
333
334 // is already last item?
335 if (data->IsLast(fInode))
336 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
337
338 *smallData = data;
339 return B_OK((int)0);
340}
341
342
343status_t
344Inode::RewindAttributes()
345{
346 fCurrentSmallData = NULL__null;
347
348 if (fAttributes != NULL__null)
349 fAttributes->Rewind();
350
351 return B_OK((int)0);
352}
353
354
355status_t
356Inode::GetNextAttribute(char *name, uint32 *type, void **data, size_t *length)
357{
358 // read attributes out of the small data section
359
360 if (fCurrentSmallData == NULL__null || !fCurrentSmallData->IsLast(fInode)) {
361 if (fCurrentSmallData == NULL__null)
362 fCurrentSmallData = fInode->small_data_start;
363 else
364 fCurrentSmallData = fCurrentSmallData->Next();
365
366 // skip name attribute
367 if (!fCurrentSmallData->IsLast(fInode)
368 && fCurrentSmallData->name_size == FILE_NAME_NAME_LENGTH1
369 && *fCurrentSmallData->Name() == FILE_NAME_NAME0x13)
370 fCurrentSmallData = fCurrentSmallData->Next();
371
372 if (!fCurrentSmallData->IsLast(fInode)) {
373 strncpy(name,fCurrentSmallData->Name(), B_FILE_NAME_LENGTH(256));
374 *type = fCurrentSmallData->type;
375 *data = fCurrentSmallData->Data();
376 *length = fCurrentSmallData->data_size;
377
378 return B_OK((int)0);
379 }
380 }
381
382 // read attributes out of the attribute directory
383
384 if (Attributes().IsZero())
385 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
386
387 if (fAttributes == NULL__null)
388 fAttributes = (Directory *)Inode::Factory(fDisk, Attributes());
389
390 status_t status = fAttributes ? fAttributes->InitCheck() : B_ERROR(-1);
391 if (status < B_OK((int)0))
392 return status;
393
394 block_run run;
395 status = fAttributes->GetNextEntry(name, &run);
396 if (status < B_OK((int)0)) {
397 free(fAttributeBuffer);
398 fAttributeBuffer = NULL__null;
399 return status;
400 }
401
402 Attribute *attribute = (Attribute *)Inode::Factory(fDisk, run);
403 if (attribute == NULL__null || attribute->InitCheck() < B_OK((int)0))
404 return B_IO_ERROR((-2147483647 - 1) + 1);
405
406 *type = attribute->Type();
407
408 void *buffer = realloc(fAttributeBuffer, attribute->Size());
409 if (buffer == NULL__null) {
410 free(fAttributeBuffer);
411 fAttributeBuffer = NULL__null;
412 delete attribute;
413 return B_NO_MEMORY((-2147483647 - 1) + 0);
414 }
415 fAttributeBuffer = buffer;
416
417 ssize_t size = attribute->Read(fAttributeBuffer, attribute->Size());
418 delete attribute;
419
420 *length = size;
421 *data = fAttributeBuffer;
422
423 return size < B_OK((int)0) ? size : B_OK((int)0);
424}
425
426
427status_t
428Inode::_FindPath(Inode::Source *source)
429{
430 BString path;
431
432 block_run parent = Parent();
433 while (!parent.IsZero() && parent != fDisk->Root()) {
434 Inode *inode;
435 if (source)
436 inode = source->InodeAt(parent);
437 else
438 inode = Inode::Factory(fDisk, parent);
439
440 if (inode == NULL__null
441 || inode->InitCheck() < B_OK((int)0)
442 || inode->Name() == NULL__null
443 || !*inode->Name()) {
444 BString sub;
445 sub << "__recovered " << parent.allocation_group << ":"
446 << (int32)parent.start << "/";
447 path.Prepend(sub);
448
449 delete inode;
450 break;
451 }
452 parent = inode->Parent();
453 path.Prepend("/");
454 path.Prepend(inode->Name());
455
456 delete inode;
457 }
458 fPath = strdup(path.String());
459
460 return B_OK((int)0);
461}
462
463
464const char *
465Inode::Path(Inode::Source *source)
466{
467 if (fPath == NULL__null)
468 _FindPath(source);
469
470 return fPath;
471}
472
473
474status_t
475Inode::CopyTo(const char *root, bool fullPath, Inode::Source *source)
476{
477 if (root == NULL__null)
478 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
479
480 BString path;
481
482 if (fullPath)
483 path.Append(Path(source));
484
485 if (*(root + strlen(root) - 1) != '/')
486 path.Prepend("/");
487 path.Prepend(root);
488
489 return create_directory(path.String(), 0777);
490}
491
492
493status_t
494Inode::CopyAttributesTo(BNode *node)
495{
496 // copy attributes
497
498 RewindAttributes();
499
500 char name[B_FILE_NAME_LENGTH(256)];
501 const uint32 kMaxBrokenAttributes = 64;
502 // sanity max value
503 uint32 count = 0;
504 uint32 type;
505 void *data;
506 size_t size;
507
508 status_t status;
509 while ((status = GetNextAttribute(name, &type, &data, &size))
510 != B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3)) {
511 if (status != B_OK((int)0)) {
512 printf("could not open attribute (possibly: %s): %s!\n",
513 name, strerror(status));
514 if (count++ > kMaxBrokenAttributes)
515 break;
516
517 continue;
518 }
519
520 ssize_t written = node->WriteAttr(name, type, 0, data, size);
521 if (written < B_OK((int)0)) {
522 printf("could not write attribute \"%s\": %s\n", name,
523 strerror(written));
524 } else if ((size_t)written < size) {
525 printf("could only write %ld bytes (from %ld) at attribute \"%s\"\n",
526 written, size, name);
527 }
528 }
529
530 // copy stats
531
532 node->SetPermissions(fInode->mode);
533 node->SetOwner(fInode->uid);
534 node->SetGroup(fInode->gid);
535 node->SetModificationTime(fInode->last_modified_time >> 16);
536 node->SetCreationTime(fInode->create_time >> 16);
537
538 return B_OK((int)0);
539}
540
541
542Inode *
543Inode::Factory(Disk *disk, bfs_inode *inode, bool ownBuffer)
544{
545 // attributes (of a file)
546 if ((inode->mode & (S_ATTR02000000000 | S_ATTR_DIR01000000000)) == S_ATTR02000000000)
547 return new Attribute(disk, inode, ownBuffer);
548
549 // directories, attribute directories, indices
550 if (S_ISDIR(inode->mode)(((inode->mode) & 00000170000) == 00000040000) || inode->mode & S_ATTR_DIR01000000000)
551 return new Directory(disk, inode, ownBuffer);
552
553 // regular files
554 if (S_ISREG(inode->mode)(((inode->mode) & 00000170000) == 00000100000))
555 return new File(disk, inode, ownBuffer);
556
557 // symlinks (short and link in data-stream)
558 if (S_ISLNK(inode->mode)(((inode->mode) & 00000170000) == 00000120000))
559 return new Symlink(disk, inode, ownBuffer);
560
561 return NULL__null;
562}
563
564
565Inode *
566Inode::Factory(Disk *disk, block_run run)
567{
568 bfs_inode *inode = (bfs_inode *)malloc(disk->BlockSize());
569 if (!inode)
570 return NULL__null;
571
572 if (disk->ReadAt(disk->ToOffset(run), inode, disk->BlockSize()) <= 0)
573 return NULL__null;
574
575 Inode *object = Factory(disk, inode);
576 if (object == NULL__null)
577 free(inode);
578
579 return object;
580}
581
582
583Inode *
584Inode::Factory(Disk *disk, Inode *inode, bool copyBuffer)
585{
586 bfs_inode *inodeBuffer = inode->fInode;
587
588 if (copyBuffer) {
589 bfs_inode *inodeCopy = (bfs_inode *)malloc(inodeBuffer->inode_size);
590 if (!inodeCopy)
591 return NULL__null;
592
593 memcpy(inodeCopy, inodeBuffer, inodeBuffer->inode_size);
594 inodeBuffer = inodeCopy;
595 }
596 return Factory(disk, inodeBuffer, copyBuffer);
597}
598
599
600Inode *
601Inode::EmptyInode(Disk *disk, const char *name, int32 mode)
602{
603 bfs_inode *inode = (bfs_inode *)malloc(disk->BlockSize());
604 if (!inode)
1
Assuming 'inode' is non-null
2
Taking false branch
605 return NULL__null;
606
607 memset(inode, 0, sizeof(bfs_inode));
608
609 inode->magic1 = INODE_MAGIC10x3bbe0ad9;
610 inode->inode_size = disk->BlockSize();
611 inode->mode = mode;
612 inode->flags = INODE_IN_USE | (mode & S_IFDIR00000040000 ? INODE_LOGGED : 0);
3
'?' condition is false
613
614 if (name) {
4
Assuming 'name' is null
5
Taking false branch
615 small_data *data = inode->small_data_start;
616 data->type = FILE_NAME_TYPE'CSTR';
617 data->name_size = FILE_NAME_NAME_LENGTH1;
618 *data->Name() = FILE_NAME_NAME0x13;
619 data->data_size = strlen(name);
620 strcpy((char *)data->Data(), name);
621 }
622
623 Inode *object = new (std::nothrow) Inode(disk, inode);
6
'object' initialized here
624 if (object == NULL__null)
7
Assuming pointer value is null
8
Taking true branch
625 free(inode);
626
627 object->AcquireBuffer();
9
Called C++ object pointer is null
628 // this must not be deleted anymore!
629 return object;
630}
631
632
633// #pragma mark -
634
635
636DataStream::DataStream(Disk *disk, bfs_inode *inode, bool ownBuffer)
637 : Inode(disk,inode,ownBuffer),
638 fCurrent(-1),
639 fPosition(0LL)
640{
641}
642
643
644DataStream::DataStream(const Inode &inode)
645 : Inode(inode),
646 fCurrent(-1),
647 fPosition(0LL)
648{
649}
650
651
652DataStream::~DataStream()
653{
654}
655
656
657status_t
658DataStream::FindBlockRun(off_t pos)
659{
660 NodeGetter _(this);
661
662 if (pos > fInode->data.size)
663 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
664
665 if (fCurrent < 0)
666 fLevel = 0;
667
668 fRunBlockEnd = fCurrent >= 0
669 ? fRunFileOffset + (fRun.length << fDisk->BlockShift()) : 0LL;
670
671 // access in current block run?
672
673 if (fCurrent >= 0 && pos >= fRunFileOffset && pos < fRunBlockEnd)
674 return B_OK((int)0);
675
676 // find matching block run
677
678 if (fInode->data.max_direct_range > 0
679 && pos >= fInode->data.max_direct_range) {
680 if (fInode->data.max_double_indirect_range > 0
681 && pos >= fInode->data.max_indirect_range) {
682 // read from double indirect blocks
683
684 //printf("find double indirect block: %ld,%d!\n",fInode->data.double_indirect.allocation_group,fInode->data.double_indirect.start);
685 block_run *indirect = (block_run *)fDisk->ReadBlockRun(fInode->data.double_indirect);
686 if (indirect == NULL__null)
687 return B_ERROR(-1);
688
689 off_t start = pos - fInode->data.max_indirect_range;
690 int32 indirectSize = fDisk->BlockSize() * 16 * (fDisk->BlockSize() / sizeof(block_run));
691 int32 directSize = fDisk->BlockSize() * 4;
692 int32 index = start / indirectSize;
693
694 //printf("\tstart = %Ld, indirectSize = %ld, directSize = %ld, index = %ld\n",start,indirectSize,directSize,index);
695 //printf("\tlook for indirect block at %ld,%d\n",indirect[index].allocation_group,indirect[index].start);
696 indirect = (block_run *)fDisk->ReadBlockRun(indirect[index]);
697 if (indirect == NULL__null)
698 return B_ERROR(-1);
699
700 fCurrent = (start % indirectSize) / directSize;
701 fRunFileOffset = fInode->data.max_indirect_range + (index * indirectSize) + (fCurrent * directSize);
702 fRunBlockEnd = fRunFileOffset + directSize;
703 fRun = indirect[fCurrent];
704 //printf("\tfCurrent = %ld, fRunFileOffset = %Ld, fRunBlockEnd = %Ld, fRun = %ld,%d\n",fCurrent,fRunFileOffset,fRunBlockEnd,fRun.allocation_group,fRun.start);
705 } else {
706 // access from indirect blocks
707
708 block_run *indirect = (block_run *)fDisk->ReadBlockRun(fInode->data.indirect);
709 if (!indirect)
710 return B_ERROR(-1);
711
712 int32 indirectRuns = (fInode->data.indirect.length << fDisk->BlockShift()) / sizeof(block_run);
713
714 if (fLevel != 1 || pos < fRunFileOffset) {
715 fRunBlockEnd = fInode->data.max_direct_range;
716 fCurrent = -1;
717 fLevel = 1;
718 }
719
720 while (++fCurrent < indirectRuns) {
721 if (indirect[fCurrent].IsZero())
722 break;
723
724 fRunFileOffset = fRunBlockEnd;
725 fRunBlockEnd += indirect[fCurrent].length << fDisk->BlockShift();
726 if (fRunBlockEnd > pos)
727 break;
728 }
729 if (fCurrent == indirectRuns || indirect[fCurrent].IsZero())
730 return B_ERROR(-1);
731
732 fRun = indirect[fCurrent];
733 //printf("reading from indirect block: %ld,%d\n",fRun.allocation_group,fRun.start);
734 //printf("### indirect-run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
735 }
736 } else {
737 // access from direct blocks
738 if (fRunFileOffset > pos) {
739 fRunBlockEnd = 0LL;
740 fCurrent = -1;
741 }
742 fLevel = 0;
743
744 while (++fCurrent < NUM_DIRECT_BLOCKS12) {
745 if (fInode->data.direct[fCurrent].IsZero())
746 break;
747
748 fRunFileOffset = fRunBlockEnd;
749 fRunBlockEnd += fInode->data.direct[fCurrent].length << fDisk->BlockShift();
750 if (fRunBlockEnd > pos)
751 break;
752 }
753 if (fCurrent == NUM_DIRECT_BLOCKS12 || fInode->data.direct[fCurrent].IsZero())
754 return B_ERROR(-1);
755
756 fRun = fInode->data.direct[fCurrent];
757 //printf("### run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
758 }
759 return B_OK((int)0);
760}
761
762
763ssize_t
764DataStream::ReadAt(off_t pos, void *buffer, size_t size)
765{
766 NodeGetter _(this);
767
768 //printf("DataStream::ReadAt(pos = %Ld,buffer = %p,size = %ld);\n",pos,buffer,size);
769 // truncate size to read
770 if (pos + (off_t)size > fInode->data.size) {
771 if (pos > fInode->data.size) // reading outside the file
772 return B_ERROR(-1);
773
774 size = fInode->data.size - pos;
775 if (!size) // there is nothing left to read
776 return 0;
777 }
778 ssize_t read = 0;
779
780 //printf("### read %ld bytes at %Ld\n",size,pos);
781 while (size > 0) {
782 status_t status = FindBlockRun(pos);
783 if (status < B_OK((int)0))
784 return status;
785
786 ssize_t bytes = min_c((off_t)size, fRunBlockEnd - pos)(((off_t)size)>(fRunBlockEnd - pos)?(fRunBlockEnd - pos):(
(off_t)size))
;
787
788 //printf("### read %ld bytes from %Ld\n### --\n",bytes,fDisk->ToOffset(fRun) + pos - fRunFileOffset);
789 bytes = fDisk->ReadAt(fDisk->ToOffset(fRun) + pos - fRunFileOffset,
790 buffer, bytes);
791 if (bytes <= 0) {
792 if (bytes == 0) {
793 printf("could not read bytes at: %" B_PRId32"l" "d" ",%d\n",
794 fRun.allocation_group, fRun.start);
795 }
796 return bytes < 0 ? bytes : B_BAD_DATA((-2147483647 - 1) + 16);
797 }
798
799 buffer = (void *)((uint8 *)buffer + bytes);
800 size -= bytes;
801 pos += bytes;
802 read += bytes;
803 }
804 if (read >= 0)
805 return read;
806
807 return B_IO_ERROR((-2147483647 - 1) + 1);
808}
809
810
811ssize_t
812DataStream::WriteAt(off_t pos, const void *buffer, size_t size)
813{
814 NodeGetter _(this);
815
816 // FIXME: truncate size -> should enlargen the file
817 if (pos + (off_t)size > fInode->data.size) {
818 if (pos > fInode->data.size) // writing outside the file
819 return B_ERROR(-1);
820
821 size = fInode->data.size - pos;
822 if (!size) // there is nothing left to write
823 return 0;
824 }
825 ssize_t written = 0;
826
827 //printf("### write %ld bytes at %Ld\n",size,pos);
828 while (size > 0) {
829 status_t status = FindBlockRun(pos);
830 if (status < B_OK((int)0))
831 return status;
832
833 ssize_t bytes = min_c((off_t)size, fRunBlockEnd - pos)(((off_t)size)>(fRunBlockEnd - pos)?(fRunBlockEnd - pos):(
(off_t)size))
;
834
835 //printf("### write %ld bytes to %Ld\n### --\n",bytes,fDisk->ToOffset(fRun) + pos - fRunFileOffset);
836 bytes = fDisk->WriteAt(fDisk->ToOffset(fRun) + pos - fRunFileOffset,buffer,bytes);
837 if (bytes < 0)
838 return bytes;
839
840 buffer = (void *)((uint8 *)buffer + bytes);
841 size -= bytes;
842 pos += bytes;
843 written += bytes;
844 }
845 if (written >= 0)
846 return written;
847
848 return B_IO_ERROR((-2147483647 - 1) + 1);
849}
850
851
852off_t
853DataStream::Seek(off_t position, uint32 seekMode)
854{
855 NodeGetter _(this);
856
857 if (seekMode == SEEK_SET0)
858 fPosition = position;
859 else if (seekMode == SEEK_END2)
860 fPosition = fInode->data.size + position;
861 else
862 fPosition += position;
863
864 return fPosition;
865}
866
867
868off_t
869DataStream::Position() const
870{
871 return fPosition;
872}
873
874
875status_t
876DataStream::SetSize(off_t size)
877{
878 NodeGetter _(this);
879
880 // FIXME: not yet supported
881 if (size > fInode->data.size || size > fInode->data.max_direct_range)
882 return B_ERROR(-1);
883
884 if (size == fInode->data.size)
885 return B_OK((int)0);
886
887 BufferClobbered();
888
889 fInode->data.size = size;
890 fInode->data.max_direct_range = size;
891 fInode->data.max_indirect_range = 0;
892 fInode->data.max_double_indirect_range = 0;
893
894 for (int32 i = 0;i < NUM_DIRECT_BLOCKS12;i++) {
895 if (size <= 0)
896 fInode->data.direct[i].SetTo(0, 0, 0);
897 else if ((fInode->data.direct[i].length << fDisk->BlockShift()) >= size) {
898 off_t blocks = (size + fDisk->BlockSize() - 1) / fDisk->BlockSize();
899 fInode->data.direct[i].length = blocks;
900 size = 0;
901 } else
902 size -= fInode->data.direct[i].length << fDisk->BlockShift();
903 }
904
905 return B_OK((int)0);
906}
907
908
909// #pragma mark -
910
911
912File::File(Disk *disk, bfs_inode *inode,bool ownBuffer)
913 : DataStream(disk,inode,ownBuffer)
914{
915}
916
917
918File::File(const Inode &inode)
919 : DataStream(inode)
920{
921}
922
923
924File::~File()
925{
926}
927
928
929status_t
930File::InitCheck()
931{
932 status_t status = DataStream::InitCheck();
933 if (status == B_OK((int)0))
934 return IsFile() ? B_OK((int)0) : B_ERROR(-1);
935
936 return status;
937}
938
939
940status_t
941File::CopyTo(const char *root, bool fullPath, Inode::Source *source)
942{
943 status_t status = Inode::CopyTo(root, fullPath, source);
944 if (status < B_OK((int)0))
945 return status;
946
947 BPath path(root);
948 if (fullPath && Path(source))
949 path.Append(Path(source));
950
951 char *name = (char *)Name();
952 if (name != NULL__null) {
953 // changes the filename in the inode buffer (for deleted entries)
954 if (!*name)
955 *name = '_';
956 path.Append(name);
957 } else {
958 BString sub;
959 sub << "__untitled " << BlockRun().allocation_group << ":"
960 << (int32)BlockRun().start;
961 path.Append(sub.String());
962 }
963 printf("%" B_PRId32"l" "d" ",%d -> %s\n", BlockRun().allocation_group,
964 BlockRun().start, path.Path());
965
966 BFile file;
967 status = file.SetTo(path.Path(),
968 B_WRITE_ONLY0x0001 | B_CREATE_FILE0x0200 | B_FAIL_IF_EXISTS0x0100);
969 if (status < B_OK((int)0))
970 return status;
971
972 char buffer[fDisk->BlockSize()];
973 ssize_t size;
974 Seek(0, SEEK_SET0);
975
976 while ((size = Read(buffer, sizeof(buffer))) > B_OK((int)0)) {
977 ssize_t written = file.Write(buffer, size);
978 if (written < B_OK((int)0))
979 return written;
980 }
981
982 return CopyAttributesTo(&file);
983}
984
985
986// #pragma mark -
987
988
989Attribute::Attribute(Disk *disk, bfs_inode *inode, bool ownBuffer)
990 : File(disk, inode, ownBuffer)
991{
992}
993
994
995Attribute::Attribute(const Inode &inode)
996 : File(inode)
997{
998}
999
1000
1001Attribute::~Attribute()
1002{
1003}
1004
1005
1006status_t
1007Attribute::InitCheck()
1008{
1009 status_t status = DataStream::InitCheck();
1010 if (status == B_OK((int)0))
1011 return IsAttribute() ? B_OK((int)0) : B_ERROR(-1);
1012
1013 return status;
1014}
1015
1016
1017status_t
1018Attribute::CopyTo(const char */*path*/, bool /*fullPath*/,
1019 Inode::Source */*source*/)
1020{
1021 // files and directories already copy all attributes
1022
1023 // eventually, this method should be implemented to recover lost
1024 // attributes on the disk
1025
1026 return B_OK((int)0);
1027}
1028
1029
1030// #pragma mark -
1031
1032
1033Directory::Directory(Disk *disk, bfs_inode *inode, bool ownBuffer)
1034 : DataStream(disk, inode, ownBuffer),
1035 fTree(NULL__null)
1036{
1037}
1038
1039
1040Directory::Directory(const Inode &inode)
1041 : DataStream(inode),
1042 fTree(NULL__null)
1043{
1044}
1045
1046
1047Directory::~Directory()
1048{
1049 delete fTree;
1050}
1051
1052
1053status_t
1054Directory::InitCheck()
1055{
1056 status_t status = DataStream::InitCheck();
1057 if (status == B_OK((int)0))
1058 return (IsDirectory() || IsAttributeDirectory()) ? B_OK((int)0) : B_ERROR(-1);
1059
1060 return status;
1061}
1062
1063
1064status_t
1065Directory::CopyTo(const char *root, bool fullPath, Inode::Source *source)
1066{
1067 // don't copy attributes or indices
1068 // the recovery program should make empty files to recover lost attributes
1069 if (IsAttributeDirectory() || IsIndex())
1070 return B_OK((int)0);
1071
1072 status_t status = Inode::CopyTo(root, fullPath, source);
1073 if (status < B_OK((int)0))
1074 return status;
1075
1076 BPath path(root);
1077 if (fullPath && Path(source))
1078 path.Append(Path(source));
1079
1080 char *name = (char *)Name();
1081 if (name != NULL__null) {
1082 // changes the filename in the inode buffer (for deleted entries)
1083 if (!*name)
1084 *name = '_';
1085 path.Append(name);
1086 } else {
1087 // create unique name
1088 BString sub;
1089 sub << "__untitled " << BlockRun().allocation_group << ":"
1090 << (int32)BlockRun().start;
1091 path.Append(sub.String());
1092 }
1093
1094 BEntry entry(path.Path());
1095 BDirectory directory;
1096 if ((status = entry.GetParent(&directory)) < B_OK((int)0))
1097 return status;
1098
1099 status = directory.CreateDirectory(path.Leaf(), NULL__null);
1100 if (status < B_OK((int)0) && status != B_FILE_EXISTS(((-2147483647 - 1) + 0x6000) + 2))
1101 return status;
1102
1103 if ((status = directory.SetTo(&entry)) < B_OK((int)0))
1104 return status;
1105
1106 return CopyAttributesTo(&directory);
1107}
1108
1109
1110status_t
1111Directory::Rewind()
1112{
1113 if (!fTree) {
1114 status_t status = CreateTree();
1115 if (status < B_OK((int)0))
1116 return status;
1117 }
1118 return fTree->Rewind();
1119}
1120
1121
1122status_t
1123Directory::GetNextEntry(char *name, block_run *run)
1124{
1125 status_t status;
1126
1127 if (!fTree) {
1128 if ((status = Rewind()) < B_OK((int)0))
1129 return status;
1130 }
1131 uint16 length;
1132 off_t offset;
1133
1134 if ((status = fTree->GetNextEntry(name, &length, B_FILE_NAME_LENGTH(256) - 1,
1135 &offset)) < B_OK((int)0))
1136 return status;
1137
1138 *run = fDisk->ToBlockRun(offset);
1139
1140 return B_OK((int)0);
1141}
1142
1143
1144status_t
1145Directory::GetNextEntry(block_run *run)
1146{
1147 char name[B_FILE_NAME_LENGTH(256)];
1148
1149 return GetNextEntry(name, run);
1150}
1151
1152
1153status_t
1154Directory::Contains(const block_run *run)
1155{
1156 status_t status;
1157
1158 if (!fTree) {
1159 if ((status = Rewind()) < B_OK((int)0))
1160 return status;
1161 }
1162
1163 block_run searchRun;
1164 while (GetNextEntry(&searchRun) == B_OK((int)0)) {
1165 if (searchRun == *run)
1166 return B_OK((int)0);
1167 }
1168
1169 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1170}
1171
1172
1173status_t
1174Directory::Contains(const Inode *inode)
1175{
1176 status_t status;
1177
1178 if (!fTree) {
1179 if ((status = CreateTree()) < B_OK((int)0))
1180 return status;
1181 }
1182
1183 off_t value;
1184 const char *name = inode->Name();
1185 status = B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1186
1187 if (name && (status = fTree->Find((uint8 *)name, (uint16)strlen(name),
1188 &value)) == B_OK((int)0)) {
1189 if (fDisk->ToBlockRun(value) == inode->InodeBuffer()->inode_num)
1190 return B_OK((int)0);
1191
1192 printf("inode address do not match (%s)!\n", inode->Name());
1193 }
1194
1195 if (status != B_OK((int)0) && status != B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3))
1196 return status;
1197
1198 return Contains(&inode->InodeBuffer()->inode_num);
1199}
1200
1201
1202status_t
1203Directory::FindEntry(const char *name, block_run *run)
1204{
1205 status_t status;
1206
1207 if (!name)
1208 return B_BAD_VALUE((-2147483647 - 1) + 5);
1209
1210 if (!fTree) {
1211 if ((status = CreateTree()) < B_OK((int)0))
1212 return status;
1213 }
1214
1215 off_t value;
1216
1217 if ((status = fTree->Find((uint8 *)name, (uint16)strlen(name),
1218 &value)) >= B_OK((int)0)) {
1219 if (run)
1220 *run = fDisk->ToBlockRun(value);
1221 return B_OK((int)0);
1222 }
1223 return status;
1224}
1225
1226
1227status_t
1228Directory::AddEntry(Inode *inode)
1229{
1230 status_t status;
1231 bool created = false;
1232
1233 if (!fTree) {
1234 status = CreateTree();
1235 if (status == B_OK((int)0))
1236 status = fTree->Validate();
1237
1238 if (status == B_BAD_DATA((-2147483647 - 1) + 16)) {
1239 //puts("bplustree corrupted!");
1240 fTree = new BPlusTree(BPLUSTREE_STRING_TYPE, BPLUSTREE_NODE_SIZE1024,
1241 false);
1242 if ((status = fTree->InitCheck()) < B_OK((int)0)) {
1243 delete fTree;
1244 fTree = NULL__null;
1245 } else
1246 created = true;
1247 }
1248
1249 if (status < B_OK((int)0))
1250 return status;
1251 }
1252 // keep all changes in memory
1253 fTree->SetHoldChanges(true);
1254
1255 if (created) {
1256 // add . and ..
1257 fTree->Insert(".", Block());
1258 fTree->Insert("..", fDisk->ToBlock(Parent()));
1259 }
1260
1261 if (inode->Flags() & INODE_DELETED)
1262 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1263
1264 BString name = inode->Name();
1265 if (name == "") {
1266 name << "__file " << inode->BlockRun().allocation_group << ":"
1267 << (int32)inode->BlockRun().start;
1268 }
1269
1270 return fTree->Insert(name.String(), inode->Block());
1271}
1272
1273
1274status_t
1275Directory::CreateTree()
1276{
1277 fTree = new BPlusTree(this);
1278
1279 status_t status = fTree->InitCheck();
1280 if (status < B_OK((int)0)) {
1281 delete fTree;
1282 fTree = NULL__null;
1283 return status;
1284 }
1285 return B_OK((int)0);
1286}
1287
1288
1289status_t
1290Directory::GetTree(BPlusTree **tree)
1291{
1292 if (!fTree) {
1293 status_t status = CreateTree();
1294 if (status < B_OK((int)0))
1295 return status;
1296 }
1297 *tree = fTree;
1298 return B_OK((int)0);
1299}
1300
1301
1302// #pragma mark -
1303
1304
1305Symlink::Symlink(Disk *disk, bfs_inode *inode,bool ownBuffer)
1306 : Inode(disk,inode,ownBuffer)
1307{
1308}
1309
1310
1311Symlink::Symlink(const Inode &inode)
1312 : Inode(inode)
1313{
1314}
1315
1316
1317Symlink::~Symlink()
1318{
1319}
1320
1321
1322status_t
1323Symlink::InitCheck()
1324{
1325 status_t status = Inode::InitCheck();
1326 if (status == B_OK((int)0))
1327 return IsSymlink() ? B_OK((int)0) : B_ERROR(-1);
1328
1329 return status;
1330}
1331
1332
1333status_t
1334Symlink::CopyTo(const char *root, bool fullPath,Inode::Source *source)
1335{
1336 status_t status = Inode::CopyTo(root,fullPath,source);
1337 if (status < B_OK((int)0))
1338 return status;
1339
1340 BPath path(root);
1341 if (fullPath && Path(source))
1342 path.Append(Path(source));
1343
1344 char *name = (char *)Name();
1345 if (name != NULL__null) {
1346 // changes the filename in the inode buffer (for deleted entries)
1347 if (!*name)
1348 *name = '_';
1349 path.Append(name);
1350 } else {
1351 // create unique name
1352 BString sub;
1353 sub << "__symlink " << BlockRun().allocation_group << ":"
1354 << (int32)BlockRun().start;
1355 path.Append(sub.String());
1356 }
1357
1358 BEntry entry(path.Path());
1359 BDirectory directory;
1360 if ((status = entry.GetParent(&directory)) < B_OK((int)0))
1361 return status;
1362
1363 char to[2048];
1364 if (LinksTo(to,sizeof(to)) < B_OK((int)0))
1365 return B_ERROR(-1);
1366
1367 BSymLink link;
1368 status = directory.CreateSymLink(path.Leaf(),to,&link);
1369 if (status < B_OK((int)0) && status != B_FILE_EXISTS(((-2147483647 - 1) + 0x6000) + 2))
1370 return status;
1371
1372 if ((status = link.SetTo(&entry)) < B_OK((int)0))
1373 return status;
1374
1375 return CopyAttributesTo(&link);
1376}
1377
1378
1379status_t
1380Symlink::LinksTo(char *to,size_t maxLength)
1381{
1382 if ((fInode->flags & INODE_LONG_SYMLINK) == 0) {
1383 strcpy(to,fInode->short_symlink);
1384 return B_OK((int)0);
1385 }
1386
1387 DataStream stream(*this);
1388 status_t status = stream.InitCheck();
1389 if (status < B_OK((int)0))
1390 return status;
1391
1392 status = stream.Read(to,maxLength);
1393
1394 return status < B_OK((int)0) ? status : B_OK((int)0);
1395}
1396