2 * Copyright 2001-2008 pinc Software. All Rights Reserved.
3 * Released under the terms of the MIT license.
10 #include "BPlusTree.h"
12 #include <Directory.h>
26 NodeGetter(Inode
* inode
)
30 fInode
->AcquireBuffer();
35 fInode
->ReleaseBuffer();
46 Inode::Inode(Disk
* disk
, bfs_inode
* inode
, bool ownBuffer
)
50 fOwnBuffer(ownBuffer
),
53 fCurrentSmallData(NULL
),
55 fAttributeBuffer(NULL
)
58 fBlockRun
= inode
->inode_num
;
62 Inode::Inode(const Inode
& inode
)
68 fBlockRun(inode
.fBlockRun
),
70 fCurrentSmallData(NULL
),
72 fAttributeBuffer(NULL
)
90 fBlockRun
.SetTo(0, 0, 0);
101 Inode::SetTo(bfs_inode
*inode
)
106 fBlockRun
= inode
->inode_num
;
112 Inode::InitCheck() const
117 // test inode magic and flags
118 if (fInode
->magic1
!= INODE_MAGIC1
119 || !(fInode
->flags
& INODE_IN_USE
)
120 || fInode
->inode_num
.length
!= 1)
123 if (fDisk
->BlockSize()) {
124 // matches known block size?
125 if (fInode
->inode_size
!= fDisk
->SuperBlock()->inode_size
126 // parent resides on disk?
127 || fInode
->parent
.allocation_group
> fDisk
->SuperBlock()->num_ags
128 || fInode
->parent
.allocation_group
< 0
129 || fInode
->parent
.start
> (1L << fDisk
->SuperBlock()->ag_shift
)
130 || fInode
->parent
.length
!= 1
132 || fInode
->attributes
.allocation_group
> fDisk
->SuperBlock()->num_ags
133 || fInode
->attributes
.allocation_group
< 0
134 || fInode
->attributes
.start
> (1L << fDisk
->SuperBlock()->ag_shift
))
137 // is inode size one of the valid values?
138 switch (fInode
->inode_size
) {
149 // is inode on a boundary matching it's size?
150 //return (Offset() % fInode->inode_size) == 0 ? B_OK : B_ERROR;
160 bfs_inode
*buffer
= (bfs_inode
*)malloc(fInode
->inode_size
);
164 memcpy(buffer
, fInode
, fInode
->inode_size
);
168 // this must not be deleted anymore
177 static bigtime_t lastChecked
;
178 static int32 percentUsed
;
180 if (system_time() > lastChecked
+ 1000000LL) {
182 get_system_info(&info
);
183 percentUsed
= 100 * info
.used_pages
/ info
.max_pages
;
186 return percentUsed
> 75;
191 Inode::ReleaseBuffer()
193 if (atomic_add(&fRefCount
, -1) != 1)
207 Inode::AcquireBuffer()
209 if (atomic_add(&fRefCount
, 1) != 0)
212 if (!fOwnBuffer
|| fInode
!= NULL
)
215 fInode
= (bfs_inode
*)malloc(fDisk
->BlockSize());
219 ssize_t bytesRead
= fDisk
->ReadAt(Offset(), fInode
, fDisk
->BlockSize());
220 if (bytesRead
< B_OK
)
228 Inode::BufferClobbered()
235 Inode::SetParent(const block_run
& run
)
237 fInode
->parent
= run
;
243 Inode::SetBlockRun(const block_run
& run
)
245 fInode
->inode_num
= run
;
252 Inode::SetMode(uint32 mode
)
260 Inode::SetName(const char *name
)
262 if (name
== NULL
|| *name
== '\0')
265 small_data
*data
= fInode
->small_data_start
, *nameData
= NULL
;
268 while (!data
->IsLast(fInode
)) {
269 if (data
->type
== FILE_NAME_TYPE
270 && data
->name_size
== FILE_NAME_NAME_LENGTH
271 && *data
->Name() == FILE_NAME_NAME
)
277 int32 oldLength
= nameData
== NULL
? 0 : nameData
->data_size
;
278 int32 newLength
= strlen(name
) + (nameData
== NULL
? sizeof(small_data
) + 5 : 0);
280 if ((addr_t
)data
+ newLength
- oldLength
>= (addr_t
)(fInode
281 + fDisk
->BlockSize()))
284 if (nameData
== NULL
) {
285 memmove(newLength
+ (uint8
*)fInode
->small_data_start
,
286 fInode
->small_data_start
,
287 (addr_t
)data
- (addr_t
)fInode
->small_data_start
);
288 nameData
= fInode
->small_data_start
;
290 memmove(newLength
+ (uint8
*)nameData
, nameData
,
291 (addr_t
)data
- (addr_t
)fInode
->small_data_start
);
294 memset(nameData
, 0, sizeof(small_data
) + 5 + strlen(name
));
295 nameData
->type
= FILE_NAME_TYPE
;
296 nameData
->name_size
= FILE_NAME_NAME_LENGTH
;
297 nameData
->data_size
= strlen(name
);
298 *nameData
->Name() = FILE_NAME_NAME
;
299 strcpy((char *)nameData
->Data(),name
);
308 if (InitCheck() != B_OK
) {
309 puts("Not getting name because node is invalid");
312 small_data
*data
= fInode
->small_data_start
;
313 while (!data
->IsLast(fInode
)) {
314 if (data
->type
== FILE_NAME_TYPE
315 && data
->name_size
== FILE_NAME_NAME_LENGTH
316 && *data
->Name() == FILE_NAME_NAME
)
317 return (const char *)data
->Data();
326 Inode::GetNextSmallData(small_data
**smallData
)
331 small_data
*data
= *smallData
;
333 // begin from the start?
335 data
= fInode
->small_data_start
;
339 // is already last item?
340 if (data
->IsLast(fInode
))
341 return B_ENTRY_NOT_FOUND
;
349 Inode::RewindAttributes()
351 fCurrentSmallData
= NULL
;
353 if (fAttributes
!= NULL
)
354 fAttributes
->Rewind();
361 Inode::GetNextAttribute(char *name
, uint32
*type
, void **data
, size_t *length
)
363 // read attributes out of the small data section
365 if (fCurrentSmallData
== NULL
|| !fCurrentSmallData
->IsLast(fInode
)) {
366 if (fCurrentSmallData
== NULL
)
367 fCurrentSmallData
= fInode
->small_data_start
;
369 fCurrentSmallData
= fCurrentSmallData
->Next();
371 // skip name attribute
372 if (!fCurrentSmallData
->IsLast(fInode
)
373 && fCurrentSmallData
->name_size
== FILE_NAME_NAME_LENGTH
374 && *fCurrentSmallData
->Name() == FILE_NAME_NAME
)
375 fCurrentSmallData
= fCurrentSmallData
->Next();
377 if (!fCurrentSmallData
->IsLast(fInode
)) {
378 strncpy(name
,fCurrentSmallData
->Name(), B_FILE_NAME_LENGTH
);
379 *type
= fCurrentSmallData
->type
;
380 *data
= fCurrentSmallData
->Data();
381 *length
= fCurrentSmallData
->data_size
;
387 // read attributes out of the attribute directory
389 if (Attributes().IsZero())
390 return B_ENTRY_NOT_FOUND
;
392 if (fAttributes
== NULL
)
393 fAttributes
= (Directory
*)Inode::Factory(fDisk
, Attributes());
395 status_t status
= fAttributes
? fAttributes
->InitCheck() : B_ERROR
;
400 status
= fAttributes
->GetNextEntry(name
, &run
);
402 free(fAttributeBuffer
);
403 fAttributeBuffer
= NULL
;
407 Attribute
*attribute
= (Attribute
*)Inode::Factory(fDisk
, run
);
408 if (attribute
== NULL
|| attribute
->InitCheck() < B_OK
)
411 *type
= attribute
->Type();
413 void *buffer
= realloc(fAttributeBuffer
, attribute
->Size());
414 if (buffer
== NULL
) {
415 free(fAttributeBuffer
);
416 fAttributeBuffer
= NULL
;
420 fAttributeBuffer
= buffer
;
422 ssize_t size
= attribute
->Read(fAttributeBuffer
, attribute
->Size());
426 *data
= fAttributeBuffer
;
428 return size
< B_OK
? size
: B_OK
;
433 Inode::_FindPath(Inode::Source
*source
)
437 block_run parent
= Parent();
438 while (!parent
.IsZero() && parent
!= fDisk
->Root()) {
441 inode
= source
->InodeAt(parent
);
443 inode
= Inode::Factory(fDisk
, parent
);
446 || inode
->InitCheck() < B_OK
447 || inode
->Name() == NULL
448 || !*inode
->Name()) {
450 sub
<< "__recovered " << parent
.allocation_group
<< ":"
451 << (int32
)parent
.start
<< "/";
457 parent
= inode
->Parent();
459 path
.Prepend(inode
->Name());
463 fPath
= strdup(path
.String());
470 Inode::Path(Inode::Source
*source
)
480 Inode::CopyTo(const char *root
, bool fullPath
, Inode::Source
*source
)
483 return B_ENTRY_NOT_FOUND
;
488 path
.Append(Path(source
));
490 if (*(root
+ strlen(root
) - 1) != '/')
494 return create_directory(path
.String(), 0777);
499 Inode::CopyAttributesTo(BNode
*node
)
505 char name
[B_FILE_NAME_LENGTH
];
506 const uint32 kMaxBrokenAttributes
= 64;
514 while ((status
= GetNextAttribute(name
, &type
, &data
, &size
))
515 != B_ENTRY_NOT_FOUND
) {
516 if (status
!= B_OK
) {
517 printf("could not open attribute (possibly: %s): %s!\n",
518 name
, strerror(status
));
519 if (count
++ > kMaxBrokenAttributes
)
525 ssize_t written
= node
->WriteAttr(name
, type
, 0, data
, size
);
526 if (written
< B_OK
) {
527 printf("could not write attribute \"%s\": %s\n", name
,
529 } else if ((size_t)written
< size
) {
530 printf("could only write %ld bytes (from %ld) at attribute \"%s\"\n",
531 written
, size
, name
);
537 node
->SetPermissions(fInode
->mode
);
538 node
->SetOwner(fInode
->uid
);
539 node
->SetGroup(fInode
->gid
);
540 node
->SetModificationTime(fInode
->last_modified_time
>> 16);
541 node
->SetCreationTime(fInode
->create_time
>> 16);
548 Inode::Factory(Disk
*disk
, bfs_inode
*inode
, bool ownBuffer
)
550 // attributes (of a file)
551 if ((inode
->mode
& (S_ATTR
| S_ATTR_DIR
)) == S_ATTR
)
552 return new Attribute(disk
, inode
, ownBuffer
);
554 // directories, attribute directories, indices
555 if (S_ISDIR(inode
->mode
) || inode
->mode
& S_ATTR_DIR
)
556 return new Directory(disk
, inode
, ownBuffer
);
559 if (S_ISREG(inode
->mode
))
560 return new File(disk
, inode
, ownBuffer
);
562 // symlinks (short and link in data-stream)
563 if (S_ISLNK(inode
->mode
))
564 return new Symlink(disk
, inode
, ownBuffer
);
571 Inode::Factory(Disk
*disk
, block_run run
)
573 bfs_inode
*inode
= (bfs_inode
*)malloc(disk
->BlockSize());
577 if (disk
->ReadAt(disk
->ToOffset(run
), inode
, disk
->BlockSize()) <= 0)
580 Inode
*object
= Factory(disk
, inode
);
589 Inode::Factory(Disk
*disk
, Inode
*inode
, bool copyBuffer
)
591 bfs_inode
*inodeBuffer
= inode
->fInode
;
594 bfs_inode
*inodeCopy
= (bfs_inode
*)malloc(inodeBuffer
->inode_size
);
598 memcpy(inodeCopy
, inodeBuffer
, inodeBuffer
->inode_size
);
599 inodeBuffer
= inodeCopy
;
601 return Factory(disk
, inodeBuffer
, copyBuffer
);
606 Inode::EmptyInode(Disk
*disk
, const char *name
, int32 mode
)
608 bfs_inode
*inode
= (bfs_inode
*)malloc(disk
->BlockSize());
612 memset(inode
, 0, sizeof(bfs_inode
));
614 inode
->magic1
= INODE_MAGIC1
;
615 inode
->inode_size
= disk
->BlockSize();
617 inode
->flags
= INODE_IN_USE
| (mode
& S_IFDIR
? INODE_LOGGED
: 0);
620 small_data
*data
= inode
->small_data_start
;
621 data
->type
= FILE_NAME_TYPE
;
622 data
->name_size
= FILE_NAME_NAME_LENGTH
;
623 *data
->Name() = FILE_NAME_NAME
;
624 data
->data_size
= strlen(name
);
625 strcpy((char *)data
->Data(), name
);
628 Inode
*object
= new (std::nothrow
) Inode(disk
, inode
);
629 if (object
== NULL
) {
634 object
->AcquireBuffer();
635 // this must not be deleted anymore!
643 DataStream::DataStream(Disk
*disk
, bfs_inode
*inode
, bool ownBuffer
)
644 : Inode(disk
,inode
,ownBuffer
),
651 DataStream::DataStream(const Inode
&inode
)
659 DataStream::~DataStream()
665 DataStream::FindBlockRun(off_t pos
)
669 if (pos
> fInode
->data
.size
)
670 return B_ENTRY_NOT_FOUND
;
675 fRunBlockEnd
= fCurrent
>= 0
676 ? fRunFileOffset
+ (fRun
.length
<< fDisk
->BlockShift()) : 0LL;
678 // access in current block run?
680 if (fCurrent
>= 0 && pos
>= fRunFileOffset
&& pos
< fRunBlockEnd
)
683 // find matching block run
685 if (fInode
->data
.max_direct_range
> 0
686 && pos
>= fInode
->data
.max_direct_range
) {
687 if (fInode
->data
.max_double_indirect_range
> 0
688 && pos
>= fInode
->data
.max_indirect_range
) {
689 // read from double indirect blocks
691 //printf("find double indirect block: %ld,%d!\n",fInode->data.double_indirect.allocation_group,fInode->data.double_indirect.start);
692 block_run
*indirect
= (block_run
*)fDisk
->ReadBlockRun(fInode
->data
.double_indirect
);
693 if (indirect
== NULL
)
696 off_t start
= pos
- fInode
->data
.max_indirect_range
;
697 int32 indirectSize
= fDisk
->BlockSize() * 16 * (fDisk
->BlockSize() / sizeof(block_run
));
698 int32 directSize
= fDisk
->BlockSize() * 4;
699 int32 index
= start
/ indirectSize
;
701 //printf("\tstart = %Ld, indirectSize = %ld, directSize = %ld, index = %ld\n",start,indirectSize,directSize,index);
702 //printf("\tlook for indirect block at %ld,%d\n",indirect[index].allocation_group,indirect[index].start);
703 indirect
= (block_run
*)fDisk
->ReadBlockRun(indirect
[index
]);
704 if (indirect
== NULL
)
707 fCurrent
= (start
% indirectSize
) / directSize
;
708 fRunFileOffset
= fInode
->data
.max_indirect_range
+ (index
* indirectSize
) + (fCurrent
* directSize
);
709 fRunBlockEnd
= fRunFileOffset
+ directSize
;
710 fRun
= indirect
[fCurrent
];
711 //printf("\tfCurrent = %ld, fRunFileOffset = %Ld, fRunBlockEnd = %Ld, fRun = %ld,%d\n",fCurrent,fRunFileOffset,fRunBlockEnd,fRun.allocation_group,fRun.start);
713 // access from indirect blocks
715 block_run
*indirect
= (block_run
*)fDisk
->ReadBlockRun(fInode
->data
.indirect
);
719 int32 indirectRuns
= (fInode
->data
.indirect
.length
<< fDisk
->BlockShift()) / sizeof(block_run
);
721 if (fLevel
!= 1 || pos
< fRunFileOffset
) {
722 fRunBlockEnd
= fInode
->data
.max_direct_range
;
727 while (++fCurrent
< indirectRuns
) {
728 if (indirect
[fCurrent
].IsZero())
731 fRunFileOffset
= fRunBlockEnd
;
732 fRunBlockEnd
+= indirect
[fCurrent
].length
<< fDisk
->BlockShift();
733 if (fRunBlockEnd
> pos
)
736 if (fCurrent
== indirectRuns
|| indirect
[fCurrent
].IsZero())
739 fRun
= indirect
[fCurrent
];
740 //printf("reading from indirect block: %ld,%d\n",fRun.allocation_group,fRun.start);
741 //printf("### indirect-run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
744 // access from direct blocks
745 if (fRunFileOffset
> pos
) {
751 while (++fCurrent
< NUM_DIRECT_BLOCKS
) {
752 if (fInode
->data
.direct
[fCurrent
].IsZero())
755 fRunFileOffset
= fRunBlockEnd
;
756 fRunBlockEnd
+= fInode
->data
.direct
[fCurrent
].length
<< fDisk
->BlockShift();
757 if (fRunBlockEnd
> pos
)
760 if (fCurrent
== NUM_DIRECT_BLOCKS
|| fInode
->data
.direct
[fCurrent
].IsZero())
763 fRun
= fInode
->data
.direct
[fCurrent
];
764 //printf("### run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
771 DataStream::ReadAt(off_t pos
, void *buffer
, size_t size
)
775 //printf("DataStream::ReadAt(pos = %Ld,buffer = %p,size = %ld);\n",pos,buffer,size);
776 // truncate size to read
777 if (pos
+ (off_t
)size
> fInode
->data
.size
) {
778 if (pos
> fInode
->data
.size
) // reading outside the file
781 size
= fInode
->data
.size
- pos
;
782 if (!size
) // there is nothing left to read
787 //printf("### read %ld bytes at %Ld\n",size,pos);
789 status_t status
= FindBlockRun(pos
);
793 ssize_t bytes
= min_c((off_t
)size
, fRunBlockEnd
- pos
);
795 //printf("### read %ld bytes from %Ld\n### --\n",bytes,fDisk->ToOffset(fRun) + pos - fRunFileOffset);
796 bytes
= fDisk
->ReadAt(fDisk
->ToOffset(fRun
) + pos
- fRunFileOffset
,
800 printf("could not read bytes at: %" B_PRId32
",%d\n",
801 fRun
.allocation_group
, fRun
.start
);
803 return bytes
< 0 ? bytes
: B_BAD_DATA
;
806 buffer
= (void *)((uint8
*)buffer
+ bytes
);
819 DataStream::WriteAt(off_t pos
, const void *buffer
, size_t size
)
823 // FIXME: truncate size -> should enlargen the file
824 if (pos
+ (off_t
)size
> fInode
->data
.size
) {
825 if (pos
> fInode
->data
.size
) // writing outside the file
828 size
= fInode
->data
.size
- pos
;
829 if (!size
) // there is nothing left to write
834 //printf("### write %ld bytes at %Ld\n",size,pos);
836 status_t status
= FindBlockRun(pos
);
840 ssize_t bytes
= min_c((off_t
)size
, fRunBlockEnd
- pos
);
842 //printf("### write %ld bytes to %Ld\n### --\n",bytes,fDisk->ToOffset(fRun) + pos - fRunFileOffset);
843 bytes
= fDisk
->WriteAt(fDisk
->ToOffset(fRun
) + pos
- fRunFileOffset
,buffer
,bytes
);
847 buffer
= (void *)((uint8
*)buffer
+ bytes
);
860 DataStream::Seek(off_t position
, uint32 seekMode
)
864 if (seekMode
== SEEK_SET
)
865 fPosition
= position
;
866 else if (seekMode
== SEEK_END
)
867 fPosition
= fInode
->data
.size
+ position
;
869 fPosition
+= position
;
876 DataStream::Position() const
883 DataStream::SetSize(off_t size
)
887 // FIXME: not yet supported
888 if (size
> fInode
->data
.size
|| size
> fInode
->data
.max_direct_range
)
891 if (size
== fInode
->data
.size
)
896 fInode
->data
.size
= size
;
897 fInode
->data
.max_direct_range
= size
;
898 fInode
->data
.max_indirect_range
= 0;
899 fInode
->data
.max_double_indirect_range
= 0;
901 for (int32 i
= 0;i
< NUM_DIRECT_BLOCKS
;i
++) {
903 fInode
->data
.direct
[i
].SetTo(0, 0, 0);
904 else if ((fInode
->data
.direct
[i
].length
<< fDisk
->BlockShift()) >= size
) {
905 off_t blocks
= (size
+ fDisk
->BlockSize() - 1) / fDisk
->BlockSize();
906 fInode
->data
.direct
[i
].length
= blocks
;
909 size
-= fInode
->data
.direct
[i
].length
<< fDisk
->BlockShift();
919 File::File(Disk
*disk
, bfs_inode
*inode
,bool ownBuffer
)
920 : DataStream(disk
,inode
,ownBuffer
)
925 File::File(const Inode
&inode
)
937 File::InitCheck() const
939 status_t status
= DataStream::InitCheck();
941 return IsFile() ? B_OK
: B_ERROR
;
948 File::CopyTo(const char *root
, bool fullPath
, Inode::Source
*source
)
950 status_t status
= Inode::CopyTo(root
, fullPath
, source
);
955 if (fullPath
&& Path(source
))
956 path
.Append(Path(source
));
958 char *name
= (char *)Name();
960 // changes the filename in the inode buffer (for deleted entries)
966 sub
<< "__untitled " << BlockRun().allocation_group
<< ":"
967 << (int32
)BlockRun().start
;
968 path
.Append(sub
.String());
970 printf("%" B_PRId32
",%d -> %s\n", BlockRun().allocation_group
,
971 BlockRun().start
, path
.Path());
974 status
= file
.SetTo(path
.Path(),
975 B_WRITE_ONLY
| B_CREATE_FILE
| B_FAIL_IF_EXISTS
);
979 char buffer
[fDisk
->BlockSize()];
983 while ((size
= Read(buffer
, sizeof(buffer
))) > B_OK
) {
984 ssize_t written
= file
.Write(buffer
, size
);
989 return CopyAttributesTo(&file
);
996 Attribute::Attribute(Disk
*disk
, bfs_inode
*inode
, bool ownBuffer
)
997 : File(disk
, inode
, ownBuffer
)
1002 Attribute::Attribute(const Inode
&inode
)
1008 Attribute::~Attribute()
1014 Attribute::InitCheck() const
1016 status_t status
= DataStream::InitCheck();
1018 return IsAttribute() ? B_OK
: B_ERROR
;
1025 Attribute::CopyTo(const char */
*path*/
, bool /*fullPath*/,
1026 Inode::Source */
*source*/
)
1028 // files and directories already copy all attributes
1030 // eventually, this method should be implemented to recover lost
1031 // attributes on the disk
1040 Directory::Directory(Disk
*disk
, bfs_inode
*inode
, bool ownBuffer
)
1041 : DataStream(disk
, inode
, ownBuffer
),
1047 Directory::Directory(const Inode
&inode
)
1048 : DataStream(inode
),
1054 Directory::~Directory()
1061 Directory::InitCheck() const
1063 status_t status
= DataStream::InitCheck();
1065 return (IsDirectory() || IsAttributeDirectory()) ? B_OK
: B_ERROR
;
1072 Directory::CopyTo(const char *root
, bool fullPath
, Inode::Source
*source
)
1074 // don't copy attributes or indices
1075 // the recovery program should make empty files to recover lost attributes
1076 if (IsAttributeDirectory() || IsIndex())
1079 status_t status
= Inode::CopyTo(root
, fullPath
, source
);
1084 if (fullPath
&& Path(source
))
1085 path
.Append(Path(source
));
1087 char *name
= (char *)Name();
1089 // changes the filename in the inode buffer (for deleted entries)
1094 // create unique name
1096 sub
<< "__untitled " << BlockRun().allocation_group
<< ":"
1097 << (int32
)BlockRun().start
;
1098 path
.Append(sub
.String());
1101 BEntry
entry(path
.Path());
1102 BDirectory directory
;
1103 if ((status
= entry
.GetParent(&directory
)) < B_OK
)
1106 status
= directory
.CreateDirectory(path
.Leaf(), NULL
);
1107 if (status
< B_OK
&& status
!= B_FILE_EXISTS
)
1110 if ((status
= directory
.SetTo(&entry
)) < B_OK
)
1113 return CopyAttributesTo(&directory
);
1121 status_t status
= CreateTree();
1125 return fTree
->Rewind();
1130 Directory::GetNextEntry(char *name
, block_run
*run
)
1135 if ((status
= Rewind()) < B_OK
)
1141 if ((status
= fTree
->GetNextEntry(name
, &length
, B_FILE_NAME_LENGTH
- 1,
1145 *run
= fDisk
->ToBlockRun(offset
);
1152 Directory::GetNextEntry(block_run
*run
)
1154 char name
[B_FILE_NAME_LENGTH
];
1156 return GetNextEntry(name
, run
);
1161 Directory::Contains(const block_run
*run
)
1166 if ((status
= Rewind()) < B_OK
)
1170 block_run searchRun
;
1171 while (GetNextEntry(&searchRun
) == B_OK
) {
1172 if (searchRun
== *run
)
1176 return B_ENTRY_NOT_FOUND
;
1181 Directory::Contains(const Inode
*inode
)
1186 if ((status
= CreateTree()) < B_OK
)
1191 const char *name
= inode
->Name();
1192 status
= B_ENTRY_NOT_FOUND
;
1194 if (name
&& (status
= fTree
->Find((uint8
*)name
, (uint16
)strlen(name
),
1196 if (fDisk
->ToBlockRun(value
) == inode
->InodeBuffer()->inode_num
)
1199 printf("inode address do not match (%s)!\n", inode
->Name());
1202 if (status
!= B_OK
&& status
!= B_ENTRY_NOT_FOUND
)
1205 return Contains(&inode
->InodeBuffer()->inode_num
);
1210 Directory::FindEntry(const char *name
, block_run
*run
)
1218 if ((status
= CreateTree()) < B_OK
)
1224 if ((status
= fTree
->Find((uint8
*)name
, (uint16
)strlen(name
),
1227 *run
= fDisk
->ToBlockRun(value
);
1235 Directory::AddEntry(Inode
*inode
)
1238 bool created
= false;
1241 status
= CreateTree();
1243 status
= fTree
->Validate();
1245 if (status
== B_BAD_DATA
) {
1246 //puts("bplustree corrupted!");
1247 fTree
= new BPlusTree(BPLUSTREE_STRING_TYPE
, BPLUSTREE_NODE_SIZE
,
1249 if ((status
= fTree
->InitCheck()) < B_OK
) {
1259 // keep all changes in memory
1260 fTree
->SetHoldChanges(true);
1264 fTree
->Insert(".", Block());
1265 fTree
->Insert("..", fDisk
->ToBlock(Parent()));
1268 if (inode
->Flags() & INODE_DELETED
)
1269 return B_ENTRY_NOT_FOUND
;
1271 BString name
= inode
->Name();
1273 name
<< "__file " << inode
->BlockRun().allocation_group
<< ":"
1274 << (int32
)inode
->BlockRun().start
;
1277 return fTree
->Insert(name
.String(), inode
->Block());
1282 Directory::CreateTree()
1284 fTree
= new BPlusTree(this);
1286 status_t status
= fTree
->InitCheck();
1287 if (status
< B_OK
) {
1297 Directory::GetTree(BPlusTree
**tree
)
1300 status_t status
= CreateTree();
1312 Symlink::Symlink(Disk
*disk
, bfs_inode
*inode
,bool ownBuffer
)
1313 : Inode(disk
,inode
,ownBuffer
)
1318 Symlink::Symlink(const Inode
&inode
)
1330 Symlink::InitCheck() const
1332 status_t status
= Inode::InitCheck();
1334 return IsSymlink() ? B_OK
: B_ERROR
;
1341 Symlink::CopyTo(const char *root
, bool fullPath
,Inode::Source
*source
)
1343 status_t status
= Inode::CopyTo(root
,fullPath
,source
);
1348 if (fullPath
&& Path(source
))
1349 path
.Append(Path(source
));
1351 char *name
= (char *)Name();
1353 // changes the filename in the inode buffer (for deleted entries)
1358 // create unique name
1360 sub
<< "__symlink " << BlockRun().allocation_group
<< ":"
1361 << (int32
)BlockRun().start
;
1362 path
.Append(sub
.String());
1365 BEntry
entry(path
.Path());
1366 BDirectory directory
;
1367 if ((status
= entry
.GetParent(&directory
)) < B_OK
)
1371 if (LinksTo(to
,sizeof(to
)) < B_OK
)
1375 status
= directory
.CreateSymLink(path
.Leaf(),to
,&link
);
1376 if (status
< B_OK
&& status
!= B_FILE_EXISTS
)
1379 if ((status
= link
.SetTo(&entry
)) < B_OK
)
1382 return CopyAttributesTo(&link
);
1387 Symlink::LinksTo(char *to
,size_t maxLength
)
1389 if ((fInode
->flags
& INODE_LONG_SYMLINK
) == 0) {
1390 strcpy(to
,fInode
->short_symlink
);
1394 DataStream
stream(*this);
1395 status_t status
= stream
.InitCheck();
1399 status
= stream
.Read(to
,maxLength
);
1401 return status
< B_OK
? status
: B_OK
;