Author: mmlr Date: 2010-02-28 08:50:28 +0100 (Sun, 28 Feb 2010) New Revision: 35652 Changeset: http://dev.haiku-os.org/changeset/35652/haiku Modified: haiku/trunk/src/add-ons/kernel/file_systems/udf/AllocationDescriptorList.h haiku/trunk/src/add-ons/kernel/file_systems/udf/Icb.cpp haiku/trunk/src/add-ons/kernel/file_systems/udf/Icb.h haiku/trunk/src/add-ons/kernel/file_systems/udf/UdfDebug.h haiku/trunk/src/add-ons/kernel/file_systems/udf/kernel_interface.cpp Log: * Implement udf_io and udf_get_file_map. * Add file map and cache and do reads through the file_cache for file ICBs. * Move the private _Read() backend from the header to the implementation file. * Read() is now only used for directory iteration. * Turned off the verbose debug output. * Minor cleanup. This fixes the abuse of the block_cache, should allow executables on UDF and won't panic on protected content. Modified: haiku/trunk/src/add-ons/kernel/file_systems/udf/AllocationDescriptorList.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/udf/AllocationDescriptorList.h 2010-02-28 05:35:31 UTC (rev 35651) +++ haiku/trunk/src/add-ons/kernel/file_systems/udf/AllocationDescriptorList.h 2010-02-28 07:50:28 UTC (rev 35652) @@ -39,7 +39,7 @@ Accessor accessor = Accessor()); status_t FindExtent(off_t start, long_address *extent, - bool *isEmpty); + bool *isEmpty); private: @@ -172,7 +172,7 @@ return B_ENTRY_NOT_FOUND; // Increment our indices and get the next descriptor - // from this extent. + // from this extent. fBlockIndex += fAccessor.GetLength(*descriptor); fDescriptorIndex++; fDescriptorNumber++; Modified: haiku/trunk/src/add-ons/kernel/file_systems/udf/Icb.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/udf/Icb.cpp 2010-02-28 05:35:31 UTC (rev 35651) +++ haiku/trunk/src/add-ons/kernel/file_systems/udf/Icb.cpp 2010-02-28 07:50:28 UTC (rev 35652) @@ -1,5 +1,5 @@ //---------------------------------------------------------------------- -// This software is part of the Haiku distribution and is covered +// This software is part of the Haiku distribution and is covered // by the MIT license. // // Copyright (c) 2003 Tyler Dauwalder, tyler@xxxxxxxxxxxxx @@ -12,10 +12,12 @@ #include "Utils.h" #include "Volume.h" +#include <file_cache.h> + status_t DirectoryIterator::GetNextEntry(char *name, uint32 *length, ino_t *id) -{ +{ if (!id || !name || !length) return B_BAD_VALUE; @@ -103,7 +105,9 @@ fInitStatus(B_NO_INIT), fId(to_vnode_id(address)), fFileEntry(&fData), - fExtendedEntry(&fData) + fExtendedEntry(&fData), + fFileCache(NULL), + fFileMap(NULL) { TRACE(("Icb::Icb: volume = %p, address(block = %ld, partition = %d, " "length = %ld)\n", volume, address.block(), address.partition(), @@ -130,11 +134,25 @@ status = header->tag().init_check(address.block()); } + if (IsFile()) { + fFileCache = file_cache_create(fVolume->ID(), fId, Length()); + fFileMap = file_map_create(fVolume->ID(), fId, Length()); + } + fInitStatus = status; TRACE(("Icb::Icb: status = 0x%lx, `%s'\n", status, strerror(status))); } +Icb::~Icb() +{ + if (fFileCache != NULL) { + file_cache_delete(fFileCache); + file_map_delete(fFileMap); + } +} + + status_t Icb::GetDirectoryIterator(DirectoryIterator **iterator) { @@ -187,6 +205,9 @@ return B_OK; } + if (fFileCache != NULL) + return file_cache_read(fFileCache, NULL, pos, buffer, length); + switch (_IcbTag().descriptor_flags()) { case ICB_DESCRIPTOR_TYPE_SHORT: { TRACE(("Icb::Read: descriptor type -> short\n")); @@ -194,7 +215,7 @@ RETURN(_Read(list, pos, buffer, length, block)); break; } - + case ICB_DESCRIPTOR_TYPE_LONG: { TRACE(("Icb::Read: descriptor type -> long\n")); AllocationDescriptorList<LongDescriptorAccessor> list(this); @@ -220,12 +241,205 @@ TRACE(("Icb::Read: invalid icb descriptor flags! (flags = %d)\n", _IcbTag().descriptor_flags())); RETURN(B_BAD_VALUE); - break; + break; } } +/*! \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) +{ + TRACE(("Icb::_Read(): list = %p, pos = %Ld, buffer = %p, length = %ld\n", + &list, pos, _buffer, (length ? *length : 0))); + + uint64 bytesLeftInFile = uint64(pos) > Length() ? 0 : Length() - pos; + size_t bytesLeft = (*length >= bytesLeftInFile) ? bytesLeftInFile : *length; + size_t bytesRead = 0; + + Volume *volume = GetVolume(); + status_t status = B_OK; + uint8 *buffer = (uint8 *)_buffer; + bool isFirstBlock = true; + + while (bytesLeft > 0) { + + TRACE(("Icb::_Read(): pos: %Ld, bytesLeft: %ld\n", pos, bytesLeft)); + long_address extent; + bool isEmpty = false; + status = list.FindExtent(pos, &extent, &isEmpty); + if (status != B_OK) { + TRACE_ERROR(("Icb::_Read: error finding extent for offset %Ld. " + "status = 0x%lx `%s'\n", pos, status, strerror(status))); + break; + } + + TRACE(("Icb::_Read(): found extent for offset %Ld: (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: + TRACE_ERROR(("Icb::_Read(): Invalid extent type found: %d\n", + extent.type())); + status = B_ERROR; + break; + } + + if (status != B_OK) + break; + + // 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 readLength = volume->BlockSize() - blockOffset; + if (bytesLeft < readLength) + readLength = bytesLeft; + if (extent.length() < readLength) + readLength = extent.length(); + + TRACE(("Icb::_Read: reading block. offset = %Ld, length: %ld\n", + blockOffset, readLength)); + + if (isEmpty) { + TRACE(("Icb::_Read: reading %ld empty bytes as zeros\n", + readLength)); + memset(buffer, 0, readLength); + } else { + off_t diskBlock; + status = volume->MapBlock(extent, &diskBlock); + if (status != B_OK) { + TRACE_ERROR(("Icb::_Read: could not map extent\n")); + break; + } + + TRACE(("Icb::_Read: %ld bytes from disk block %Ld using " + "block_cache_get_etc()\n", readLength, diskBlock)); + uint8 *data = (uint8*)block_cache_get_etc(volume->BlockCache(), + diskBlock, 0, readLength); + if (data == NULL) + break; + memcpy(buffer, data + blockOffset, readLength); + block_cache_put(volume->BlockCache(), diskBlock); + } + + bytesLeft -= readLength; + bytesRead += readLength; + pos += readLength; + buffer += readLength; + } + + *length = bytesRead; + + return status; +} + + +status_t +Icb::GetFileMap(off_t offset, size_t size, file_io_vec *vecs, size_t *count) +{ + switch (_IcbTag().descriptor_flags()) { + case ICB_DESCRIPTOR_TYPE_SHORT: + { + AllocationDescriptorList<ShortDescriptorAccessor> list(this, + ShortDescriptorAccessor(0)); + return _GetFileMap(list, offset, size, vecs, count); + } + + case ICB_DESCRIPTOR_TYPE_LONG: + { + AllocationDescriptorList<LongDescriptorAccessor> list(this); + return _GetFileMap(list, offset, size, vecs, count); + } + + case ICB_DESCRIPTOR_TYPE_EXTENDED: + case ICB_DESCRIPTOR_TYPE_EMBEDDED: + default: + { + // TODO: implement? + return B_UNSUPPORTED; + } + } +} + + +template<class DescriptorList> +status_t +Icb::_GetFileMap(DescriptorList &list, off_t offset, size_t size, + struct file_io_vec *vecs, size_t *count) +{ + size_t index = 0; + size_t max = *count; + + while (true) { + long_address extent; + bool isEmpty = false; + status_t status = list.FindExtent(offset, &extent, &isEmpty); + if (status != B_OK) + return status; + + switch (extent.type()) { + case EXTENT_TYPE_RECORDED: + isEmpty = false; + break; + + case EXTENT_TYPE_ALLOCATED: + case EXTENT_TYPE_UNALLOCATED: + isEmpty = true; + break; + + default: + return B_ERROR; + } + + if (isEmpty) + vecs[index].offset = -1; + else { + off_t diskBlock; + fVolume->MapBlock(extent, &diskBlock); + vecs[index].offset = diskBlock << fVolume->BlockShift(); + } + + off_t length = extent.length(); + vecs[index].length = length; + + offset += length; + size -= length; + index++; + + if (index >= max || size <= vecs[index - 1].length + || offset >= (off_t)Length()) { + *count = index; + return index >= max ? B_BUFFER_OVERFLOW : B_OK; + } + } + + // can never get here + return B_ERROR; +} + + +status_t Icb::Find(const char *filename, ino_t *id) { TRACE(("Icb::Find: filename = `%s', id = %p\n", filename, id)); Modified: haiku/trunk/src/add-ons/kernel/file_systems/udf/Icb.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/udf/Icb.h 2010-02-28 05:35:31 UTC (rev 35651) +++ haiku/trunk/src/add-ons/kernel/file_systems/udf/Icb.h 2010-02-28 07:50:28 UTC (rev 35652) @@ -79,6 +79,8 @@ class Icb { public: Icb(Volume *volume, long_address address); + ~Icb(); + status_t InitCheck(); ino_t Id() { return fId; } @@ -105,6 +107,12 @@ status_t Read(off_t pos, void *buffer, size_t *length, uint32 *block = NULL); + void * FileCache() { return fFileCache; } + void * FileMap() { return fFileMap; } + + status_t GetFileMap(off_t offset, size_t size, + struct file_io_vec *vecs, size_t *count); + // for directories only status_t GetDirectoryIterator(DirectoryIterator **iterator); status_t Find(const char *filename, ino_t *id); @@ -114,7 +122,7 @@ private: AbstractFileEntry *_AbstractEntry() { return (_Tag().id() == TAGID_EXTENDED_FILE_ENTRY) - ? (AbstractFileEntry *)&fExtendedEntry + ? (AbstractFileEntry *)&fExtendedEntry : (AbstractFileEntry *)&fFileEntry; } descriptor_tag &_Tag() { return ((icb_header *)fData.Block())->tag(); } @@ -122,130 +130,26 @@ file_icb_entry *_FileEntry() { return (file_icb_entry *)fData.Block(); } extended_file_icb_entry &_ExtendedEntry() { return *(extended_file_icb_entry *)fData.Block(); } - template <class DescriptorList> + template<class DescriptorList> + status_t _GetFileMap(DescriptorList &list, off_t offset, + size_t size, struct file_io_vec *vecs, + size_t *count); + template<class DescriptorList> status_t _Read(DescriptorList &list, off_t pos, void *buffer, size_t *length, uint32 *block); -private: Volume *fVolume; CachedBlock fData; status_t fInitStatus; ino_t fId; SinglyLinkedList<DirectoryIterator> fIteratorList; FileEntry<file_icb_entry> fFileEntry; - FileEntry<extended_file_icb_entry> fExtendedEntry; + FileEntry<extended_file_icb_entry> fExtendedEntry; + void * fFileCache; + void * fFileMap; }; -/*! \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) -{ - TRACE(("Icb::_Read(): list = %p, pos = %Ld, buffer = %p, length = %ld\n", - &list, pos, _buffer, (length ? *length : 0))); - - uint64 bytesLeftInFile = uint64(pos) > Length() ? 0 : Length() - pos; - size_t bytesLeft = (*length >= bytesLeftInFile) ? bytesLeftInFile : *length; - size_t bytesRead = 0; - - Volume *volume = GetVolume(); - status_t status = B_OK; - uint8 *buffer = (uint8 *)_buffer; - bool isFirstBlock = true; - - while (bytesLeft > 0) { - - TRACE(("Icb::_Read(): pos: %Ld, bytesLeft: %ld\n", pos, bytesLeft)); - long_address extent; - bool isEmpty = false; - status = list.FindExtent(pos, &extent, &isEmpty); - if (status != B_OK) { - TRACE_ERROR(("Icb::_Read: error finding extent for offset %Ld. " - "status = 0x%lx `%s'\n", pos, status, strerror(status))); - break; - } - - TRACE(("Icb::_Read(): found extent for offset %Ld: (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: - TRACE_ERROR(("Icb::_Read(): Invalid extent type found: %d\n", - extent.type())); - status = B_ERROR; - break; - } - - if (status != B_OK) - break; - - // 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 readLength = volume->BlockSize() - blockOffset; - if (bytesLeft < readLength) - readLength = bytesLeft; - if (extent.length() < readLength) - readLength = extent.length(); - - TRACE(("Icb::_Read: reading block. offset = %Ld, length: %ld\n", - blockOffset, readLength)); - - if (isEmpty) { - TRACE(("Icb::_Read: reading %ld empty bytes as zeros\n", - readLength)); - memset(buffer, 0, readLength); - } else { - off_t diskBlock; - status = volume->MapBlock(extent, &diskBlock); - if (status != B_OK) { - TRACE_ERROR(("Icb::_Read: could not map extent\n")); - break; - } - - TRACE(("Icb::_Read: %ld bytes from disk block %Ld using " - "block_cache_get_etc()\n", readLength, diskBlock)); - uint8 *data = (uint8*)block_cache_get_etc(volume->BlockCache(), - diskBlock, 0, readLength); - if (data == NULL) - break; - memcpy(buffer, data + blockOffset, readLength); - block_cache_put(volume->BlockCache(), diskBlock); - } - - bytesLeft -= readLength; - bytesRead += readLength; - pos += readLength; - buffer += readLength; - } - - *length = bytesRead; - - return status; -} - - template <class Descriptor> FileEntry<Descriptor>::FileEntry(CachedBlock *descriptorBlock) : fDescriptorBlock(descriptorBlock) Modified: haiku/trunk/src/add-ons/kernel/file_systems/udf/UdfDebug.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/udf/UdfDebug.h 2010-02-28 05:35:31 UTC (rev 35651) +++ haiku/trunk/src/add-ons/kernel/file_systems/udf/UdfDebug.h 2010-02-28 07:50:28 UTC (rev 35652) @@ -1,5 +1,5 @@ //---------------------------------------------------------------------- -// This software is part of the OpenBeOS distribution and is covered +// This software is part of the OpenBeOS distribution and is covered // by the OpenBeOS license. // // This version copyright (c) 2003 Tyler Dauwalder, tyler@xxxxxxxxxxxxx @@ -31,15 +31,15 @@ # include <stdarg.h> extern "C" int vsprintf(char *s, const char *format, va_list arg); # include <fcntl.h> -# define __out dbg_printf +# define __out dbg_printf void dbg_printf(const char *format,...); void initialize_debugger(const char *filename); #else -# if !_KERNEL_MODE -//# include <stdio.h> -# define __out printf -# else -//# include <null.h> +# if !_KERNEL_MODE +//# include <stdio.h> +# define __out printf +# else +//# include <null.h> # define __out dprintf # endif # include <stdio.h> @@ -64,10 +64,10 @@ public: DebugHelper(const char *className = NULL, uint8 tabCount = 1); ~DebugHelper(); - + uint8 TabCount() const { return fTabCount; } const char* ClassName() const { return fClassName; } - + private: uint8 fTabCount; char *fClassName; @@ -98,14 +98,14 @@ #else #define INITIALIZE_DEBUGGING_OUTPUT_FILE(filename) ; #endif - + #define DEBUG_INIT_SILENT(className) \ - DebugHelper _debugHelper(className, 2); + DebugHelper _debugHelper(className, 2); #define DEBUG_INIT(className) \ DEBUG_INIT_SILENT(className); \ PRINT(("\n")); - + #define DEBUG_INIT_ETC(className, arguments) \ DEBUG_INIT_SILENT(className) \ { \ @@ -119,10 +119,10 @@ __out arguments; \ __out("):\n"); \ } - + #define DUMP_INIT(className) \ - DEBUG_INIT_SILENT(className); - + DEBUG_INIT_SILENT(className); + #define PRINT(x) { \ { \ PRINT_INDENT(); \ @@ -164,21 +164,21 @@ } \ } \ } - + #define PRINT_DIVIDER() \ PRINT_INDENT(); \ SIMPLE_PRINT(("------------------------------------------------------------\n")); - + #define DUMP(object) \ { \ (object).dump(); \ - } - + } + #define PDUMP(objectPointer) \ { \ (objectPointer)->dump(); \ - } - + } + #define REPORT_ERROR(error) { \ LPRINT(("returning error 0x%lx, `%s'\n", error, strerror(error))); \ } @@ -205,9 +205,9 @@ #define FATAL(x) { \ PRINT(("fatal error: ")); SIMPLE_PRINT(x); \ } - + #define DBG(x) x ; - + #else // ifdef DEBUG #define INITIALIZE_DEBUGGING_OUTPUT_FILE(filename) ; #define DEBUG_INIT_SILENT(className) ; @@ -228,7 +228,7 @@ #define DBG(x) ; #endif // ifdef DEBUG else -#define TRACE(x) dprintf x +#define TRACE(x) /*dprintf x*/ #define TRACE_ERROR(x) dprintf x // These macros turn on or off extensive and generally unnecessary Modified: haiku/trunk/src/add-ons/kernel/file_systems/udf/kernel_interface.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/udf/kernel_interface.cpp 2010-02-28 05:35:31 UTC (rev 35651) +++ haiku/trunk/src/add-ons/kernel/file_systems/udf/kernel_interface.cpp 2010-02-28 07:50:28 UTC (rev 35652) @@ -16,6 +16,8 @@ #include <KernelExport.h> #include <util/kernel_cpp.h> +#include <io_requests.h> + #include "Icb.h" #include "Recognition.h" #include "Utils.h" @@ -37,6 +39,28 @@ extern fs_vnode_ops gUDFVnodeOps; +// #pragma mark - io callbacks + + +static status_t +iterative_io_get_vecs_hook(void *cookie, io_request *request, off_t offset, + size_t size, struct file_io_vec *vecs, size_t *count) +{ + Icb *icb = (Icb *)cookie; + return file_map_translate(icb->FileMap(), offset, size, vecs, count, + icb->GetVolume()->BlockSize()); +} + + +static status_t +iterative_io_finished_hook(void *cookie, io_request *request, status_t status, + bool partialTransfer, size_t bytesTransferred) +{ + // nothing to do + return B_OK; +} + + // #pragma mark - fs_volume_ops fuctions @@ -266,7 +290,7 @@ static status_t udf_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie) -{ +{ TRACE(("udf_free_cookie: _volume = %p, _node = %p\n", _volume, _node)); return B_OK; } @@ -274,7 +298,7 @@ static status_t udf_access(fs_volume* _volume, fs_vnode* _node, int accessMode) -{ +{ TRACE(("udf_access: _volume = %p, _node = %p\n", _volume, _node)); return B_OK; } @@ -299,6 +323,34 @@ static status_t +udf_io(fs_volume *volume, fs_vnode *vnode, void *cookie, io_request *request) +{ + if (io_request_is_write(request)) { + notify_io_request(request, B_READ_ONLY_DEVICE); + return B_READ_ONLY_DEVICE; + } + + Icb *icb = (Icb *)vnode->private_node; + if (icb->FileCache() == NULL) { + notify_io_request(request, B_BAD_VALUE); + return B_BAD_VALUE; + } + + return do_iterative_fd_io(((Volume *)volume->private_volume)->Device(), + request, iterative_io_get_vecs_hook, iterative_io_finished_hook, icb); +} + + +static status_t +udf_get_file_map(fs_volume *_volume, fs_vnode *vnode, off_t offset, size_t size, + struct file_io_vec *vecs, size_t *count) +{ + Icb *icb = (Icb *)vnode->private_node; + return icb->GetFileMap(offset, size, vecs, count); +} + + +static status_t udf_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) { TRACE(("udf_open_dir: volume = %p, vnode = %p\n", volume, vnode)); @@ -568,11 +620,11 @@ NULL, // write_pages /* asynchronous I/O */ - NULL, // io() + &udf_io, NULL, // cancel_io() /* cache file access */ - NULL, // &udf_get_file_map, + &udf_get_file_map, /* common operations */ NULL, // ioctl