Implemented file reading

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4157 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Tyler Dauwalder
2003-07-31 06:59:21 +00:00
parent 928e05006d
commit 3dc4d42634
2 changed files with 346 additions and 16 deletions
+91 -10
View File
@@ -1,5 +1,6 @@
#include "Icb.h" #include "Icb.h"
#include "AllocationDescriptorList.h"
#include "DirectoryIterator.h" #include "DirectoryIterator.h"
#include "Utils.h" #include "Utils.h"
#include "Volume.h" #include "Volume.h"
@@ -7,22 +8,24 @@
using namespace Udf; using namespace Udf;
Icb::Icb(Volume *volume, udf_long_address address) Icb::Icb(Volume *volume, udf_long_address address)
: fVolume(NULL) : fVolume(volume)
, fIcbData(volume ? volume->BlockSize() : 0) , fData(volume)
, fInitStatus(B_NO_INIT) , fInitStatus(B_NO_INIT)
, fId(to_vnode_id(address)) , fId(to_vnode_id(address))
, fFileEntry(&fData)
, fExtendedEntry(&fData)
{ {
DEBUG_INIT_ETC(CF_PUBLIC, "Icb", ("Volume*(%p), long_address(block: %ld, partition: %d, length: %ld)", volume, address.block(), address.partition(), address.length())); DEBUG_INIT_ETC(CF_PUBLIC, "Icb", ("volume: %p, address(block: %ld, "
"partition: %d, length: %ld)", volume, address.block(),
address.partition(), address.length()));
status_t err = volume ? B_OK : B_BAD_VALUE; status_t err = volume ? B_OK : B_BAD_VALUE;
if (!err) { if (!err) {
err = fIcbData.InitCheck(); off_t block;
err = fVolume->MapBlock(address, &block);
if (!err) { if (!err) {
err = volume->Read(address, fIcbData.Size(), fIcbData.Data()); udf_icb_header *header = reinterpret_cast<udf_icb_header*>(fData.SetTo(block));
if (!err) { PDUMP(header);
udf_icb_header *header = reinterpret_cast<udf_icb_header*>(fIcbData.Data()); err = header->tag().init_check(address.block());
PDUMP(header);
err = header->tag().init_check(address.block());
}
} }
} }
fInitStatus = err; fInitStatus = err;
@@ -34,6 +37,51 @@ Icb::InitCheck()
return fInitStatus; return fInitStatus;
} }
status_t
Icb::Read(off_t pos, void *buffer, size_t *length, uint32 *block)
{
DEBUG_INIT_ETC(CF_PUBLIC | CF_HIGH_VOLUME, "Icb",
("pos: %lld, buffer: %p, length: (%p)->%ld", pos, buffer, length, (length ? *length : 0)));
if (!buffer || !length || uint64(pos) >= Length())
RETURN(B_BAD_VALUE);
switch (IcbTag().descriptor_flags()) {
case ICB_DESCRIPTOR_TYPE_SHORT: {
PRINT(("descriptor type: short\n"));
AllocationDescriptorList<ShortDescriptorAccessor> list(this, ShortDescriptorAccessor(0));
RETURN(_Read(list, pos, buffer, length, block));
break;
}
case ICB_DESCRIPTOR_TYPE_LONG: {
PRINT(("descriptor type: long\n"));
AllocationDescriptorList<LongDescriptorAccessor> list(this);
RETURN(_Read(list, pos, buffer, length, block));
break;
}
case ICB_DESCRIPTOR_TYPE_EXTENDED: {
PRINT(("descriptor type: extended\n"));
// AllocationDescriptorList<ExtendedDescriptorAccessor> list(this, ExtendedDescriptorAccessor(0));
// RETURN(_Read(list, pos, buffer, length, block));
RETURN(B_ERROR);
break;
}
case ICB_DESCRIPTOR_TYPE_EMBEDDED: {
PRINT(("descriptor type: embedded\n"));
RETURN(B_ERROR);
break;
}
default:
PRINT(("Invalid icb descriptor flags! (flags = %d)\n", IcbTag().descriptor_flags()));
RETURN(B_BAD_VALUE);
break;
}
}
status_t status_t
Icb::GetDirectoryIterator(DirectoryIterator **iterator) Icb::GetDirectoryIterator(DirectoryIterator **iterator)
{ {
@@ -51,4 +99,37 @@ Icb::GetDirectoryIterator(DirectoryIterator **iterator)
return err; return err;
} }
status_t
Icb::Find(const char *filename, vnode_id *id)
{
DEBUG_INIT_ETC(CF_PUBLIC | CF_DIRECTORY_OPS | CF_HIGH_VOLUME, "Icb",
("filename: `%s', id: %p", filename, id));
if (!filename || !id)
RETURN(B_BAD_VALUE);
DirectoryIterator *i;
status_t err = GetDirectoryIterator(&i);
if (!err) {
vnode_id entryId;
uint32 length = B_FILE_NAME_LENGTH;
char name[B_FILE_NAME_LENGTH];
bool foundIt = false;
while (i->GetNextEntry(name, &length, &entryId) == B_OK)
{
if (strcmp(filename, name) == 0) {
foundIt = true;
break;
}
}
if (foundIt) {
*id = entryId;
} else {
err = B_ENTRY_NOT_FOUND;
}
}
RETURN(err);
}
+253 -4
View File
@@ -21,8 +21,8 @@ extern "C" {
#include "cpp.h" #include "cpp.h"
#include "UdfDebug.h" #include "UdfDebug.h"
#include "CachedBlock.h"
#include "DiskStructures.h" #include "DiskStructures.h"
#include "MemoryChunk.h"
#include "SinglyLinkedList.h" #include "SinglyLinkedList.h"
namespace Udf { namespace Udf {
@@ -30,6 +30,36 @@ namespace Udf {
class DirectoryIterator; class DirectoryIterator;
class Volume; class Volume;
/*! \brief Abstract interface to file entry structure members
that are not commonly accessible through udf_file_icb_entry().
This is necessary, since we can't use virtual functions in
the disk structure structs themselves, since we generally
don't create disk structure objects by calling new, but
rather just cast a chunk of memory read off disk to be
a pointer to the struct of interest (which works fine
for regular functions, but fails miserably for virtuals
due to the vtable not being setup properly).
*/
class AbstractFileEntry {
public:
virtual uint8* AllocationDescriptors() = 0;
virtual uint32 AllocationDescriptorsLength() = 0;
};
template <class Descriptor>
class FileEntry : public AbstractFileEntry {
public:
FileEntry(CachedBlock *descriptorBlock = NULL);
void SetTo(CachedBlock *descriptorBlock);
virtual uint8* AllocationDescriptors();
virtual uint32 AllocationDescriptorsLength();
private:
Descriptor* _Descriptor();
CachedBlock *fDescriptorBlock;
};
class Icb { class Icb {
public: public:
Icb(Volume *volume, udf_long_address address); Icb(Volume *volume, udf_long_address address);
@@ -42,24 +72,243 @@ public:
bool IsDirectory() { return InitCheck() == B_OK bool IsDirectory() { return InitCheck() == B_OK
&& (Type() == ICB_TYPE_DIRECTORY || Type() == ICB_TYPE_STREAM_DIRECTORY); } && (Type() == ICB_TYPE_DIRECTORY || Type() == ICB_TYPE_STREAM_DIRECTORY); }
// directories uint32 Uid() { return 0; }//FileEntry()->uid(); }
uint32 Gid() { return 0; }
uint16 FileLinkCount() { return FileEntry()->file_link_count(); }
uint64 Length() { return FileEntry()->information_length(); }
mode_t Mode() { return (IsDirectory() ? S_IFDIR : S_IFREG) | S_IRUSR | S_IRGRP | S_IROTH; }
uint8 *AllocationDescriptors() { return AbstractEntry()->AllocationDescriptors(); }
uint32 AllocationDescriptorsSize() { return AbstractEntry()->AllocationDescriptorsLength(); }
status_t Read(off_t pos, void *buffer, size_t *length, uint32 *block = NULL);
// for directories only
status_t GetDirectoryIterator(DirectoryIterator **iterator); status_t GetDirectoryIterator(DirectoryIterator **iterator);
status_t Find(const char *filename, vnode_id *id);
Volume* GetVolume() const { return fVolume; }
private: private:
Icb(); // unimplemented Icb(); // unimplemented
udf_icb_entry_tag& IcbTag() { return (reinterpret_cast<udf_icb_header*>(fIcbData.Data()))->icb_tag(); } udf_tag& Tag() { return (reinterpret_cast<udf_icb_header*>(fData.Block()))->tag(); }
udf_icb_entry_tag& IcbTag() { return (reinterpret_cast<udf_icb_header*>(fData.Block()))->icb_tag(); }
AbstractFileEntry* AbstractEntry() {
DEBUG_INIT(CF_PRIVATE | CF_HIGH_VOLUME, "Icb");
return (Tag().id() == TAGID_EXTENDED_FILE_ENTRY)
// ? reinterpret_cast<udf_extended_file_icb_entry*>(fData.Block())
// : reinterpret_cast<udf_file_icb_entry*>(fData.Block()));
? &fExtendedEntry
: &fFileEntry;
}
udf_file_icb_entry* FileEntry() { return (reinterpret_cast<udf_file_icb_entry*>(fData.Block())); }
udf_extended_file_icb_entry& ExtendedEntry() { return *(reinterpret_cast<udf_extended_file_icb_entry*>(fData.Block())); }
template <class DescriptorList>
status_t _Read(DescriptorList &list, off_t pos, void *buffer, size_t *length, uint32 *block);
private: private:
Volume *fVolume; Volume *fVolume;
MemoryChunk fIcbData; CachedBlock fData;
status_t fInitStatus; status_t fInitStatus;
vnode_id fId; vnode_id fId;
SinglyLinkedList<Strategy::SinglyLinkedList::Auto<DirectoryIterator*> > fIteratorList; SinglyLinkedList<Strategy::SinglyLinkedList::Auto<DirectoryIterator*> > fIteratorList;
FileEntry<udf_file_icb_entry> fFileEntry;
FileEntry<udf_extended_file_icb_entry> fExtendedEntry;
}; };
/*! \brief Does the dirty work of reading using the given DescriptorList object
to access the allocation descriptors properly.
*/
template <class DescriptorList>
status_t
Icb::_Read(DescriptorList &list, off_t pos, void *_buffer, size_t *length, uint32 *block)
{
DEBUG_INIT_ETC(CF_PRIVATE | CF_HIGH_VOLUME, "Icb", ("list: %p, pos: %lld, buffer: %p, length: (%p)->%ld",
&list, pos, _buffer, length, (length ? *length : 0)));
if (!_buffer || !length)
RETURN(B_BAD_VALUE);
uint64 bytesLeftInFile = uint64(pos) > Length() ? 0 : Length() - pos;
size_t bytesLeft = (*length >= bytesLeftInFile) ? bytesLeftInFile : *length;
size_t bytesRead = 0;
Volume *volume = GetVolume();
status_t err = B_OK;
uint8 *buffer = reinterpret_cast<uint8*>(_buffer);
bool isFirstBlock = true;
while (bytesLeft > 0 && !err) {
PRINT(("pos: %lld\n", pos));
PRINT(("bytesLeft: %ld\n", bytesLeft));
udf_long_address extent;
bool isEmpty = false;
err = list.FindExtent(pos, &extent, &isEmpty);
if (!err) {
PRINT(("found extent for offset %lld: (block: %ld, partition: %d, length: %ld, type: %d)\n",
pos, extent.block(), extent.partition(), extent.length(), extent.type()));
switch (extent.type()) {
case EXTENT_TYPE_RECORDED:
isEmpty = false;
break;
case EXTENT_TYPE_ALLOCATED:
case EXTENT_TYPE_UNALLOCATED:
isEmpty = true;
break;
default:
PRINT(("Invalid extent type found: %d\n", extent.type()));
err = B_ERROR;
break;
}
if (!err) {
// Note the unmapped first block of the total read in
// the block output parameter if provided
if (isFirstBlock) {
isFirstBlock = false;
if (block)
*block = extent.block();
}
off_t blockOffset = pos - off_t((pos >> volume->BlockShift()) << volume->BlockShift());
size_t fullBlocksLeft = bytesLeft >> volume->BlockShift();
if (fullBlocksLeft > 0 && blockOffset == 0) {
PRINT(("reading full block (or more)\n"));
// Block aligned and at least one full block left. Read in using
// cached_read() calls.
off_t diskBlock;
err = volume->MapBlock(extent, &diskBlock);
if (!err) {
size_t fullBlockBytesLeft = fullBlocksLeft << volume->BlockShift();
size_t readLength = fullBlockBytesLeft < extent.length()
? fullBlockBytesLeft
: extent.length();
if (isEmpty) {
PRINT(("reading %ld empty bytes as zeros\n", readLength));
memset(buffer, 0, readLength);
} else {
off_t diskBlock;
err = volume->MapBlock(extent, &diskBlock);
if (!err) {
PRINT(("reading %ld bytes from disk block %lld using cached_read()\n",
readLength, diskBlock));
err = cached_read(volume->Device(), diskBlock, buffer,
readLength >> volume->BlockShift(),
volume->BlockSize());
}
}
if (!err) {
bytesLeft -= readLength;
bytesRead += readLength;
pos += readLength;
buffer += readLength;
}
}
} else {
PRINT(("partial block\n"));
off_t partialOffset;
size_t partialLength;
if (blockOffset == 0) {
// Block aligned, but only a partial block's worth remaining. Read
// in remaining bytes of file
partialOffset = 0;
partialLength = bytesLeft;
} else {
// Not block aligned, so just read up to the next block boundary.
partialOffset = blockOffset;
partialLength = volume->BlockSize() - blockOffset;
if (bytesLeft < partialLength)
partialLength = bytesLeft;
}
PRINT(("partialOffset: %lld\n", partialOffset));
PRINT(("partialLength: %ld\n", partialLength));
if (isEmpty) {
PRINT(("reading %ld empty bytes as zeros\n", partialLength));
memset(buffer, 0, partialLength);
} else {
off_t diskBlock;
err = volume->MapBlock(extent, &diskBlock);
if (!err) {
PRINT(("reading %ld bytes from disk block %lld using get_block()\n",
partialLength, diskBlock));
uint8 *data = (uint8*)get_block(volume->Device(), diskBlock, volume->BlockSize());
err = data ? B_OK : B_BAD_DATA;
if (!err) {
memcpy(buffer, data+partialOffset, partialLength);
release_block(volume->Device(), diskBlock);
}
}
}
if (!err) {
bytesLeft -= partialLength;
bytesRead += partialLength;
pos += partialLength;
buffer += partialLength;
}
}
}
} else {
PRINT(("error finding extent for offset %lld: 0x%lx, `%s'", pos,
err, strerror(err)));
break;
}
}
*length = bytesRead;
RETURN(err);
}
template <class Descriptor>
FileEntry<Descriptor>::FileEntry(CachedBlock *descriptorBlock)
: fDescriptorBlock(descriptorBlock)
{
}
template <class Descriptor>
void
FileEntry<Descriptor>::SetTo(CachedBlock *descriptorBlock)
{
fDescriptorBlock = descriptorBlock;
}
template <class Descriptor>
uint8*
FileEntry<Descriptor>::AllocationDescriptors()
{
Descriptor* descriptor = _Descriptor();
return descriptor ? descriptor->allocation_descriptors() : NULL;
}
template <class Descriptor>
uint32
FileEntry<Descriptor>::AllocationDescriptorsLength()
{
Descriptor* descriptor = _Descriptor();
return descriptor ? descriptor->allocation_descriptors_length() : 0;
}
template <class Descriptor>
Descriptor*
FileEntry<Descriptor>::_Descriptor()
{
return fDescriptorBlock ? reinterpret_cast<Descriptor*>(fDescriptorBlock->Block()) : NULL;
}
}; // namespace Udf }; // namespace Udf
#endif // _UDF_ICB_H #endif // _UDF_ICB_H