2 * Copyright 2001-2008 pinc Software. All Rights Reserved.
11 #include <Directory.h>
25 NodeGetter(Inode
* inode
)
29 fInode
->AcquireBuffer();
34 fInode
->ReleaseBuffer();
45 Inode::Inode(Disk
* disk
, bfs_inode
* inode
, bool ownBuffer
)
49 fOwnBuffer(ownBuffer
),
52 fCurrentSmallData(NULL
),
54 fAttributeBuffer(NULL
)
57 fBlockRun
= inode
->inode_num
;
61 Inode::Inode(const Inode
& inode
)
67 fBlockRun(inode
.fBlockRun
),
69 fCurrentSmallData(NULL
),
71 fAttributeBuffer(NULL
)
89 fBlockRun
.SetTo(0, 0, 0);
100 Inode::SetTo(bfs_inode
*inode
)
105 fBlockRun
= inode
->inode_num
;
111 Inode::InitCheck() const
116 // test inode magic and flags
117 if (fInode
->magic1
!= INODE_MAGIC1
118 || !(fInode
->flags
& INODE_IN_USE
)
119 || fInode
->inode_num
.length
!= 1)
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
131 || fInode
->attributes
.allocation_group
> fDisk
->SuperBlock()->num_ags
132 || fInode
->attributes
.allocation_group
< 0
133 || fInode
->attributes
.start
> (1L << fDisk
->SuperBlock()->ag_shift
))
136 // is inode size one of the valid values?
137 switch (fInode
->inode_size
) {
148 // is inode on a boundary matching it's size?
149 //return (Offset() % fInode->inode_size) == 0 ? B_OK : B_ERROR;
159 bfs_inode
*buffer
= (bfs_inode
*)malloc(fInode
->inode_size
);
163 memcpy(buffer
, fInode
, fInode
->inode_size
);
167 // this must not be deleted anymore
176 static bigtime_t lastChecked
;
177 static int32 percentUsed
;
179 if (system_time() > lastChecked
+ 1000000LL) {
181 get_system_info(&info
);
182 percentUsed
= 100 * info
.used_pages
/ info
.max_pages
;
185 return percentUsed
> 75;
190 Inode::ReleaseBuffer()
192 if (atomic_add(&fRefCount
, -1) != 1)
206 Inode::AcquireBuffer()
208 if (atomic_add(&fRefCount
, 1) != 0)
211 if (!fOwnBuffer
|| fInode
!= NULL
)
214 fInode
= (bfs_inode
*)malloc(fDisk
->BlockSize());
218 ssize_t bytesRead
= fDisk
->ReadAt(Offset(), fInode
, fDisk
->BlockSize());
219 if (bytesRead
< B_OK
)
227 Inode::BufferClobbered()
234 Inode::SetParent(const block_run
& run
)
236 fInode
->parent
= run
;
242 Inode::SetBlockRun(const block_run
& run
)
244 fInode
->inode_num
= run
;
251 Inode::SetMode(uint32 mode
)
259 Inode::SetName(const char *name
)
261 if (name
== NULL
|| *name
== '\0')
264 small_data
*data
= fInode
->small_data_start
, *nameData
= NULL
;
267 while (!data
->IsLast(fInode
)) {
268 if (data
->type
== FILE_NAME_TYPE
269 && data
->name_size
== FILE_NAME_NAME_LENGTH
270 && *data
->Name() == FILE_NAME_NAME
)
276 int32 oldLength
= nameData
== NULL
? 0 : nameData
->data_size
;
277 int32 newLength
= strlen(name
) + (nameData
== NULL
? sizeof(small_data
) + 5 : 0);
279 if ((addr_t
)data
+ newLength
- oldLength
>= (addr_t
)(fInode
280 + fDisk
->BlockSize()))
283 if (nameData
== 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
;
289 memmove(newLength
+ (uint8
*)nameData
, nameData
,
290 (addr_t
)data
- (addr_t
)fInode
->small_data_start
);
293 memset(nameData
, 0, sizeof(small_data
) + 5 + strlen(name
));
294 nameData
->type
= FILE_NAME_TYPE
;
295 nameData
->name_size
= FILE_NAME_NAME_LENGTH
;
296 nameData
->data_size
= strlen(name
);
297 *nameData
->Name() = FILE_NAME_NAME
;
298 strcpy((char *)nameData
->Data(),name
);
307 if (InitCheck() != B_OK
) {
308 puts("Not getting name because node is invalid");
311 small_data
*data
= fInode
->small_data_start
;
312 while (!data
->IsLast(fInode
)) {
313 if (data
->type
== FILE_NAME_TYPE
314 && data
->name_size
== FILE_NAME_NAME_LENGTH
315 && *data
->Name() == FILE_NAME_NAME
)
316 return (const char *)data
->Data();
325 Inode::GetNextSmallData(small_data
**smallData
)
330 small_data
*data
= *smallData
;
332 // begin from the start?
334 data
= fInode
->small_data_start
;
338 // is already last item?
339 if (data
->IsLast(fInode
))
340 return B_ENTRY_NOT_FOUND
;
348 Inode::RewindAttributes()
350 fCurrentSmallData
= NULL
;
352 if (fAttributes
!= NULL
)
353 fAttributes
->Rewind();
360 Inode::GetNextAttribute(char *name
, uint32
*type
, void **data
, size_t *length
)
362 // read attributes out of the small data section
364 if (fCurrentSmallData
== NULL
|| !fCurrentSmallData
->IsLast(fInode
)) {
365 if (fCurrentSmallData
== NULL
)
366 fCurrentSmallData
= fInode
->small_data_start
;
368 fCurrentSmallData
= fCurrentSmallData
->Next();
370 // skip name attribute
371 if (!fCurrentSmallData
->IsLast(fInode
)
372 && fCurrentSmallData
->name_size
== FILE_NAME_NAME_LENGTH
373 && *fCurrentSmallData
->Name() == FILE_NAME_NAME
)
374 fCurrentSmallData
= fCurrentSmallData
->Next();
376 if (!fCurrentSmallData
->IsLast(fInode
)) {
377 strncpy(name
,fCurrentSmallData
->Name(), B_FILE_NAME_LENGTH
);
378 *type
= fCurrentSmallData
->type
;
379 *data
= fCurrentSmallData
->Data();
380 *length
= fCurrentSmallData
->data_size
;
386 // read attributes out of the attribute directory
388 if (Attributes().IsZero())
389 return B_ENTRY_NOT_FOUND
;
391 if (fAttributes
== NULL
)
392 fAttributes
= (Directory
*)Inode::Factory(fDisk
, Attributes());
394 status_t status
= fAttributes
? fAttributes
->InitCheck() : B_ERROR
;
399 status
= fAttributes
->GetNextEntry(name
, &run
);
401 free(fAttributeBuffer
);
402 fAttributeBuffer
= NULL
;
406 Attribute
*attribute
= (Attribute
*)Inode::Factory(fDisk
, run
);
407 if (attribute
== NULL
|| attribute
->InitCheck() < B_OK
)
410 *type
= attribute
->Type();
412 void *buffer
= realloc(fAttributeBuffer
, attribute
->Size());
413 if (buffer
== NULL
) {
414 free(fAttributeBuffer
);
415 fAttributeBuffer
= NULL
;
419 fAttributeBuffer
= buffer
;
421 ssize_t size
= attribute
->Read(fAttributeBuffer
, attribute
->Size());
425 *data
= fAttributeBuffer
;
427 return size
< B_OK
? size
: B_OK
;
432 Inode::_FindPath(Inode::Source
*source
)
436 block_run parent
= Parent();
437 while (!parent
.IsZero() && parent
!= fDisk
->Root()) {
440 inode
= source
->InodeAt(parent
);
442 inode
= Inode::Factory(fDisk
, parent
);
445 || inode
->InitCheck() < B_OK
446 || inode
->Name() == NULL
447 || !*inode
->Name()) {
449 sub
<< "__recovered " << parent
.allocation_group
<< ":"
450 << (int32
)parent
.start
<< "/";
456 parent
= inode
->Parent();
458 path
.Prepend(inode
->Name());
462 fPath
= strdup(path
.String());
469 Inode::Path(Inode::Source
*source
)
479 Inode::CopyTo(const char *root
, bool fullPath
, Inode::Source
*source
)
482 return B_ENTRY_NOT_FOUND
;
487 path
.Append(Path(source
));
489 if (*(root
+ strlen(root
) - 1) != '/')
493 return create_directory(path
.String(), 0777);
498 Inode::CopyAttributesTo(BNode
*node
)
504 char name
[B_FILE_NAME_LENGTH
];
505 const uint32 kMaxBrokenAttributes
= 64;
513 while ((status
= GetNextAttribute(name
, &type
, &data
, &size
))
514 != B_ENTRY_NOT_FOUND
) {
515 if (status
!= B_OK
) {
516 printf("could not open attribute (possibly: %s): %s!\n",
517 name
, strerror(status
));
518 if (count
++ > kMaxBrokenAttributes
)
524 ssize_t written
= node
->WriteAttr(name
, type
, 0, data
, size
);
525 if (written
< B_OK
) {
526 printf("could not write attribute \"%s\": %s\n", name
,
528 } else if ((size_t)written
< size
) {
529 printf("could only write %ld bytes (from %ld) at attribute \"%s\"\n",
530 written
, size
, name
);
536 node
->SetPermissions(fInode
->mode
);
537 node
->SetOwner(fInode
->uid
);
538 node
->SetGroup(fInode
->gid
);
539 node
->SetModificationTime(fInode
->last_modified_time
>> 16);
540 node
->SetCreationTime(fInode
->create_time
>> 16);
547 Inode::Factory(Disk
*disk
, bfs_inode
*inode
, bool ownBuffer
)
549 // attributes (of a file)
550 if ((inode
->mode
& (S_ATTR
| S_ATTR_DIR
)) == S_ATTR
)
551 return new Attribute(disk
, inode
, ownBuffer
);
553 // directories, attribute directories, indices
554 if (S_ISDIR(inode
->mode
) || inode
->mode
& S_ATTR_DIR
)
555 return new Directory(disk
, inode
, ownBuffer
);
558 if (S_ISREG(inode
->mode
))
559 return new File(disk
, inode
, ownBuffer
);
561 // symlinks (short and link in data-stream)
562 if (S_ISLNK(inode
->mode
))
563 return new Symlink(disk
, inode
, ownBuffer
);
570 Inode::Factory(Disk
*disk
, block_run run
)
572 bfs_inode
*inode
= (bfs_inode
*)malloc(disk
->BlockSize());
576 if (disk
->ReadAt(disk
->ToOffset(run
), inode
, disk
->BlockSize()) <= 0)
579 Inode
*object
= Factory(disk
, inode
);
588 Inode::Factory(Disk
*disk
, Inode
*inode
, bool copyBuffer
)
590 bfs_inode
*inodeBuffer
= inode
->fInode
;
593 bfs_inode
*inodeCopy
= (bfs_inode
*)malloc(inodeBuffer
->inode_size
);
597 memcpy(inodeCopy
, inodeBuffer
, inodeBuffer
->inode_size
);
598 inodeBuffer
= inodeCopy
;
600 return Factory(disk
, inodeBuffer
, copyBuffer
);
605 Inode::EmptyInode(Disk
*disk
, const char *name
, int32 mode
)
607 bfs_inode
*inode
= (bfs_inode
*)malloc(disk
->BlockSize());
611 memset(inode
, 0, sizeof(bfs_inode
));
613 inode
->magic1
= INODE_MAGIC1
;
614 inode
->inode_size
= disk
->BlockSize();
616 inode
->flags
= INODE_IN_USE
| (mode
& S_IFDIR
? INODE_LOGGED
: 0);
619 small_data
*data
= inode
->small_data_start
;
620 data
->type
= FILE_NAME_TYPE
;
621 data
->name_size
= FILE_NAME_NAME_LENGTH
;
622 *data
->Name() = FILE_NAME_NAME
;
623 data
->data_size
= strlen(name
);
624 strcpy((char *)data
->Data(), name
);
627 Inode
*object
= new (std::nothrow
) Inode(disk
, inode
);
628 if (object
== NULL
) {
633 object
->AcquireBuffer();
634 // this must not be deleted anymore!
642 DataStream::DataStream(Disk
*disk
, bfs_inode
*inode
, bool ownBuffer
)
643 : Inode(disk
,inode
,ownBuffer
),
650 DataStream::DataStream(const Inode
&inode
)
658 DataStream::~DataStream()
664 DataStream::FindBlockRun(off_t pos
)
668 if (pos
> fInode
->data
.size
)
669 return B_ENTRY_NOT_FOUND
;
674 fRunBlockEnd
= fCurrent
>= 0
675 ? fRunFileOffset
+ (fRun
.length
<< fDisk
->BlockShift()) : 0LL;
677 // access in current block run?
679 if (fCurrent
>= 0 && pos
>= fRunFileOffset
&& pos
< fRunBlockEnd
)
682 // find matching block run
684 if (fInode
->data
.max_direct_range
> 0
685 && pos
>= fInode
->data
.max_direct_range
) {
686 if (fInode
->data
.max_double_indirect_range
> 0
687 && pos
>= fInode
->data
.max_indirect_range
) {
688 // read from double indirect blocks
690 //printf("find double indirect block: %ld,%d!\n",fInode->data.double_indirect.allocation_group,fInode->data.double_indirect.start);
691 block_run
*indirect
= (block_run
*)fDisk
->ReadBlockRun(fInode
->data
.double_indirect
);
692 if (indirect
== NULL
)
695 off_t start
= pos
- fInode
->data
.max_indirect_range
;
696 int32 indirectSize
= fDisk
->BlockSize() * 16 * (fDisk
->BlockSize() / sizeof(block_run
));
697 int32 directSize
= fDisk
->BlockSize() * 4;
698 int32 index
= start
/ indirectSize
;
700 //printf("\tstart = %Ld, indirectSize = %ld, directSize = %ld, index = %ld\n",start,indirectSize,directSize,index);
701 //printf("\tlook for indirect block at %ld,%d\n",indirect[index].allocation_group,indirect[index].start);
702 indirect
= (block_run
*)fDisk
->ReadBlockRun(indirect
[index
]);
703 if (indirect
== NULL
)
706 fCurrent
= (start
% indirectSize
) / directSize
;
707 fRunFileOffset
= fInode
->data
.max_indirect_range
+ (index
* indirectSize
) + (fCurrent
* directSize
);
708 fRunBlockEnd
= fRunFileOffset
+ directSize
;
709 fRun
= indirect
[fCurrent
];
710 //printf("\tfCurrent = %ld, fRunFileOffset = %Ld, fRunBlockEnd = %Ld, fRun = %ld,%d\n",fCurrent,fRunFileOffset,fRunBlockEnd,fRun.allocation_group,fRun.start);
712 // access from indirect blocks
714 block_run
*indirect
= (block_run
*)fDisk
->ReadBlockRun(fInode
->data
.indirect
);
718 int32 indirectRuns
= (fInode
->data
.indirect
.length
<< fDisk
->BlockShift()) / sizeof(block_run
);
720 if (fLevel
!= 1 || pos
< fRunFileOffset
) {
721 fRunBlockEnd
= fInode
->data
.max_direct_range
;
726 while (++fCurrent
< indirectRuns
) {
727 if (indirect
[fCurrent
].IsZero())
730 fRunFileOffset
= fRunBlockEnd
;
731 fRunBlockEnd
+= indirect
[fCurrent
].length
<< fDisk
->BlockShift();
732 if (fRunBlockEnd
> pos
)
735 if (fCurrent
== indirectRuns
|| indirect
[fCurrent
].IsZero())
738 fRun
= indirect
[fCurrent
];
739 //printf("reading from indirect block: %ld,%d\n",fRun.allocation_group,fRun.start);
740 //printf("### indirect-run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
743 // access from direct blocks
744 if (fRunFileOffset
> pos
) {
750 while (++fCurrent
< NUM_DIRECT_BLOCKS
) {
751 if (fInode
->data
.direct
[fCurrent
].IsZero())
754 fRunFileOffset
= fRunBlockEnd
;
755 fRunBlockEnd
+= fInode
->data
.direct
[fCurrent
].length
<< fDisk
->BlockShift();
756 if (fRunBlockEnd
> pos
)
759 if (fCurrent
== NUM_DIRECT_BLOCKS
|| fInode
->data
.direct
[fCurrent
].IsZero())
762 fRun
= fInode
->data
.direct
[fCurrent
];
763 //printf("### run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
770 DataStream::ReadAt(off_t pos
, void *buffer
, size_t size
)
774 //printf("DataStream::ReadAt(pos = %Ld,buffer = %p,size = %ld);\n",pos,buffer,size);
775 // truncate size to read
776 if (pos
+ (off_t
)size
> fInode
->data
.size
) {
777 if (pos
> fInode
->data
.size
) // reading outside the file
780 size
= fInode
->data
.size
- pos
;
781 if (!size
) // there is nothing left to read
786 //printf("### read %ld bytes at %Ld\n",size,pos);
788 status_t status
= FindBlockRun(pos
);
792 ssize_t bytes
= min_c((off_t
)size
, fRunBlockEnd
- pos
);
794 //printf("### read %ld bytes from %Ld\n### --\n",bytes,fDisk->ToOffset(fRun) + pos - fRunFileOffset);
795 bytes
= fDisk
->ReadAt(fDisk
->ToOffset(fRun
) + pos
- fRunFileOffset
,
799 printf("could not read bytes at: %" B_PRId32
",%d\n",
800 fRun
.allocation_group
, fRun
.start
);
802 return bytes
< 0 ? bytes
: B_BAD_DATA
;
805 buffer
= (void *)((uint8
*)buffer
+ bytes
);
818 DataStream::WriteAt(off_t pos
, const void *buffer
, size_t size
)
822 // FIXME: truncate size -> should enlargen the file
823 if (pos
+ (off_t
)size
> fInode
->data
.size
) {
824 if (pos
> fInode
->data
.size
) // writing outside the file
827 size
= fInode
->data
.size
- pos
;
828 if (!size
) // there is nothing left to write
833 //printf("### write %ld bytes at %Ld\n",size,pos);
835 status_t status
= FindBlockRun(pos
);
839 ssize_t bytes
= min_c((off_t
)size
, fRunBlockEnd
- pos
);
841 //printf("### write %ld bytes to %Ld\n### --\n",bytes,fDisk->ToOffset(fRun) + pos - fRunFileOffset);
842 bytes
= fDisk
->WriteAt(fDisk
->ToOffset(fRun
) + pos
- fRunFileOffset
,buffer
,bytes
);
846 buffer
= (void *)((uint8
*)buffer
+ bytes
);
859 DataStream::Seek(off_t position
, uint32 seekMode
)
863 if (seekMode
== SEEK_SET
)
864 fPosition
= position
;
865 else if (seekMode
== SEEK_END
)
866 fPosition
= fInode
->data
.size
+ position
;
868 fPosition
+= position
;
875 DataStream::Position() const
882 DataStream::SetSize(off_t size
)
886 // FIXME: not yet supported
887 if (size
> fInode
->data
.size
|| size
> fInode
->data
.max_direct_range
)
890 if (size
== fInode
->data
.size
)
895 fInode
->data
.size
= size
;
896 fInode
->data
.max_direct_range
= size
;
897 fInode
->data
.max_indirect_range
= 0;
898 fInode
->data
.max_double_indirect_range
= 0;
900 for (int32 i
= 0;i
< NUM_DIRECT_BLOCKS
;i
++) {
902 fInode
->data
.direct
[i
].SetTo(0, 0, 0);
903 else if ((fInode
->data
.direct
[i
].length
<< fDisk
->BlockShift()) >= size
) {
904 off_t blocks
= (size
+ fDisk
->BlockSize() - 1) / fDisk
->BlockSize();
905 fInode
->data
.direct
[i
].length
= blocks
;
908 size
-= fInode
->data
.direct
[i
].length
<< fDisk
->BlockShift();
918 File::File(Disk
*disk
, bfs_inode
*inode
,bool ownBuffer
)
919 : DataStream(disk
,inode
,ownBuffer
)
924 File::File(const Inode
&inode
)
936 File::InitCheck() const
938 status_t status
= DataStream::InitCheck();
940 return IsFile() ? B_OK
: B_ERROR
;
947 File::CopyTo(const char *root
, bool fullPath
, Inode::Source
*source
)
949 status_t status
= Inode::CopyTo(root
, fullPath
, source
);
954 if (fullPath
&& Path(source
))
955 path
.Append(Path(source
));
957 char *name
= (char *)Name();
959 // changes the filename in the inode buffer (for deleted entries)
965 sub
<< "__untitled " << BlockRun().allocation_group
<< ":"
966 << (int32
)BlockRun().start
;
967 path
.Append(sub
.String());
969 printf("%" B_PRId32
",%d -> %s\n", BlockRun().allocation_group
,
970 BlockRun().start
, path
.Path());
973 status
= file
.SetTo(path
.Path(),
974 B_WRITE_ONLY
| B_CREATE_FILE
| B_FAIL_IF_EXISTS
);
978 char buffer
[fDisk
->BlockSize()];
982 while ((size
= Read(buffer
, sizeof(buffer
))) > B_OK
) {
983 ssize_t written
= file
.Write(buffer
, size
);
988 return CopyAttributesTo(&file
);
995 Attribute::Attribute(Disk
*disk
, bfs_inode
*inode
, bool ownBuffer
)
996 : File(disk
, inode
, ownBuffer
)
1001 Attribute::Attribute(const Inode
&inode
)
1007 Attribute::~Attribute()
1013 Attribute::InitCheck() const
1015 status_t status
= DataStream::InitCheck();
1017 return IsAttribute() ? B_OK
: B_ERROR
;
1024 Attribute::CopyTo(const char */
*path*/
, bool /*fullPath*/,
1025 Inode::Source */
*source*/
)
1027 // files and directories already copy all attributes
1029 // eventually, this method should be implemented to recover lost
1030 // attributes on the disk
1039 Directory::Directory(Disk
*disk
, bfs_inode
*inode
, bool ownBuffer
)
1040 : DataStream(disk
, inode
, ownBuffer
),
1046 Directory::Directory(const Inode
&inode
)
1047 : DataStream(inode
),
1053 Directory::~Directory()
1060 Directory::InitCheck() const
1062 status_t status
= DataStream::InitCheck();
1064 return (IsDirectory() || IsAttributeDirectory()) ? B_OK
: B_ERROR
;
1071 Directory::CopyTo(const char *root
, bool fullPath
, Inode::Source
*source
)
1073 // don't copy attributes or indices
1074 // the recovery program should make empty files to recover lost attributes
1075 if (IsAttributeDirectory() || IsIndex())
1078 status_t status
= Inode::CopyTo(root
, fullPath
, source
);
1083 if (fullPath
&& Path(source
))
1084 path
.Append(Path(source
));
1086 char *name
= (char *)Name();
1088 // changes the filename in the inode buffer (for deleted entries)
1093 // create unique name
1095 sub
<< "__untitled " << BlockRun().allocation_group
<< ":"
1096 << (int32
)BlockRun().start
;
1097 path
.Append(sub
.String());
1100 BEntry
entry(path
.Path());
1101 BDirectory directory
;
1102 if ((status
= entry
.GetParent(&directory
)) < B_OK
)
1105 status
= directory
.CreateDirectory(path
.Leaf(), NULL
);
1106 if (status
< B_OK
&& status
!= B_FILE_EXISTS
)
1109 if ((status
= directory
.SetTo(&entry
)) < B_OK
)
1112 return CopyAttributesTo(&directory
);
1120 status_t status
= CreateTree();
1124 return fTree
->Rewind();
1129 Directory::GetNextEntry(char *name
, block_run
*run
)
1134 if ((status
= Rewind()) < B_OK
)
1140 if ((status
= fTree
->GetNextEntry(name
, &length
, B_FILE_NAME_LENGTH
- 1,
1144 *run
= fDisk
->ToBlockRun(offset
);
1151 Directory::GetNextEntry(block_run
*run
)
1153 char name
[B_FILE_NAME_LENGTH
];
1155 return GetNextEntry(name
, run
);
1160 Directory::Contains(const block_run
*run
)
1165 if ((status
= Rewind()) < B_OK
)
1169 block_run searchRun
;
1170 while (GetNextEntry(&searchRun
) == B_OK
) {
1171 if (searchRun
== *run
)
1175 return B_ENTRY_NOT_FOUND
;
1180 Directory::Contains(const Inode
*inode
)
1185 if ((status
= CreateTree()) < B_OK
)
1190 const char *name
= inode
->Name();
1191 status
= B_ENTRY_NOT_FOUND
;
1193 if (name
&& (status
= fTree
->Find((uint8
*)name
, (uint16
)strlen(name
),
1195 if (fDisk
->ToBlockRun(value
) == inode
->InodeBuffer()->inode_num
)
1198 printf("inode address do not match (%s)!\n", inode
->Name());
1201 if (status
!= B_OK
&& status
!= B_ENTRY_NOT_FOUND
)
1204 return Contains(&inode
->InodeBuffer()->inode_num
);
1209 Directory::FindEntry(const char *name
, block_run
*run
)
1217 if ((status
= CreateTree()) < B_OK
)
1223 if ((status
= fTree
->Find((uint8
*)name
, (uint16
)strlen(name
),
1226 *run
= fDisk
->ToBlockRun(value
);
1234 Directory::AddEntry(Inode
*inode
)
1237 bool created
= false;
1240 status
= CreateTree();
1242 status
= fTree
->Validate();
1244 if (status
== B_BAD_DATA
) {
1245 //puts("bplustree corrupted!");
1246 fTree
= new BPlusTree(BPLUSTREE_STRING_TYPE
, BPLUSTREE_NODE_SIZE
,
1248 if ((status
= fTree
->InitCheck()) < B_OK
) {
1258 // keep all changes in memory
1259 fTree
->SetHoldChanges(true);
1263 fTree
->Insert(".", Block());
1264 fTree
->Insert("..", fDisk
->ToBlock(Parent()));
1267 if (inode
->Flags() & INODE_DELETED
)
1268 return B_ENTRY_NOT_FOUND
;
1270 BString name
= inode
->Name();
1272 name
<< "__file " << inode
->BlockRun().allocation_group
<< ":"
1273 << (int32
)inode
->BlockRun().start
;
1276 return fTree
->Insert(name
.String(), inode
->Block());
1281 Directory::CreateTree()
1283 fTree
= new BPlusTree(this);
1285 status_t status
= fTree
->InitCheck();
1286 if (status
< B_OK
) {
1296 Directory::GetTree(BPlusTree
**tree
)
1299 status_t status
= CreateTree();
1311 Symlink::Symlink(Disk
*disk
, bfs_inode
*inode
,bool ownBuffer
)
1312 : Inode(disk
,inode
,ownBuffer
)
1317 Symlink::Symlink(const Inode
&inode
)
1329 Symlink::InitCheck() const
1331 status_t status
= Inode::InitCheck();
1333 return IsSymlink() ? B_OK
: B_ERROR
;
1340 Symlink::CopyTo(const char *root
, bool fullPath
,Inode::Source
*source
)
1342 status_t status
= Inode::CopyTo(root
,fullPath
,source
);
1347 if (fullPath
&& Path(source
))
1348 path
.Append(Path(source
));
1350 char *name
= (char *)Name();
1352 // changes the filename in the inode buffer (for deleted entries)
1357 // create unique name
1359 sub
<< "__symlink " << BlockRun().allocation_group
<< ":"
1360 << (int32
)BlockRun().start
;
1361 path
.Append(sub
.String());
1364 BEntry
entry(path
.Path());
1365 BDirectory directory
;
1366 if ((status
= entry
.GetParent(&directory
)) < B_OK
)
1370 if (LinksTo(to
,sizeof(to
)) < B_OK
)
1374 status
= directory
.CreateSymLink(path
.Leaf(),to
,&link
);
1375 if (status
< B_OK
&& status
!= B_FILE_EXISTS
)
1378 if ((status
= link
.SetTo(&entry
)) < B_OK
)
1381 return CopyAttributesTo(&link
);
1386 Symlink::LinksTo(char *to
,size_t maxLength
)
1388 if ((fInode
->flags
& INODE_LONG_SYMLINK
) == 0) {
1389 strcpy(to
,fInode
->short_symlink
);
1393 DataStream
stream(*this);
1394 status_t status
= stream
.InitCheck();
1398 status
= stream
.Read(to
,maxLength
);
1400 return status
< B_OK
? status
: B_OK
;