//////////////////////////////////////////////////////////////////// // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine // All rights reserved // This file was released under the GPLv2 on June 2015. //////////////////////////////////////////////////////////////////// /* Module name: extent.cpp Abstract: This file contains filesystem-specific routines responsible for extent & mapping management */ #include "udf.h" #define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO_EXTENT /* This routine converts offset in extent to Lba & returns offset in the 1st sector & bytes before end of block. Here we assume no references to AllocDescs */ uint32 UDFExtentOffsetToLba( IN PVCB Vcb, IN PEXTENT_MAP Extent, // Extent array IN int64 Offset, // offset in extent OUT uint32* SectorOffset, OUT uint32* AvailLength, // available data in this block OUT uint32* Flags, OUT uint32* Index ) { uint32 j=0, l, d, BSh = Vcb->BlockSizeBits; uint32 Offs; uint32 i=0, BOffset; // block nums BOffset = (uint32)(Offset >> BSh); // scan extent table for suitable range (frag) ExtPrint(("ExtLen %x\n", Extent->extLength)); while(i+(d = (l = (Extent->extLength & UDF_EXTENT_LENGTH_MASK)) >> BSh) <= BOffset) { if(!l) { if(Index) (*Index) = j-1; if(Flags) { Extent--; (*Flags) = (Extent->extLength >> 30); } return LBA_OUT_OF_EXTENT; } if(!d) break; i += d; //frag offset j++; // frag index Extent++; } BOffset -= i; Offs = (*((uint32*)&Offset)) - (i << BSh); // offset in frag if(SectorOffset) (*SectorOffset) = Offs & (Vcb->BlockSize-1);// offset in 1st Lba if(AvailLength) (*AvailLength) = l - Offs;// bytes to EO frag if(Flags) (*Flags) = (Extent->extLength >> 30); if(Index) (*Index) = j; ASSERT(((Extent->extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) || Extent->extLocation); return Extent->extLocation + BOffset;// 1st Lba } // end UDFExtentOffsetToLba() uint32 UDFNextExtentToLba( IN PVCB Vcb, IN PEXTENT_MAP Extent, // Extent array OUT uint32* AvailLength, // available data in this block OUT uint32* Flags, OUT uint32* Index ) { // uint32 Lba; uint32 l; // uint32 d; // scan extent table for suitable range (frag) // d = (l = (Extent->extLength & UDF_EXTENT_LENGTH_MASK)); l = (Extent->extLength & UDF_EXTENT_LENGTH_MASK); if(!l) { (*Index) = -1; Extent--; (*Flags) = (Extent->extLength >> 30); return LBA_OUT_OF_EXTENT; } (*Index) = 0; (*AvailLength) = l;// bytes to EO frag (*Flags) = (Extent->extLength >> 30); ASSERT(((*Flags) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) || Extent->extLocation); return Extent->extLocation;// 1st Lba } // end UDFNextExtentToLba() /* This routine locates frag containing specified Lba in extent */ ULONG UDFLocateLbaInExtent( IN PVCB Vcb, IN PEXTENT_MAP Extent, // Extent array IN lba_t lba ) { uint32 l, BSh = Vcb->BlockSizeBits; uint32 i=0; while((l = ((Extent->extLength & UDF_EXTENT_LENGTH_MASK) >> BSh))) { if(Extent->extLocation >= lba && Extent->extLocation+l < lba) { return i; } i++; //frag offset Extent++; } return LBA_OUT_OF_EXTENT;// index of item in extent, containing out Lba } // end UDFLocateLbaInExtent() /* This routine calculates total length of specified extent. Here we assume no references to AllocDescs */ int64 UDFGetExtentLength( IN PEXTENT_MAP Extent // Extent array ) { if(!Extent) return 0; int64 i=0; #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) __asm push ebx __asm push ecx __asm push esi __asm lea ebx,i __asm mov esi,Extent __asm xor ecx,ecx While_1: __asm mov eax,[esi+ecx*8] // Extent[j].extLength __asm and eax,UDF_EXTENT_LENGTH_MASK __asm jz EO_While __asm add [ebx],eax __asm adc [ebx+4],0 __asm inc ecx __asm jmp While_1 EO_While:; __asm pop esi __asm pop ecx __asm pop ebx #else // NO X86 optimization , use generic C/C++ while(Extent->extLength) { i += (Extent->extLength & UDF_EXTENT_LENGTH_MASK); Extent++; } #endif // _X86_ return i; } // UDFGetExtentLength() /* This routine appends Zero-terminator to single Extent-entry. Such operation makes it compatible with other internal routines */ PEXTENT_MAP __fastcall UDFExtentToMapping_( IN PEXTENT_AD Extent #ifdef UDF_TRACK_EXTENT_TO_MAPPING ,IN ULONG src, IN ULONG line #endif //UDF_TRACK_EXTENT_TO_MAPPING ) { PEXTENT_MAP Map; #ifdef UDF_TRACK_EXTENT_TO_MAPPING #define UDF_EXT_MAP_MULT 4 #else //UDF_TRACK_EXTENT_TO_MAPPING #define UDF_EXT_MAP_MULT 2 #endif //UDF_TRACK_EXTENT_TO_MAPPING Map = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDF_EXT_MAP_MULT * sizeof(EXTENT_MAP), MEM_EXTMAP_TAG); if(!Map) return NULL; RtlZeroMemory((int8*)(Map+1), sizeof(EXTENT_MAP)); Map[0].extLength = Extent->extLength; Map[0].extLocation = Extent->extLocation; #ifdef UDF_TRACK_EXTENT_TO_MAPPING Map[2].extLength = src; Map[2].extLocation = line; #endif //UDF_TRACK_EXTENT_TO_MAPPING return Map; } // end UDFExtentToMapping() /* This routine calculates file mapping length (in bytes) including ZERO-terminator */ uint32 UDFGetMappingLength( IN PEXTENT_MAP Extent ) { if(!Extent) return 0; uint32 i=0; #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) __asm push ebx __asm mov ebx,Extent __asm xor eax,eax While_1: __asm mov ecx,[ebx+eax*8] __asm jecxz EO_While __asm inc eax __asm jmp While_1 EO_While: __asm inc eax __asm shl eax,3 __asm mov i,eax __asm pop ebx #else // NO X86 optimization , use generic C/C++ while(Extent->extLength) { i++; Extent++; } i++; i*=sizeof(EXTENT_MAP); #endif // _X86_ return i; // i*sizeof(EXTENT_MAP) } // end UDFGetMappingLength() /* This routine merges 2 sequencial file mappings */ PEXTENT_MAP __fastcall UDFMergeMappings( IN PEXTENT_MAP Extent, IN PEXTENT_MAP Extent2 ) { PEXTENT_MAP NewExt; uint32 len, len2; len = UDFGetMappingLength(Extent); len2 = UDFGetMappingLength(Extent2); ASSERT(len2 && len); if(!len2) { return Extent; } if(MyReallocPool__((int8*)Extent, len, (int8**)(&NewExt), len+len2-sizeof(EXTENT_MAP))) { RtlCopyMemory(((int8*)NewExt)+len-sizeof(EXTENT_MAP), (int8*)Extent2, len2); } else { ExtPrint(("UDFMergeMappings failed\n")); BrutePoint(); } return NewExt; } // end UDFMergeMappings() /* This routine builds file mapping according to ShortAllocDesc (SHORT_AD) array */ PEXTENT_MAP UDFShortAllocDescToMapping( IN PVCB Vcb, IN uint32 PartNum, IN PSHORT_AD AllocDesc, IN uint32 AllocDescLength, IN uint32 SubCallCount, OUT PEXTENT_INFO AllocLoc ) { uint32 i, lim, l, len, type; // uint32 BSh; PEXTENT_MAP Extent, Extent2, AllocMap; EXTENT_AD AllocExt; PALLOC_EXT_DESC NextAllocDesc; lb_addr locAddr; uint32 ReadBytes; EXTENT_INFO NextAllocLoc; BOOLEAN w2k_compat = FALSE; ExtPrint(("UDFShortAllocDescToMapping: len=%x\n", AllocDescLength)); if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL; locAddr.partitionReferenceNum = (uint16)PartNum; // BSh = Vcb->BlockSizeBits; l = ((lim = (AllocDescLength/sizeof(SHORT_AD))) + 1 ) * sizeof(EXTENT_AD); Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG); if(!Extent) return NULL; NextAllocLoc.Offset = 0; for(i=0;i> 30; len = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK; ExtPrint(("ShExt: type %x, loc %x, len %x\n", type, AllocDesc[i].extPosition, len)); if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) { // read next frag of allocation descriptors if encountered if(len < sizeof(ALLOC_EXT_DESC)) { MyFreePool__(Extent); return NULL; } NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG); if(!NextAllocDesc) { MyFreePool__(Extent); return NULL; } // record information about this frag locAddr.logicalBlockNum = AllocDesc[i].extPosition; AllocExt.extLength = len; AllocExt.extLocation = UDFPartLbaToPhys(Vcb, &locAddr); if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) { UDFPrint(("bad address\n")); MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } NextAllocLoc.Mapping = AllocMap = UDFExtentToMapping(&AllocExt); NextAllocLoc.Length = len; if(!AllocMap) { MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap); if(!AllocLoc->Mapping || // read this frag !OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc, 0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes))) { MyFreePool__(AllocMap); MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } MyFreePool__(AllocMap); // check integrity if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) || (NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) { UDFPrint(("Integrity check failed\n")); UDFPrint(("NextAllocDesc->descTag.tagIdent = %x\n", NextAllocDesc->descTag.tagIdent)); UDFPrint(("NextAllocDesc->lengthAllocDescs = %x\n", NextAllocDesc->lengthAllocDescs)); UDFPrint(("len = %x\n", len)); MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } // perform recursive call to obtain mapping NextAllocLoc.Flags = 0; Extent2 = UDFShortAllocDescToMapping(Vcb, PartNum, (PSHORT_AD)(NextAllocDesc+1), NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc); if(!Extent2) { MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } UDFCheckSpaceAllocation(Vcb, 0, Extent2, AS_USED); // check if used // and merge this 2 mappings into 1 Extent[i].extLength = 0; Extent[i].extLocation = 0; Extent = UDFMergeMappings(Extent, Extent2); if(NextAllocLoc.Flags & EXTENT_FLAG_2K_COMPAT) { ExtPrint(("w2k-compat\n")); AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT; } MyFreePool__(Extent2); return Extent; } // #ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT ASSERT(!(len & (Vcb->LBlockSize-1) )); #endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT if(len & (Vcb->LBlockSize-1)) { w2k_compat = TRUE; } Extent[i].extLength = (len+Vcb->LBlockSize-1) & ~(Vcb->LBlockSize-1); locAddr.logicalBlockNum = AllocDesc[i].extPosition; // Note: for compatibility Adaptec DirectCD we check 'len' here // That strange implementation records bogus extLocation in terminal entries if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) { Extent[i].extLocation = UDFPartLbaToPhys(Vcb, &locAddr); if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) { UDFPrint(("bad address (2)\n")); MyFreePool__(Extent); return NULL; } } else { Extent[i].extLocation = 0; } if(!len) { // some UDF implementations set strange AllocDesc sequence length, // but terminates it with zeros in proper place, so handle // this case ASSERT(i>=(lim-1)); ASSERT(!Extent[i].extLength); Extent[i].extLocation = 0; if(/*!SubCallCount &&*/ w2k_compat) { ExtPrint(("w2k-compat\n")); AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT; } return Extent; } Extent[i].extLength |= (type << 30); } // set terminator Extent[i].extLength = 0; Extent[i].extLocation = 0; if(/*!SubCallCount &&*/ w2k_compat) { ExtPrint(("w2k-compat\n")); AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT; } return Extent; } // end UDFShortAllocDescToMapping() /* This routine builds file mapping according to LongAllocDesc (LONG_AD) array */ PEXTENT_MAP UDFLongAllocDescToMapping( IN PVCB Vcb, IN PLONG_AD AllocDesc, IN uint32 AllocDescLength, IN uint32 SubCallCount, OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero) ) { uint32 i, lim, l, len, type; // uint32 BSh; PEXTENT_MAP Extent, Extent2, AllocMap; EXTENT_AD AllocExt; PALLOC_EXT_DESC NextAllocDesc; uint32 ReadBytes; EXTENT_INFO NextAllocLoc; ExtPrint(("UDFLongAllocDescToMapping: len=%x\n", AllocDescLength)); if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL; // BSh = Vcb->BlockSizeBits; l = ((lim = (AllocDescLength/sizeof(LONG_AD))) + 1 ) * sizeof(EXTENT_AD); Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG); if(!Extent) return NULL; NextAllocLoc.Offset = 0; for(i=0;i> 30; len = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK; ExtPrint(("LnExt: type %x, loc %x (%x:%x), len %x\n", type, UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)), AllocDesc[i].extLocation.partitionReferenceNum, AllocDesc[i].extLocation.logicalBlockNum, len)); if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) { // read next frag of allocation descriptors if encountered if(len < sizeof(ALLOC_EXT_DESC)) { MyFreePool__(Extent); return NULL; } NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG); if(!NextAllocDesc) { MyFreePool__(Extent); return NULL; } // record information about this frag AllocExt.extLength = len; AllocExt.extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) { UDFPrint(("bad address\n")); MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } NextAllocLoc.Mapping = AllocMap = UDFExtentToMapping(&AllocExt); NextAllocLoc.Length = len; if(!AllocMap) { MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap); if(!AllocLoc->Mapping || // read this frag !OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc, 0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes))) { MyFreePool__(AllocMap); MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } MyFreePool__(AllocMap); // check integrity if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) || (NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) { UDFPrint(("Integrity check failed\n")); UDFPrint(("NextAllocDesc->descTag.tagIdent = %x\n", NextAllocDesc->descTag.tagIdent)); UDFPrint(("NextAllocDesc->lengthAllocDescs = %x\n", NextAllocDesc->lengthAllocDescs)); UDFPrint(("len = %x\n", len)); MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } // perform recursive call to obtain mapping Extent2 = UDFLongAllocDescToMapping(Vcb, (PLONG_AD)(NextAllocDesc+1), NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc); if(!Extent2) { MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } // and merge this 2 mappings into 1 Extent[i].extLength = 0; Extent[i].extLocation = 0; Extent = UDFMergeMappings(Extent, Extent2); MyFreePool__(Extent2); return Extent; } // Extent[i].extLength = len; #ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT ASSERT(!(len & (Vcb->LBlockSize-1) )); #endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT Extent[i].extLength = (len+Vcb->LBlockSize-1) & ~(Vcb->LBlockSize-1); // Note: for compatibility Adaptec DirectCD we check 'len' here // That strange implementation records bogus extLocation in terminal entries if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) { Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) { UDFPrint(("bad address (2)\n")); MyFreePool__(Extent); return NULL; } } else { Extent[i].extLocation = 0; } if(!len) { // some UDF implementations set strange AllocDesc sequence length, // but terminates it with zeros in proper place, so handle // this case Extent[i].extLocation = 0; return Extent; } Extent[i].extLength |= (type << 30); } // set terminator Extent[i].extLength = 0; Extent[i].extLocation = 0; return Extent; } // end UDFLongAllocDescToMapping() /* This routine builds file mapping according to ExtendedAllocDesc (EXT_AD) array */ PEXTENT_MAP UDFExtAllocDescToMapping( IN PVCB Vcb, IN PEXT_AD AllocDesc, IN uint32 AllocDescLength, IN uint32 SubCallCount, OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero) ) { uint32 i, lim, l, len, type; // uint32 BSh; PEXTENT_MAP Extent, Extent2, AllocMap; EXTENT_AD AllocExt; PALLOC_EXT_DESC NextAllocDesc; uint32 ReadBytes; EXTENT_INFO NextAllocLoc; ExtPrint(("UDFExtAllocDescToMapping: len=%x\n", AllocDescLength)); if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL; // BSh = Vcb->BlockSizeBits; l = ((lim = (AllocDescLength/sizeof(EXT_AD))) + 1 ) * sizeof(EXTENT_AD); Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG); if(!Extent) return NULL; NextAllocLoc.Offset = 0; for(i=0;i> 30; len = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK; ExtPrint(("ExExt: type %x, loc %x, len %x\n", type, UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)), len)); if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) { // read next frag of allocation descriptors if encountered if(len < sizeof(ALLOC_EXT_DESC)) { MyFreePool__(Extent); return NULL; } NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG); if(!NextAllocDesc) { MyFreePool__(Extent); return NULL; } // record information about this frag AllocExt.extLength = len; AllocExt.extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) { UDFPrint(("bad address\n")); MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } NextAllocLoc.Mapping = AllocMap = UDFExtentToMapping(&AllocExt); NextAllocLoc.Length = len; if(!AllocMap) { MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap); if(!AllocLoc->Mapping || // read this frag !OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc, 0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes))) { MyFreePool__(AllocMap); MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } MyFreePool__(AllocMap); // check integrity if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) || (NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) { UDFPrint(("Integrity check failed\n")); MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } // perform recursive call to obtain mapping Extent2 = UDFExtAllocDescToMapping(Vcb, (PEXT_AD)(NextAllocDesc+1), NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc); if(!Extent2) { MyFreePool__(NextAllocDesc); MyFreePool__(Extent); return NULL; } // and merge this 2 mappings into 1 Extent[i].extLength = 0; Extent[i].extLocation = 0; Extent = UDFMergeMappings(Extent, Extent2); MyFreePool__(Extent2); return Extent; } /* if((AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK) > // Uncomment!!! (AllocDesc[i].recordedLength & UDF_EXTENT_LENGTH_MASK)) { Extent[i].extLength = AllocDesc[i].recordedLength; Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); }*/ Extent[i].extLength = len; #ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT ASSERT(!(len & (Vcb->LBlockSize-1) )); #endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT // Note: for compatibility Adaptec DirectCD we check 'len' here // That strange implementation records bogus extLocation in terminal entries if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) { Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) { UDFPrint(("bad address (2)\n")); MyFreePool__(Extent); return NULL; } } else { Extent[i].extLocation = 0; } if(!len) { // some UDF implementations set strange AllocDesc sequence length, // but terminates it with zeros in proper place, so handle // this case Extent[i].extLocation = 0; return Extent; } Extent[i].extLength |= (type << 30); } // set terminator Extent[i].extLength = 0; Extent[i].extLocation = 0; return Extent; } // end UDFExtAllocDescToMapping() /* This routine builds FileMapping according to given FileEntry Return: pointer to EXTENT_MAP array or offset inside FileEntry (negative) when ICB_FLAG_AD_IN_ICB encountered of NULL if an error occured */ PEXTENT_MAP UDFReadMappingFromXEntry( IN PVCB Vcb, IN uint32 PartNum, IN tag* XEntry, IN OUT uint32* Offset, OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero) ) { PEXTENT_AD Extent; uint16 AllocMode; int8* AllocDescs; uint32 len; // EntityID* eID; // for compatibility with Adaptec DirectCD Extent = NULL; (*Offset) = 0; if(XEntry->tagIdent == TID_FILE_ENTRY) { // UDFPrint(("Standard FileEntry\n")); PFILE_ENTRY FileEntry = (PFILE_ENTRY)XEntry; ExtPrint(("Standard FileEntry\n")); AllocDescs = (int8*)(((int8*)(FileEntry+1))+(FileEntry->lengthExtendedAttr)); len = FileEntry->lengthAllocDescs; AllocLoc->Offset = sizeof(FILE_ENTRY) + FileEntry->lengthExtendedAttr; // eID = &(FileEntry->impIdent); AllocMode = FileEntry->icbTag.flags & ICB_FLAG_ALLOC_MASK; } else if(XEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) { // UDFPrint(("Extended FileEntry\n")); ExtPrint(("Extended FileEntry\n")); PEXTENDED_FILE_ENTRY ExFileEntry = (PEXTENDED_FILE_ENTRY)XEntry; AllocDescs = (((int8*)(ExFileEntry+1))+(ExFileEntry->lengthExtendedAttr)); len = ExFileEntry->lengthAllocDescs; AllocLoc->Offset = sizeof(EXTENDED_FILE_ENTRY) + ExFileEntry->lengthExtendedAttr; // eID = &(FileEntry->impIdent); AllocMode = ExFileEntry->icbTag.flags & ICB_FLAG_ALLOC_MASK; } else { return NULL; } // for compatibility with Adaptec DirectCD // if(!(Vcb->UDF_VCB_IC_ADAPTEC_NONALLOC_COMPAT)) AllocLoc->Length=len; AllocLoc->Flags |= EXTENT_FLAG_VERIFY; // for metadata switch (AllocMode) { case ICB_FLAG_AD_SHORT: { Extent = UDFShortAllocDescToMapping(Vcb, PartNum, (PSHORT_AD)AllocDescs, len, 0, AllocLoc); break; } case ICB_FLAG_AD_LONG: { Extent = UDFLongAllocDescToMapping(Vcb, (PLONG_AD)AllocDescs, len, 0, AllocLoc); break; } case ICB_FLAG_AD_EXTENDED: { Extent = UDFExtAllocDescToMapping(Vcb, (PEXT_AD)AllocDescs, len, 0, AllocLoc); break; } default : { // case ICB_FLAG_AD_IN_ICB Extent = NULL; *Offset = (uint32)AllocDescs - (uint32)XEntry; AllocLoc->Offset=0; AllocLoc->Length=0; if(AllocLoc->Mapping) MyFreePool__(AllocLoc->Mapping); AllocLoc->Mapping=NULL; break; } } ExtPrint(("UDFReadMappingFromXEntry: mode %x, loc %x, len %x\n", AllocMode, AllocLoc->Mapping ? AllocLoc->Mapping[0].extLocation : -1, len)); UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used return Extent; }// end UDFReadMappingFromXEntry() #ifndef UDF_READ_ONLY_BUILD /* This routine builds data for AllocDesc sequence for specified extent */ OSSTATUS UDFBuildShortAllocDescs( IN PVCB Vcb, IN uint32 PartNum, OUT int8** Buff, // data for AllocLoc IN uint32 InitSz, IN OUT PUDF_FILE_INFO FileInfo ) { uint32 i, j; uint32 len=0; PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping; PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc); PSHORT_AD Alloc; uint32 NewLen; OSSTATUS status; uint32 ph_len=0; // in general, this should be uint64, // but we need its lower part only #ifdef UDF_ALLOW_FRAG_AD uint32 ts, ac, len2; uint32 LBS = Vcb->LBlockSize; uint32 LBSh = Vcb->BlockSizeBits; uint32 TagLen = 0; tag* Tag = NULL; PSHORT_AD saved_Alloc; uint32 TagLoc, prevTagLoc; uint32 BufOffs; uint32 ExtOffs; uint32 saved_NewLen; #endif //UDF_ALLOW_FRAG_AD ValidateFileInfo(FileInfo); ExtPrint(("UDFBuildShortAllocDescs: FE %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); // calculate length for(len=0; (i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK)); len++, ph_len+=i) { ExtPrint(("bShExt: type %x, loc %x, len %x\n", Extent[len].extLength >> 30, Extent[len].extLocation, Extent[len].extLength & UDF_EXTENT_LENGTH_MASK)); } Alloc = (PSHORT_AD)MyAllocatePoolTag__(NonPagedPool, (len+1)*sizeof(SHORT_AD), MEM_SHAD_TAG); if(!Alloc) { BrutePoint(); return STATUS_INSUFFICIENT_RESOURCES; } // fill contiguous AllocDesc buffer (decribing UserData) for(i=0;iCompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) && i) { Alloc[i-1].extLength -= (ph_len - (ULONG)(FileInfo->Dloc->DataLoc.Length)) & (Vcb->LBlockSize-1); ExtPrint(("bShExt: cut tail -> %x\n", Alloc[i-1].extLength & UDF_EXTENT_LENGTH_MASK)); } Alloc[i].extLength = Alloc[i].extPosition = 0; j = len*sizeof(SHORT_AD); // required space len = (InitSz & ~(sizeof(SHORT_AD)-1)); // space available in 1st block ASSERT(len == InitSz); // Ok. Let's init AllocLoc if(!(FileInfo->Dloc->AllocLoc.Mapping)) { FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, 2 * sizeof(EXTENT_MAP), MEM_EXTMAP_TAG); if(!(FileInfo->Dloc->AllocLoc.Mapping)) { BrutePoint(); MyFreePool__(Alloc); return STATUS_INSUFFICIENT_RESOURCES; } // allocation descriptors are located in the same sector as FileEntry // (at least their 1st part), just after it FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0]; FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen; FileInfo->Dloc->AllocLoc.Length = 0; // set terminator FileInfo->Dloc->AllocLoc.Mapping[1].extLength = FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0; } if(j <= len) { // we needn't allocating additional blocks to store AllocDescs AdPrint(("in-ICB AllocDescs, j=%x\n",j)); RtlCopyMemory(*Buff, (int8*)Alloc, j); NewLen = j; MyFreePool__(Alloc); } else { #ifndef UDF_ALLOW_FRAG_AD AdPrint((" DISK_FULL\n")); return STATUS_DISK_FULL; #else //UDF_ALLOW_FRAG_AD AdPrint(("multi-block AllocDescs, j=%x\n",j)); BufOffs = 0; TagLoc = prevTagLoc = 0; // calculate the space available for SHORT_ADs in each block ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(SHORT_AD))) & ~(sizeof(SHORT_AD)-1); len2 = len; // tail size ts = InitSz - len2; len -= sizeof(SHORT_AD); // calculate actual AllocSequence length (in bytes) NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + InitSz + sizeof(SHORT_AD); MyFreePool__(*Buff); (*Buff) = (int8*)MyAllocatePoolTag__(NonPagedPool, NewLen, MEM_SHAD_TAG); if(!(*Buff)) { status = STATUS_INSUFFICIENT_RESOURCES; UDFPrint(("UDFResizeExtent() failed (%x)\n",status)); BrutePoint(); goto sh_alloc_err; } if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) { status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); if(!OS_SUCCESS(status)) { UDFPrint(("UDFResizeExtent(2) failed (%x)\n",status)); BrutePoint(); sh_alloc_err: MyFreePool__(Alloc); return status; } } ExtOffs = AllocExtent->Offset; RtlZeroMemory(*Buff, NewLen); saved_NewLen = NewLen; NewLen = 0; // recorded length saved_Alloc = Alloc; // fill buffer sector by sector (adding links at the end of each one) while(TRUE) { // j - remained AllocDescs length (in bytes) // len - bytes available for AllocDescs in current block // ac - bytes available for AllocDescs in each block // leave space for terminator or pointer to next part of sequence if(j == len2) { // if we have only 1 SHORT_AD that we can fit in last sector // we shall do it instead of recording link & allocating new block len = TagLen = len2; } ASSERT(saved_NewLen >= (BufOffs + len)); RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len); Alloc = (PSHORT_AD)((int8*)Alloc + len); j -= len; BufOffs += len; if(Tag) { // Set up Tag for AllocDesc Tag->tagIdent = TID_ALLOC_EXTENT_DESC; UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc); prevTagLoc = TagLoc; } if(!j) { // terminate loop NewLen = BufOffs; break; } len = ac; if(j <= (len + sizeof(SHORT_AD))) len = j - sizeof(SHORT_AD); len2 = len + sizeof(SHORT_AD); // we have more than 1 SHORT_AD that we can't fit in current block // so we shall set up pointer to the next block ((PSHORT_AD)((*Buff)+BufOffs))->extLength = /*LBS*/ len2 | (((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ; ((PSHORT_AD)((*Buff)+BufOffs))->extPosition = TagLoc = UDFPhysLbaToPart(Vcb, PartNum, UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping, ExtOffs+BufOffs+sizeof(SHORT_AD)+ts, NULL, NULL, NULL, NULL) ); // reflect additional (link) block & LBlock tail (if any) BufOffs += ts+sizeof(SHORT_AD); // init AllocDesc ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2; ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc; Tag = (tag*)((*Buff)+BufOffs); TagLen = len2; ts = LBS-len2-sizeof(ALLOC_EXT_DESC); BufOffs += sizeof(ALLOC_EXT_DESC); } MyFreePool__(saved_Alloc); #endif //UDF_ALLOW_FRAG_AD } status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); return status; } // end UDFBuildShortAllocDescs() /* This routine builds data for AllocDesc sequence for specified extent */ OSSTATUS UDFBuildLongAllocDescs( IN PVCB Vcb, IN uint32 PartNum, OUT int8** Buff, // data for AllocLoc IN uint32 InitSz, IN OUT PUDF_FILE_INFO FileInfo ) { uint32 i, j; uint32 len=0; PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping; PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc); PLONG_AD Alloc; uint32 NewLen; OSSTATUS status; uint32 ph_len=0; // in general, this should be uint64, // but we need its lower part only #ifdef UDF_ALLOW_FRAG_AD uint32 ac, len2, ts; uint32 TagLoc, prevTagLoc; uint32 LBS = Vcb->LBlockSize; uint32 LBSh = Vcb->BlockSizeBits; uint32 BufOffs; uint32 ExtOffs = AllocExtent->Offset; PLONG_AD saved_Alloc; uint32 TagLen = 0; tag* Tag = NULL; #endif //UDF_ALLOW_FRAG_AD ValidateFileInfo(FileInfo); ExtPrint(("UDFBuildLongAllocDescs: FE %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); // calculate length //for(len=0; i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK); len++, ph_len+=i); for(len=0; (i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK)); len++, ph_len+=i) { ExtPrint(("bLnExt: type %x, loc %x, len %x\n", Extent[len].extLength >> 30, Extent[len].extLocation, Extent[len].extLength & UDF_EXTENT_LENGTH_MASK)); } Alloc = (PLONG_AD)MyAllocatePoolTag__(NonPagedPool, (len+1)*sizeof(LONG_AD), MEM_LNGAD_TAG); if(!Alloc) return STATUS_INSUFFICIENT_RESOURCES; // fill contiguous AllocDesc buffer (decribing UserData) for(i=0;iCompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) && i) { Alloc[i-1].extLength -= (ph_len - (ULONG)(FileInfo->Dloc->DataLoc.Length)) & (Vcb->LBlockSize-1); ExtPrint(("bLnExt: cut tail -> %x\n", Alloc[i-1].extLength & UDF_EXTENT_LENGTH_MASK)); } RtlZeroMemory(&(Alloc[i]), sizeof(LONG_AD)); j = len*sizeof(LONG_AD); // required space len = (InitSz & ~(sizeof(LONG_AD)-1)); // space available in 1st block ASSERT(len == InitSz); // Ok. Let's init AllocLoc if(!(FileInfo->Dloc->AllocLoc.Mapping)) { FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, 2 * sizeof(EXTENT_MAP), MEM_EXTMAP_TAG); if(!(FileInfo->Dloc->AllocLoc.Mapping)) { MyFreePool__(Alloc); return STATUS_INSUFFICIENT_RESOURCES; } // allocation descriptors are located in the same sector as FileEntry // (at least their 1st part), just after it FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0]; FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen; FileInfo->Dloc->AllocLoc.Length = 0; // set terminator FileInfo->Dloc->AllocLoc.Mapping[1].extLength = FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0; } if(j <= len) { // we needn't allocating additional blocks to store AllocDescs RtlCopyMemory(*Buff, (int8*)Alloc, j); NewLen = j; MyFreePool__(Alloc); } else { #ifndef UDF_ALLOW_FRAG_AD AdPrint((" DISK_FULL\n")); return STATUS_DISK_FULL; #else //UDF_ALLOW_FRAG_AD BufOffs = 0; TagLoc = prevTagLoc = 0; // calculate the space available for LONG_ADs in each block ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(LONG_AD))) & ~(sizeof(LONG_AD)-1); len2 = len; // tail size ts = InitSz - len2; len -= sizeof(LONG_AD); // calculate actual AllocSequence length (in LBlocks) NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + InitSz + sizeof(LONG_AD); MyFreePool__(*Buff); (*Buff) = (int8*)MyAllocatePoolTag__(NonPagedPool, NewLen, MEM_LNGAD_TAG); if(!(*Buff)) { status = STATUS_INSUFFICIENT_RESOURCES; goto lad_alloc_err; } if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) { status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); if(!OS_SUCCESS(status)) { lad_alloc_err: MyFreePool__(Alloc); return status; } } ExtOffs = AllocExtent->Offset; RtlZeroMemory(*Buff, NewLen); NewLen = 0; // recorded length saved_Alloc = Alloc; len2 = len+sizeof(LONG_AD); // fill buffer sector by sector (adding links at the end of each one) while(TRUE) { // j - remained AllocDescs length (in bytes) // len - bytes available for in AllocDescs each block // leave space for terminator or pointer to next part of sequence if(j == len2) { // if we have only 1 LONG_AD that we can fit in last sector // we shall do it instead of recording link & allocating new block len = TagLen = len2; } RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len); Alloc = (PLONG_AD)((int8*)Alloc + len); j -= len; BufOffs += len; if(Tag) { // Set up Tag for AllocDesc Tag->tagIdent = TID_ALLOC_EXTENT_DESC; UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc); prevTagLoc = TagLoc; } if(!j) { // terminate loop NewLen = BufOffs; break; } len = ac; if(j <= (len + sizeof(LONG_AD))) len = j - sizeof(LONG_AD); len2 = len+sizeof(LONG_AD); // we have more than 1 LONG_AD that we can't fit in current block // so we shall set up pointer to the next block ((PLONG_AD)((*Buff)+BufOffs))->extLength = /*LBS*/ len2 | (((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ; ((PLONG_AD)((*Buff)+BufOffs))->extLocation.logicalBlockNum = TagLoc = UDFPhysLbaToPart(Vcb, PartNum, UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping, ExtOffs+BufOffs+sizeof(LONG_AD)+ts, NULL, NULL, NULL, NULL) ); ((PLONG_AD)((*Buff)+BufOffs))->extLocation.partitionReferenceNum = (uint16)PartNum; // reflect additional (link) block & LBlock tail (if any) BufOffs += ts+sizeof(LONG_AD); // init AllocDesc ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2; ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc; Tag = (tag*)((*Buff)+BufOffs); TagLen = len2; ts = LBS-len2-sizeof(ALLOC_EXT_DESC); BufOffs += sizeof(ALLOC_EXT_DESC); } MyFreePool__(saved_Alloc); #endif //UDF_ALLOW_FRAG_AD } status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); return status; } // end UDFBuildLongAllocDescs() /* This routine builds data for AllocDesc sequence for specified extent */ /*OSSTATUS UDFBuildExtAllocDescs( IN PVCB Vcb, IN uint32 PartNum, OUT int8** Buff, // data for AllocLoc IN uint32 InitSz, IN OUT PUDF_FILE_INFO FileInfo ) { uint32 i, j; uint32 len=0, ac, len2; uint32 TagLoc, prevTagLoc; uint32 LBS = Vcb->LBlockSize; uint32 LBSh = Vcb->BlockSizeBits; PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping; PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc); PEXT_AD Alloc, saved_Alloc; uint32 BufOffs; uint32 ExtOffs = AllocExtent->Offset; uint32 NewLen; OSSTATUS status; uint32 TagLen = 0; tag* Tag = NULL; ValidateFileInfo(FileInfo); // calculate length for(len=0; Extent[len].extLength; len++); Alloc = (PEXT_AD)MyAllocatePool__(NonPagedPool, (len+1)*sizeof(EXT_AD)); if(!Alloc) return STATUS_INSUFFICIENT_RESOURCES; // fill contiguous AllocDesc buffer (decribing UserData) for(i=0;iDloc->AllocLoc.Mapping)) { FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, 2 * sizeof(EXTENT_MAP)); if(!(FileInfo->Dloc->AllocLoc.Mapping)) { MyFreePool__(Alloc); return STATUS_INSUFFICIENT_RESOURCES; } // allocation descriptors are located in the same sector as FileEntry // (at least their 1st part), just after it FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0]; FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen; FileInfo->Dloc->AllocLoc.Length = 0; // set terminator FileInfo->Dloc->AllocLoc.Mapping[1].extLength = FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0; } if(j <= len) { // we needn't allocating additional blocks to store AllocDescs RtlCopyMemory(*Buff, (int8*)Alloc, j); NewLen = j; MyFreePool__(Alloc); } else { BufOffs = 0; TagLoc = prevTagLoc = 0; // calculate the space available for EXT_ADs in each block ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(EXT_AD))) & ~(sizeof(EXT_AD)-1); // calculate actual AllocSequence length (in LBlocks) len -= sizeof(EXT_AD); NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + len + sizeof(EXT_AD); MyFreePool__(*Buff); (*Buff) = (int8*)MyAllocatePool__(NonPagedPool, NewLen); if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) { status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); if(!OS_SUCCESS(status)) { MyFreePool__(Alloc); return status; } } RtlZeroMemory(*Buff, NewLen); NewLen = 0; // recorded length saved_Alloc = Alloc; len2 = len + sizeof(EXT_AD); // fill buffer sector by sector (adding links at the end of each one) while(TRUE) { // j - remained AllocDescs length (in bytes) // len - bytes available for in AllocDescs each block // leave space for terminator or pointer to next part of sequence if(j == len2) { // if we have only 1 EXT_AD that we can fit in last sector // we shall do it instead of recording link & allocating new block len = TagLen = len2; } RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len); Alloc = (PEXT_AD)((int8*)Alloc + len); j -= len; BufOffs += len; if(Tag) { // Set up Tag for AllocDesc Tag->tagIdent = TID_ALLOC_EXTENT_DESC; UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc); prevTagLoc = TagLoc; } if(!j) { // terminate loop NewLen = BufOffs; break; } len = ac; if(j <= (len + sizeof(EXT_AD))) len = j - sizeof(EXT_AD); len2 = len + sizeof(EXT_AD); // we have more than 1 EXT_AD that we can't fit in current block // so we shall set up pointer to the next block ((PEXT_AD)((*Buff)+BufOffs))->extLength = ((PEXT_AD)((*Buff)+BufOffs))->recordedLength = LBS; ((PEXT_AD)((*Buff)+BufOffs))->informationLength = len2 | (((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ; ((PEXT_AD)((*Buff)+BufOffs))->extLocation.logicalBlockNum = TagLoc = UDFPhysLbaToPart(Vcb, PartNum, UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping, ExtOffs + BufOffs + 2*sizeof(EXT_AD)-1, NULL, NULL, NULL, NULL) ); ((PEXT_AD)((*Buff)+BufOffs))->extLocation.partitionReferenceNum = (uint16)PartNum; BufOffs = (BufOffs + 2*sizeof(EXT_AD) - 1) & ~(sizeof(EXT_AD)-1) ; // init AllocDesc ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2; ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc; Tag = (tag*)((*Buff)+BufOffs); TagLen = len2; BufOffs += sizeof(ALLOC_EXT_DESC); } MyFreePool__(saved_Alloc); } status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); return status; } // end UDFBuildExtAllocDescs()*/ void UDFDiscardFESpace( IN PVCB Vcb, IN PEXTENT_MAP Mapping, IN uint32 lim ) { #ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE PEXTENT_MAP Mapping2; uint32 i; UDFPrint((" DiscardFESpace\n")); Mapping2 = Mapping; for(i=0;iextLength >> 30) == EXTENT_RECORDED_ALLOCATED) { UDFPrint((" used @ %x\n", Mapping->extLocation)); Mapping->extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); Mapping->extLocation = 0; } else { UDFPrint((" free @ %x\n", Mapping->extLocation)); } } UDFMarkSpaceAsXXX(Vcb, 0, Mapping2, AS_DISCARDED); MyFreePool__(Mapping2); #else // UDF_FE_ALLOCATION_CHARGE ASSERT(!Dloc->DirIndex->FECharge.Mapping); return; #endif // UDF_FE_ALLOCATION_CHARGE } // end UDFDiscardFESpace() OSSTATUS UDFInitAllocationCache( IN PVCB Vcb, IN uint32 AllocClass, OUT PUDF_ALLOCATION_CACHE_ITEM* _AllocCache, OUT uint32* _lim, IN BOOLEAN Init ) { PUDF_ALLOCATION_CACHE_ITEM AllocCache; PUDF_ALLOCATION_CACHE_ITEM* pAllocCache; uint32 i, lim; uint32* plim; switch(AllocClass) { case UDF_PREALLOC_CLASS_FE: UDFPrint(("AllocationCache FE:\n")); pAllocCache = &(Vcb->FEChargeCache); plim = &(Vcb->FEChargeCacheMaxSize); lim = 32; break; case UDF_PREALLOC_CLASS_DIR: UDFPrint(("AllocationCache DIR:\n")); pAllocCache = &(Vcb->PreallocCache); plim = &(Vcb->PreallocCacheMaxSize); lim = 32; break; default: return STATUS_INVALID_PARAMETER; } if(!(*plim)) { if(!Init) { return STATUS_UNSUCCESSFUL; } (*pAllocCache) = AllocCache = (PUDF_ALLOCATION_CACHE_ITEM) MyAllocatePoolTag__(NonPagedPool , sizeof(UDF_ALLOCATION_CACHE_ITEM)*lim, MEM_ALLOC_CACHE_TAG); if(!AllocCache) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(AllocCache, sizeof(UDF_ALLOCATION_CACHE_ITEM)*lim); for(i=0; iPreallocResource),TRUE); status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, FALSE); if(!OS_SUCCESS(status)) { UDFReleaseResource(&(Vcb->PreallocResource)); return status; } UDFPrint(("Get AllocationCache for %x\n", ParentLocation)); for(i=0; iMapping, i)); if(Items) { (*Items) = AllocCache[i].Items; } RtlZeroMemory(&(AllocCache[i]), sizeof(AllocCache[i])); AllocCache[i].ParentLocation = LBA_NOT_ALLOCATED; UDFReleaseResource(&(Vcb->PreallocResource)); return STATUS_SUCCESS; } } AdPrint((" no map\n")); UDFReleaseResource(&(Vcb->PreallocResource)); return STATUS_UNSUCCESSFUL; } // end UDFGetCachedAllocation() OSSTATUS UDFStoreCachedAllocation( IN PVCB Vcb, IN uint32 ParentLocation, IN PEXTENT_INFO Ext, IN uint32 Items, IN uint32 AllocClass ) { PUDF_ALLOCATION_CACHE_ITEM AllocCache; uint32 i, lim; OSSTATUS status; UDFAcquireResourceExclusive(&(Vcb->PreallocResource),TRUE); status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, TRUE); if(!OS_SUCCESS(status)) { UDFReleaseResource(&(Vcb->PreallocResource)); return status; } UDFPrint(("Store AllocationCache for %x, map %x\n", ParentLocation, Ext->Mapping)); for(i=0; iPreallocResource)); return STATUS_SUCCESS; } } // AdPrint((" drop map %x (%x)\n", AllocCache[lim-1].Ext.Mapping, lim-1)); switch(AllocClass) { case UDF_PREALLOC_CLASS_FE: UDFDiscardFESpace(Vcb, AllocCache[lim-1].Ext.Mapping, AllocCache[lim-1].Items); break; case UDF_PREALLOC_CLASS_DIR: UDFMarkSpaceAsXXX(Vcb, 0, AllocCache[lim-1].Ext.Mapping, AS_DISCARDED); break; } RtlMoveMemory(&(AllocCache[1]), &(AllocCache[0]), sizeof(UDF_ALLOCATION_CACHE_ITEM)*(lim-1)); AllocCache[0].Ext = (*Ext); AllocCache[0].Items = Items; AllocCache[0].ParentLocation = ParentLocation; AdPrint((" stored in 0\n")); UDFReleaseResource(&(Vcb->PreallocResource)); return STATUS_SUCCESS; } // end UDFStoreCachedAllocation() OSSTATUS UDFFlushAllCachedAllocations( IN PVCB Vcb, IN uint32 AllocClass ) { PUDF_ALLOCATION_CACHE_ITEM AllocCache; uint32 i, lim; OSSTATUS status; UDFPrint(("Flush AllocationCache\n")); UDFAcquireResourceExclusive(&(Vcb->PreallocResource),TRUE); status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, FALSE); if(!OS_SUCCESS(status)) { UDFReleaseResource(&(Vcb->PreallocResource)); return status; } for(i=0; iFEChargeCache = NULL; Vcb->FEChargeCacheMaxSize = 0; break; case UDF_PREALLOC_CLASS_DIR: Vcb->PreallocCache = NULL; Vcb->PreallocCacheMaxSize = 0; break; } UDFReleaseResource(&(Vcb->PreallocResource)); // return STATUS_SUCCESS; } // end UDFFlushAllCachedAllocations() /* This routine allocates space for FE of the file being created If FE-Charge is enabled it reserves an extent & allocates space in it. It works much faster then usual way both while allocating & accessing on disk If FE-Charge is disabled FE may be allocated at any suitable location */ OSSTATUS UDFAllocateFESpace( IN PVCB Vcb, IN PUDF_FILE_INFO DirInfo, IN uint32 PartNum, IN PEXTENT_INFO FEExtInfo, IN uint32 Len ) { #ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE OSSTATUS status; PEXTENT_INFO Ext; EXTENT_AD Extent; BOOLEAN retry = FALSE; uint32 i, lim; /* 1. #Dir1#->*File* -> Dir1's FECharge 2. #Dir1#->*Dir* -> Dir1's FECharge 3. #Dir1#->*SDir* -> Dir1's FECharge 4. Dir1->#SDir#->*Stream* -> Dir1's FEChargeSDir 5. Dir1->#File#->*SDir* -> Dir1's FEChargeSDir 6. Dir1->#Dir#->*SDir* -> (see p.2) 7. Dir1->File->#SDir#->*Stream* -> Dir1's FEChargeSDir 8. Dir1->Dir->#SDir#->*Stream* -> (see p.4) ## ~ DirInfo ** ~ Object to be created */ // ASSERT(!FEExtInfo->Mapping); // check if DirInfo we are called with is a Directory // (it can be a file with SDir) if(!DirInfo || !DirInfo->Dloc->DirIndex || ((lim = ((DirInfo->Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge)) <= 1)) #endif // UDF_FE_ALLOCATION_CHARGE return UDFAllocFreeExtent(Vcb, Len, UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), FEExtInfo, EXTENT_FLAG_VERIFY); #ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE Ext = &(DirInfo->Dloc->DirIndex->FECharge); while(TRUE) { if(!Ext->Mapping) { ULONG p_start; ULONG p_end; ULONG fe_loc; ULONG l1, l2; p_start = UDFPartStart(Vcb, PartNum); p_end = UDFPartEnd(Vcb, PartNum); fe_loc = DirInfo->Dloc->FELoc.Mapping[0].extLocation; status = UDFGetCachedAllocation(Vcb, fe_loc, Ext, NULL, UDF_PREALLOC_CLASS_FE); if(OS_SUCCESS(status)) { // do nothing, even do not unpack } else if(Vcb->LowFreeSpace) { status = UDFAllocFreeExtent(Vcb, Len << Vcb->LBlockSizeBits,p_start, p_end, FEExtInfo, EXTENT_FLAG_VERIFY); if(OS_SUCCESS(status)) { UDFPrint(("FE @ %x (1)\n", FEExtInfo->Mapping[0].extLocation )); } return status; } else { if(fe_loc > p_start + 512*16) { l1 = fe_loc - 512*16; } else { l1 = p_start; } if(fe_loc + 512*16 < p_end) { l2 = fe_loc + 512*16; } else { l2 = p_end; } status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, l1, l2, Ext, EXTENT_FLAG_VERIFY); if(!OS_SUCCESS(status)) { status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, (p_start+fe_loc)/2, (fe_loc+p_end)/2, Ext, EXTENT_FLAG_VERIFY); } if(!OS_SUCCESS(status)) { status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start, p_end, Ext, EXTENT_FLAG_VERIFY); } if(!OS_SUCCESS(status)) { status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start+1024, p_end-1024, Ext, EXTENT_FLAG_VERIFY); } if(!OS_SUCCESS(status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start, p_end, Ext, EXTENT_FLAG_VERIFY) )) { // can't pre-allocate space for multiple FEs. Try single FE UDFPrint(("allocate single FE entry\n")); status = UDFAllocFreeExtent(Vcb, Len, p_start, p_end, FEExtInfo, EXTENT_FLAG_VERIFY); if(OS_SUCCESS(status)) { UDFPrint(("FE @ %x (2)\n", FEExtInfo->Mapping[0].extLocation )); } return status; } status = UDFUnPackMapping(Vcb, Ext); if(!OS_SUCCESS(status)) { MyFreePool__(Ext->Mapping); Ext->Mapping = NULL; return status; } } } for(i=0;iMapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED ) { Ext->Mapping[i].extLength &= UDF_EXTENT_LENGTH_MASK; // EXTENT_RECORDED_ALLOCATED Extent.extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_ALLOCATED << 30); Extent.extLocation = Ext->Mapping[i].extLocation; if(Vcb->BSBM_Bitmap) { uint32 lba = Ext->Mapping[i].extLocation; if(UDFGetBadBit((uint32*)(Vcb->BSBM_Bitmap), lba)) { UDFPrint(("Remove BB @ %x from FE charge\n", lba)); Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); Ext->Mapping[i].extLocation = 0; continue; } } FEExtInfo->Mapping = UDFExtentToMapping(&Extent); if(!FEExtInfo->Mapping) { ASSERT(!(Ext->Mapping[i].extLength >> 30)); Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); return STATUS_INSUFFICIENT_RESOURCES; } UDFPrint(("FE @ %x (3)\n", FEExtInfo->Mapping[0].extLocation )); FEExtInfo->Length = Len; FEExtInfo->Offset = 0; FEExtInfo->Modified = TRUE; return STATUS_SUCCESS; } } if(Vcb->LowFreeSpace) { status = UDFAllocFreeExtent(Vcb, Len, UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), FEExtInfo, EXTENT_FLAG_VERIFY); if(OS_SUCCESS(status)) { UDFPrint(("FE @ %x (4)\n", FEExtInfo->Mapping[0].extLocation )); } return status; } if(retry) return STATUS_INSUFFICIENT_RESOURCES; // we can get here if there are no free slots in // preallocated FE charge. So, we should release // memory and try to allocate space for new FE charge. MyFreePool__(Ext->Mapping); Ext->Mapping = NULL; retry = TRUE; } return STATUS_INSUFFICIENT_RESOURCES; #endif // UDF_FE_ALLOCATION_CHARGE } // end UDFAllocateFESpace() /* This routine frees space allocated for FE. */ void UDFFreeFESpace( IN PVCB Vcb, IN PUDF_FILE_INFO DirInfo, IN PEXTENT_INFO FEExtInfo ) { #ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE PEXTENT_INFO Ext; uint32 i, lim, j=-1; uint32 Lba; // check if the DirInfo we are called with is a Directory // (it can be a file with SDir) if(DirInfo && DirInfo->Dloc->DirIndex && (Ext = &(DirInfo->Dloc->DirIndex->FECharge))->Mapping) { if(!FEExtInfo->Mapping) return; Lba = FEExtInfo->Mapping[0].extLocation; lim = (DirInfo->Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge; for(i=0;iMapping[i].extLocation == Lba) { ASSERT(!(Ext->Mapping[i].extLength >> 30)); Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); goto clean_caller; } if(!Ext->Mapping[i].extLocation) { j = i; } } if(j != (ULONG)-1) { i = j; Ext->Mapping[i].extLocation = Lba; Ext->Mapping[i].extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_ALLOCATED << 30); goto clean_caller; } } #endif // UDF_FE_ALLOCATION_CHARGE UDFMarkSpaceAsXXX(Vcb, 0, FEExtInfo->Mapping, AS_DISCARDED); // free clean_caller: FEExtInfo->Mapping[0].extLocation = 0; FEExtInfo->Mapping[0].extLength = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); return; } // end UDFFreeFESpace() #endif //UDF_READ_ONLY_BUILD /* This routine flushes FE-Charge buffer, marks unused blocks as free in bitmap & releases memory allocated for FE-Charge management */ void UDFFlushFESpace( IN PVCB Vcb, IN PUDF_DATALOC_INFO Dloc, IN BOOLEAN Discard ) { #ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE PEXTENT_MAP Mapping; uint32 lim; if(!(Mapping = Dloc->DirIndex->FECharge.Mapping)) return; lim = (Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge; if(!Discard) { // cache it! if(OS_SUCCESS(UDFStoreCachedAllocation(Vcb, Dloc->FELoc.Mapping[0].extLocation, &Dloc->DirIndex->FECharge, lim, UDF_PREALLOC_CLASS_FE))) { Dloc->DirIndex->FECharge.Mapping = NULL; return; } } Dloc->DirIndex->FECharge.Mapping = NULL; UDFDiscardFESpace(Vcb, Mapping, lim); #else // UDF_FE_ALLOCATION_CHARGE ASSERT(!Dloc->DirIndex->FECharge.Mapping); return; #endif // UDF_FE_ALLOCATION_CHARGE } // end UDFFlushFESpace() #ifndef UDF_READ_ONLY_BUILD /* This routine rebuilds mapping on write attempts to Alloc-Not-Rec area. Here we assume that required area lays in a single frag. */ OSSTATUS UDFMarkAllocatedAsRecorded( IN PVCB Vcb, IN int64 Offset, IN uint32 Length, IN PEXTENT_INFO ExtInfo // Extent array ) { uint32 i, len, lba, sLen; PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array PEXTENT_MAP NewExtent; uint32 BS = Vcb->BlockSize; uint32 LBS = Vcb->LBlockSize; uint32 BSh = Vcb->BlockSizeBits; BOOLEAN TryPack = TRUE; #ifdef UDF_DBG int64 check_size; #endif //UDF_DBG // I don't know what else comment can be added here. // Just belive that it works lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, (Offset & ~((int64)LBS-1)), NULL, NULL, NULL, &i); if(i == (ULONG)-1) return STATUS_INVALID_PARAMETER; #ifdef UDF_DBG check_size = UDFGetExtentLength(ExtInfo->Mapping); ASSERT(!(check_size & (LBS-1))); #endif //UDF_DBG AdPrint(("Alloc->Rec ExtInfo %x, Extent %x\n", ExtInfo, Extent)); if((Extent[i].extLength >> 30) == EXTENT_RECORDED_ALLOCATED) return STATUS_SUCCESS; if((Extent[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) return STATUS_INVALID_PARAMETER; ASSERT((((uint32)Offset) & (LBS-1)) + Length <= (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK)); sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh; if((Extent[i].extLocation == lba) && (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK ) >> BSh) == sLen)) { // xxxxxx -> RRRRRR Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK; // Extent[i].extLength |= (EXTENT_RECORDED_ALLOCATED << 30); // = 0; ExtInfo->Modified = TRUE; if(i && ((Extent[i-1].extLength >> 30) == EXTENT_RECORDED_ALLOCATED) && (lba == (Extent[i-1].extLocation + ((len = Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh))) && ((len + (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK)) <= UDF_MAX_EXTENT_LENGTH) && (i == ((UDFGetMappingLength(Extent) / sizeof(EXTENT_MAP)) - 2)) && TRUE) { // make optimization for sequentially written files Extent[i-1].extLength += Extent[i].extLength; Extent[i].extLocation = 0; Extent[i].extLength = 0; } else { UDFPackMapping(Vcb, ExtInfo); } AdPrint(("Alloc->Rec (1) new %x\n", ExtInfo->Mapping)); #ifdef UDF_DBG ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping)); #endif AdPrint(("Alloc->Rec: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping)); return STATUS_SUCCESS; } if(Extent[i].extLocation < lba) { if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (lba - Extent[i].extLocation)) > sLen ) { // xxxxxx -> xxRRxx NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP)*2, MEM_EXTMAP_TAG); if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES; Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK; RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); RtlCopyMemory((int8*)&(NewExtent[i+3]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); NewExtent[i].extLocation = Extent[i].extLocation; NewExtent[i].extLength = (lba - Extent[i].extLocation) << BSh; NewExtent[i+1].extLength = (Length+BS-1) & ~(BS-1); NewExtent[i+1].extLocation = lba; NewExtent[i+2].extLength = Extent[i].extLength - NewExtent[i].extLength - NewExtent[i+1].extLength; NewExtent[i+2].extLocation = lba + ((Length+BS-1) >> BSh); ASSERT(!(NewExtent[i].extLength >> 30)); ASSERT(!(NewExtent[i+2].extLength >> 30)); NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); NewExtent[i+2].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); TryPack = FALSE; AdPrint(("Alloc->Rec (2) new %x\n", NewExtent)); } else { // xxxxxx -> xxRRRR NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP), MEM_EXTMAP_TAG); if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES; Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK; RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); NewExtent[i].extLocation = Extent[i].extLocation; NewExtent[i].extLength = (lba - Extent[i].extLocation) << BSh; NewExtent[i+1].extLength = Extent[i].extLength - NewExtent[i].extLength; NewExtent[i+1].extLocation = lba; ASSERT(!(NewExtent[i].extLength >> 30)); NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); AdPrint(("Alloc->Rec (3) new %x\n", NewExtent)); } } else { // xxxxxx -> RRRRxx NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP), MEM_EXTMAP_TAG); if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES; Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK; RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); NewExtent[i].extLocation = Extent[i].extLocation; NewExtent[i].extLength = (Length+BS-1) & ~(BS-1); NewExtent[i+1].extLength = Extent[i].extLength - NewExtent[i].extLength; NewExtent[i+1].extLocation = Extent[i].extLocation + (NewExtent[i].extLength >> BSh); ASSERT(!(NewExtent[i+1].extLength >> 30)); NewExtent[i+1].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); AdPrint(("Alloc->Rec (4) new %x\n", NewExtent)); } //ASSERT(check_size == UDFGetExtentLength(Extent)); //ASSERT(!(check_size & (LBS-1))); AdPrint(("Free Extent %x (new %x)\n", Extent, NewExtent)); MyFreePool__(Extent); ExtInfo->Modified = TRUE; ExtInfo->Mapping = NewExtent; if(TryPack) UDFPackMapping(Vcb, ExtInfo); #ifdef UDF_DBG ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping)); ASSERT(!(check_size & (LBS-1))); #endif AdPrint(("Alloc->Rec: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping)); return STATUS_SUCCESS; } // end UDFMarkAllocatedAsRecorded() /* This routine rebuilds mapping on write attempts to Not-Alloc-Not-Rec area. Here we assume that required area lays in a single frag. */ OSSTATUS UDFMarkNotAllocatedAsAllocated( IN PVCB Vcb, IN int64 Offset, IN uint32 Length, IN PEXTENT_INFO ExtInfo // Extent array ) { uint32 i, len, /*lba,*/ d, l, BOffs, j; PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array PEXTENT_MAP NewExtent; // uint32 BS = Vcb->BlockSize; uint32 BSh = Vcb->BlockSizeBits; OSSTATUS status; EXTENT_INFO TmpExtInf; uint32 aLen, sLen; uint32 LBS = Vcb->LBlockSize; // I don't know what else comment can be added here. // Just belive that it works /*lba = */ #ifndef ALLOW_SPARSE BrutePoint(); #endif AdPrint(("Not->Alloc ExtInfo %x, Extent %x\n", ExtInfo, Extent)); UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, &i); if(i == (ULONG)-1) return STATUS_INVALID_PARAMETER; if((Extent[i].extLength >> 30) != EXTENT_NOT_RECORDED_NOT_ALLOCATED) return STATUS_SUCCESS; uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Extent[0].extLocation); BOffs = (uint32)(Offset >> BSh); // length of existing Not-Alloc-Not-Rec frag sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh; // required allocation length increment (in bytes) aLen = (uint32)( ((Offset+Length+LBS-1) & ~(LBS-1)) - (Offset & ~(LBS-1))); // try to extend previous frag or allocate space _after_ it to // avoid backward seeks, if previous frag is not Not-Rec-Not-Alloc if(i && ((Extent[i-1].extLength >> 30) != EXTENT_NOT_RECORDED_NOT_ALLOCATED) ) { status = UDFAllocFreeExtent(Vcb, aLen, Extent[i-1].extLocation + ((Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh), min(UDFPartEnd(Vcb, PartNum), Extent[i-1].extLocation + ((Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) + sLen ), &TmpExtInf, ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/); if(status == STATUS_DISK_FULL) // if there are not enough free blocks after that frag... goto try_alloc_anywhere; } else { try_alloc_anywhere: // ... try to alloc required disk space anywhere status = UDFAllocFreeExtent(Vcb, aLen, UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), &TmpExtInf, ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/); } // check for successfull allocation if(!OS_SUCCESS(status)) { AdPrint(("Not->Alloc no free\n")); return status; } // get number of frags in allocated block d = (UDFGetMappingLength(TmpExtInf.Mapping) / sizeof(EXTENT_MAP)) - 1; // calculate number of existing blocks before the frag to be changed l=0; for(j=0; j> BSh); } // and now just update mapping... if( (l == BOffs) && (((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) == sLen) ) { // xxxxxx -> RRRRRR // (d-1) - since we have to raplace last frag of Extent with 1 or more frags of TmpExtInf.Mapping NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + (d-1)*sizeof(EXTENT_MAP) ); if(!NewExtent) { MyFreePool__(TmpExtInf.Mapping); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); RtlCopyMemory((int8*)&(NewExtent[i]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) ); RtlCopyMemory((int8*)&(NewExtent[i+d]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); AdPrint(("Not->Alloc (1) new %x\n", NewExtent)); } else if(l < BOffs) { // .ExtLength, BOffs & l are already aligned... if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (BOffs-l)) > sLen ) { // xxxxxx -> xxRRxx NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + (d+1)*sizeof(EXTENT_MAP) ); if(!NewExtent) { MyFreePool__(TmpExtInf.Mapping); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); RtlCopyMemory((int8*)&(NewExtent[i+1]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) ); RtlCopyMemory((int8*)&(NewExtent[i+d+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); NewExtent[i].extLocation = 0; NewExtent[i].extLength = (BOffs - l) << BSh; NewExtent[i+d+1].extLength = Extent[i].extLength - NewExtent[i].extLength - aLen; NewExtent[i+d+1].extLocation = 0; NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); NewExtent[i+d+1].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); AdPrint(("Not->Alloc (2) new %x\n", NewExtent)); } else { // xxxxxx -> xxRRRR NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + d*sizeof(EXTENT_MAP) ); if(!NewExtent) { MyFreePool__(TmpExtInf.Mapping); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); RtlCopyMemory((int8*)&(NewExtent[i+1]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) ); RtlCopyMemory((int8*)&(NewExtent[i+d+1]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); NewExtent[i].extLocation = 0; NewExtent[i].extLength = (BOffs - l) << BSh; NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); AdPrint(("Not->Alloc (3) new %x\n", NewExtent)); } } else { // xxxxxx -> RRRRxx NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + d*sizeof(EXTENT_MAP) ); if(!NewExtent) { MyFreePool__(TmpExtInf.Mapping); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); RtlCopyMemory((int8*)&(NewExtent[i]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) ); RtlCopyMemory((int8*)&(NewExtent[i+d+1]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); NewExtent[i+d].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen; NewExtent[i+d].extLocation = 0; NewExtent[i+d].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); AdPrint(("Not->Alloc (4) new %x\n", NewExtent)); } AdPrint(("Free Extent %x, TmpExtInf.Mapping, (new %x)\n", Extent, TmpExtInf.Mapping, NewExtent)); MyFreePool__(Extent); MyFreePool__(TmpExtInf.Mapping); ExtInfo->Modified = TRUE; ExtInfo->Mapping = NewExtent; AdPrint(("Not->Alloc: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping)); return STATUS_SUCCESS; } // end UDFMarkNotAllocatedAsAllocated() //#if 0 /* This routine rebuilds mapping on write zero attempts to Alloc-Not-Rec area. Here we assume that required area lays in a single frag. */ OSSTATUS UDFMarkAllocatedAsNotXXX( IN PVCB Vcb, IN int64 Offset, IN uint32 Length, IN PEXTENT_INFO ExtInfo, // Extent array IN BOOLEAN Deallocate ) { uint32 i, len, /*lba, d,*/ l, BOffs, j; PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array PEXTENT_MAP NewExtent; // EXTENT_MAP TmpExtent; // uint32 BS = Vcb->BlockSize; uint32 BSh = Vcb->BlockSizeBits; // OSSTATUS status; EXTENT_INFO TmpExtInf; uint32 aLen, sLen; uint32 flags; uint32 target_flags = Deallocate ? EXTENT_NOT_RECORDED_NOT_ALLOCATED : EXTENT_NOT_RECORDED_ALLOCATED; uint32 LBS = Vcb->LBlockSize; EXTENT_MAP DeadMapping[2]; // I don't know what else comment can be added here. // Just belive that it works /*lba = */ #ifndef ALLOW_SPARSE if(Deallocate) { BrutePoint(); } #endif AdPrint(("Alloc->Not ExtInfo %x, Extent %x\n", ExtInfo, Extent)); DeadMapping[0].extLocation = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, &i); if(i == (ULONG)-1) { BrutePoint(); return STATUS_INVALID_PARAMETER; } DeadMapping[0].extLength = Extent[i].extLength; DeadMapping[1].extLocation = DeadMapping[1].extLength = 0; TmpExtInf.Mapping = (PEXTENT_MAP)&DeadMapping; TmpExtInf.Offset = 0; TmpExtInf.Length = Extent[i].extLength & UDF_EXTENT_LENGTH_MASK; flags = Extent[i].extLength >> 30; if(flags == target_flags) return STATUS_SUCCESS; // uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Extent[0].extLocation); BOffs = (uint32)(Offset >> BSh); // length of existing Alloc-(Not-)Rec frag (in sectors) sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh; // required deallocation length increment (in bytes) aLen = (uint32)( ((Offset+Length+LBS-1) & ~(LBS-1)) - (Offset & ~(LBS-1)) ); l=0; for(j=0; j> BSh); } flags <<= 30; if( (l == BOffs) && (((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) == sLen) ) { // xxxxxx -> RRRRRR Extent[i].extLocation = 0; Extent[i].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) | flags; NewExtent = Extent; AdPrint(("Alloc->Not (1) NewExtent = Extent = %x\n", NewExtent)); } else if(l < BOffs) { // .ExtLength, BOffs & l are already aligned... if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (BOffs-l)) > sLen ) { // xxxxxx -> xxRRxx NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + 2*sizeof(EXTENT_MAP) ); if(!NewExtent) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); RtlCopyMemory((int8*)&(NewExtent[i+3]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); NewExtent[i].extLength = (BOffs - l) << BSh; NewExtent[i].extLength |= flags; NewExtent[i+1].extLocation = 0; NewExtent[i+1].extLength = aLen | (target_flags << 30); NewExtent[i+2].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - (NewExtent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen ; NewExtent[i+2].extLocation = Extent[i].extLocation + (NewExtent[i+2].extLength >> BSh); NewExtent[i+2].extLength |= flags; AdPrint(("Alloc->Not (2) new %x\n", NewExtent)); } else { // xxxxxx -> xxRRRR NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) ); if(!NewExtent) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); NewExtent[i].extLength = ((BOffs - l) << BSh) | flags; NewExtent[i+1].extLocation = 0; NewExtent[i+1].extLength = aLen | (target_flags << 30); AdPrint(("Alloc->Not (3) new %x\n", NewExtent)); } } else { // xxxxxx -> RRRRxx NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) ); if(!NewExtent) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); NewExtent[i+1].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen; NewExtent[i+1].extLength |= flags; NewExtent[i].extLocation = 0; NewExtent[i].extLength = aLen | (target_flags << 30); AdPrint(("Alloc->Not (4) new %x\n", NewExtent)); } if(Deallocate) UDFMarkSpaceAsXXX(Vcb, (-1), TmpExtInf.Mapping, AS_DISCARDED); // mark as free if(Extent) { AdPrint(("Alloc->Not kill %x\n", Extent)); MyFreePool__(Extent); } else { AdPrint(("Alloc->Not keep %x\n", Extent)); } ExtInfo->Modified = TRUE; ExtInfo->Mapping = NewExtent; AdPrint(("Alloc->Not: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping)); return STATUS_SUCCESS; } // end UDFMarkAllocatedAsNotXXX() //#endif //0 /* This routine resizes extent & updates associated mapping */ OSSTATUS UDFResizeExtent( IN PVCB Vcb, IN uint32 PartNum, IN int64 Length, // Required Length IN BOOLEAN AlwaysInIcb, // must be TRUE for AllocDescs OUT PEXTENT_INFO ExtInfo ) { uint32 i, flags, lba, lim; int64 l; OSSTATUS status; EXTENT_INFO TmpExtInf; EXTENT_MAP TmpMapping[2]; uint32 s, req_s, pe, BSh, LBS, PS; LBS = Vcb->LBlockSize; BSh = Vcb->BlockSizeBits; PS = Vcb->WriteBlockSize >> Vcb->BlockSizeBits; uint32 MaxGrow = (UDF_MAX_EXTENT_LENGTH & ~(LBS-1)); BOOLEAN Sequential = FALSE; ASSERT(PartNum < 3); ExtPrint(("Resize ExtInfo %x, %I64x -> %I64x\n", ExtInfo, ExtInfo->Length, Length)); if(ExtInfo->Flags & EXTENT_FLAG_CUT_PREALLOCATED) { AdPrint((" cut preallocated\n")); } else if(ExtInfo->Length == Length) { return STATUS_SUCCESS; } if((ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) { MaxGrow &= ~(Vcb->WriteBlockSize-1); Sequential = TRUE; } UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used if(ExtInfo->Offset) { if(ExtInfo->Offset + Length <= LBS) { ExtPrint(("Resize IN-ICB\n")); ExtInfo->Length = Length; return STATUS_SUCCESS; } if(!AlwaysInIcb) // simulate unused 1st sector in extent ExtInfo->Offset = LBS; // it'll be truncated later Length += ExtInfo->Offset; // convert to real offset in extent } lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length, NULL, NULL, &flags, &i); if(ExtInfo->Length < Length) { // increase extent if(OS_SUCCESS(UDFGetCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation, &TmpExtInf, NULL, UDF_PREALLOC_CLASS_DIR))) { AdPrint(("Resize found cached(1)\n")); ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping); MyFreePool__(TmpExtInf.Mapping); } if((l = UDFGetExtentLength(ExtInfo->Mapping)) >= Length) { // we have enough space inside extent ExtInfo->Length = Length; AdPrint(("Resize do nothing (1)\n")); } else /*if(lba == LBA_OUT_OF_EXTENT)*/ { Length -= ExtInfo->Offset; if(/*Length && l &&*/ (l % MaxGrow) && (Length-1)/MaxGrow != (l-1)/MaxGrow) { AdPrint(("Crossing MAX_FRAG boundary...\n")); int64 l2 = ((l-1)/MaxGrow + 1)*MaxGrow; status = UDFResizeExtent(Vcb, PartNum, l2, AlwaysInIcb, ExtInfo); if(!OS_SUCCESS(status)) { UDFPrint(("Sub-call to UDFResizeExtent() failed (%x)\n", status)); return status; } l = ExtInfo->Length; ASSERT(l == l2); } while((Length - l) > MaxGrow) { status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo); if(!OS_SUCCESS(status)) { UDFPrint(("Sub-call (2) to UDFResizeExtent() failed (%x)\n", status)); return status; } l = ExtInfo->Length; } Length += ExtInfo->Offset; // at first, try to resize existing frag #ifndef UDF_ALLOW_FRAG_AD i = UDFGetMappingLength(ExtInfo->Mapping); if(i > (LBS-sizeof(EXTENDED_FILE_ENTRY))) { // this is very important check since we will not // be able to _record_ too long AllocDesc because of // some DEMO limitations in UDFBuildXXXAllocDescs() AdPrint((" DISK_FULL\n")); return STATUS_DISK_FULL; } i /= sizeof(EXTENT_MAP); #else //UDF_ALLOW_FRAG_AD i = UDFGetMappingLength(ExtInfo->Mapping) / sizeof(EXTENT_MAP); #endif //UDF_ALLOW_FRAG_AD #ifdef ALLOW_SPARSE if(!AlwaysInIcb && !(ExtInfo->Offset) && (Length - l >= (Vcb->SparseThreshold << BSh))) { // last frag will be Not-Alloc-Not-Rec... AdPrint(("Resize sparse (2)\n")); RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO)); TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , sizeof(EXTENT_MAP)*2, MEM_EXTMAP_TAG); if(!TmpExtInf.Mapping) return STATUS_INSUFFICIENT_RESOURCES; TmpExtInf.Mapping[0].extLength = (((uint32)(Length - l) + LBS-1) & ~(LBS-1)) | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); TmpExtInf.Mapping[0].extLocation =// 0; TmpExtInf.Mapping[1].extLength = TmpExtInf.Mapping[1].extLocation = 0; l = Length; ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping); MyFreePool__(TmpExtInf.Mapping); } else #endif //ALLOW_SPARSE // allocate some sectors if(i>1 && !(ExtInfo->Offset)) { i-=2; // check if Not-Alloc-Not-Rec at the end of mapping if((uint32)Length - (uint32)l + (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) > MaxGrow) { // do nothing, but jump directly to allocator } else if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) { AdPrint(("Resize grow sparse (3)\n")); ExtInfo->Mapping[i].extLength += (((uint32)Length-(uint32)l+LBS-1) & ~(LBS-1)) ; l = Length; // check if Alloc-Not-Rec at the end of mapping } else if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) { AdPrint(("Resize grow Not-Rec (3)\n")); // current length of last frag s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh); // prefered location of the next frag lba = ExtInfo->Mapping[i].extLocation + s; pe=UDFPartEnd(Vcb,PartNum); // maximum frag length if(Sequential) { lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1); } else { lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1); } // required last extent length req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) - ((l + LBS - 1) & ~(LBS-1)) ) >> BSh); if(lim > req_s) { lim = req_s; } UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); /* if((ExtInfo->Flags & EXTENT_FLAG_SEQUENTIAL) && ((Length & ~(PS-1)) > (l & ~(PS-1))) && TRUE) { status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo); }*/ // how many sectors we should add req_s = lim - s; ASSERT(req_s); if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) { s += UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1)); } /* for(s1=lba; (sFSBM_Bitmap, s1); s1++) { s++; }*/ if(s==lim) { // we can just increase the last frag AdPrint(("Resize grow last Not-Rec (4)\n")); ExtInfo->Mapping[i].extLength = (lim << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30); l = Length; UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used } else { // we get here if simple increasing of last frag failed // it worth truncating last frag and try to allocate // all required data as a single frag /* if(Sequential && s>=PS) { s &= ~(PS-1); AdPrint(("Resize grow last Not-Rec (4/2)\n")); ExtInfo->Mapping[i].extLength = (s << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30); l += (s << BSh); UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used }*/ AdPrint(("Resize reloc last Not-Rec (5)\n")); TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (i+1)*sizeof(EXTENT_MAP), MEM_EXTMAP_TAG); if(!TmpExtInf.Mapping) { UDFPrint(("UDFResizeExtent: !TmpExtInf.Mapping\n")); UDFReleaseResource(&(Vcb->BitMapResource1)); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory(TmpExtInf.Mapping, ExtInfo->Mapping, i*sizeof(EXTENT_MAP)); TmpExtInf.Mapping[i].extLength = TmpExtInf.Mapping[i].extLocation = 0; TmpExtInf.Offset = ExtInfo->Offset; l -= (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); TmpExtInf.Length = l; ASSERT(i || !ExtInfo->Offset); UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free MyFreePool__(ExtInfo->Mapping); (*ExtInfo) = TmpExtInf; } UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used UDFReleaseResource(&(Vcb->BitMapResource1)); // check if Alloc-Rec } else { // current length of last frag s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh); // prefered location of the next frag lba = ExtInfo->Mapping[i].extLocation + s; pe=UDFPartEnd(Vcb,PartNum); // maximum frag length if(Sequential) { lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1); } else { lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1); } // required last extent length req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) - ((l + LBS - 1) & ~(LBS-1)) ) >> BSh); if(lim > req_s) { lim = req_s; } // s=0; // how many sectors we should add req_s = lim - s; if(req_s) { uint32 d=0; UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); //ASSERT(req_s); if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) { s += (d = UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1))); } /* for(s1=lba; (sFSBM_Bitmap, s1); s1++) { s++; }*/ if(s==lim) { AdPrint(("Resize grow last Rec (6)\n")); // we can just increase last frag TmpMapping[0].extLength = req_s << BSh; TmpMapping[0].extLocation = lba; TmpMapping[1].extLength = TmpMapping[1].extLocation = 0; UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh); } else if(d) { AdPrint(("Resize part-grow last Rec (6)\n")); // increase last frag, then alloc rest TmpMapping[0].extLength = d << BSh; TmpMapping[0].extLocation = lba; TmpMapping[1].extLength = TmpMapping[1].extLocation = 0; UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh); } else { AdPrint(("Can't grow last Rec (6)\n")); } UDFReleaseResource(&(Vcb->BitMapResource1)); } else { AdPrint(("Max frag length reached (6)\n")); } } } if(l < Length) { // we get here if simple increasing of the last frag failed AdPrint(("Resize add new frag (7)\n")); if(l < LBS && Length >= LBS && (ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) { AdPrint(("Resize tune for SEQUENTIAL i/o\n")); } status = UDFAllocFreeExtent(Vcb, Length - l, UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), &TmpExtInf, ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/); if(!OS_SUCCESS(status)) { UDFPrint(("UDFResizeExtent: UDFAllocFreeExtent() failed (%x)\n", status)); return status; } ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping); MyFreePool__(TmpExtInf.Mapping); } UDFPackMapping(Vcb, ExtInfo); } } else if(Length) { // decrease extent AdPrint(("Resize cut (8)\n")); lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length-1, NULL, &lim, &flags, &i); i++; ASSERT(lba != LBA_OUT_OF_EXTENT); ASSERT(lba != LBA_NOT_ALLOCATED); ASSERT(i); if(ExtInfo->Mapping[i].extLength) { UDFCheckSpaceAllocation(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // check if used if(!ExtInfo->Offset && (ExtInfo->Flags & EXTENT_FLAG_PREALLOCATED)) { AdPrint(("Resize try save cutted (8)\n")); RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO)); s = UDFGetMappingLength(&(ExtInfo->Mapping[i])); TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , s, MEM_EXTMAP_TAG); if(TmpExtInf.Mapping) { RtlCopyMemory(TmpExtInf.Mapping, &(ExtInfo->Mapping[i]), s); AdPrint(("Resize save cutted (8)\n")); if(OS_SUCCESS(UDFStoreCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation, &TmpExtInf, 0, UDF_PREALLOC_CLASS_DIR))) { ExtInfo->Mapping[i].extLength = 0; ExtInfo->Mapping[i].extLocation = 0; goto tail_cached; } } } UDFMarkSpaceAsXXX(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free tail_cached:; } if((lim-1 >= LBS) && (flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED)) { AdPrint(("i=%x, lba=%x, len=%x\n",i,lba,lim)); ASSERT(lim); // BrutePoint(); EXTENT_MAP ClrMap[2]; ClrMap[0].extLength = lim & ~(LBS-1); s = (ExtInfo->Mapping[i-1].extLength - ClrMap[0].extLength) & UDF_EXTENT_LENGTH_MASK; ClrMap[0].extLocation = ExtInfo->Mapping[i-1].extLocation + (s >> BSh); ClrMap[1].extLength = ClrMap[1].extLocation = 0; ASSERT((ExtInfo->Mapping[i].extLocation < ClrMap[0].extLocation) || (ExtInfo->Mapping[i].extLocation >= (ClrMap[0].extLocation + (ClrMap[0].extLength >> BSh)))); UDFCheckSpaceAllocation(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_USED); // check if used UDFMarkSpaceAsXXX(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_DISCARDED); // mark as free ExtInfo->Mapping[i-1].extLength = s | (flags << 30); } s = UDFGetMappingLength(ExtInfo->Mapping); if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), (i+1)*sizeof(EXTENT_MAP))) { // This must never happen on truncate !!! AdPrint(("ResizeExtent: MyReallocPool__(8) failed\n")); } ExtInfo->Mapping[i].extLength = ExtInfo->Mapping[i].extLocation = 0; } else { AdPrint(("Resize zero (9)\n")); ASSERT(!ExtInfo->Offset); UDFMarkSpaceAsXXX(Vcb, 0, ExtInfo->Mapping, AS_DISCARDED); // mark as free s = UDFGetMappingLength(ExtInfo->Mapping); if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), 2*sizeof(EXTENT_MAP))) { // This must never happen on truncate !!! AdPrint(("ResizeExtent: MyReallocPool__(9) failed\n")); } ExtInfo->Mapping[0].extLength = LBS | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); ExtInfo->Mapping[0].extLocation = ExtInfo->Mapping[1].extLength = ExtInfo->Mapping[1].extLocation = 0; } if(ExtInfo->Offset) { if(!AlwaysInIcb) { // remove 1st entry pointing to FileEntry s = UDFGetMappingLength(ExtInfo->Mapping); RtlMoveMemory(&(ExtInfo->Mapping[0]), &(ExtInfo->Mapping[1]), s - sizeof(EXTENT_MAP)); if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), s - sizeof(EXTENT_MAP) )) { // This must never happen on truncate !!! AdPrint(("ResizeExtent: MyReallocPool__(10) failed\n")); } Length -= ExtInfo->Offset; ExtInfo->Offset = 0; } else { Length -= ExtInfo->Offset; // back to in-icb } } ExtInfo->Length = Length; UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used for(i=0; (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); i++) { ExtPrint(("Resized Ext: type %x, loc %x, len %x\n", ExtInfo->Mapping[i].extLength >> 30, ExtInfo->Mapping[i].extLocation, ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK)); } return STATUS_SUCCESS; } // end UDFResizeExtent() /* This routine (re)builds AllocDescs data for all allocation modes except in-ICB & resizes associated extent (FileInfo->Dloc->AllocLoc) for already allocated user data extent (FileInfo->Dloc->DataLoc). AllocMode in FileEntry pointed by FileInfo must be already initialized. */ OSSTATUS UDFBuildAllocDescs( IN PVCB Vcb, IN uint32 PartNum, IN OUT PUDF_FILE_INFO FileInfo, OUT int8** AllocData ) { // PEXTENT_MAP InMap; // uint32 i=0; int8* Allocs; uint16 AllocMode; uint32 InitSz; OSSTATUS status; ValidateFileInfo(FileInfo); AdPrint(("BuildAllocDesc\n")); // get space available in the 1st LBlock after FE InitSz = Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen; Allocs = (int8*)MyAllocatePool__(NonPagedPool, InitSz); if(!Allocs) { *AllocData = NULL; AdPrint(("BuildAllocDesc: cant alloc %x bytes for Allocs\n", InitSz)); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(Allocs, InitSz); // InMap = FileInfo->Dloc->DataLoc.Mapping; UDFCheckSpaceAllocation(Vcb, 0, InMap, AS_USED); // check if used // TODO: move data from mapped locations here AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; switch(AllocMode) { case ICB_FLAG_AD_IN_ICB: { MyFreePool__(Allocs); ASSERT(!FileInfo->Dloc->AllocLoc.Mapping); Allocs = NULL; status = STATUS_SUCCESS; break; } case ICB_FLAG_AD_SHORT: { status = UDFBuildShortAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo); break; } case ICB_FLAG_AD_LONG: { status = UDFBuildLongAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo); break; } /* case ICB_FLAG_AD_EXTENDED: { status = UDFBuildExtAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo); break; }*/ default: { MyFreePool__(Allocs); Allocs = NULL; status = STATUS_INVALID_PARAMETER; } } *AllocData = Allocs; UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used return status; } // end UDFBuildAllocDescs() /* This routine discards file's allocation */ void UDFFreeFileAllocation( IN PVCB Vcb, IN PUDF_FILE_INFO DirInfo, IN PUDF_FILE_INFO FileInfo ) { if(FileInfo->Dloc->DataLoc.Offset) { // in-ICB data if(FileInfo->Dloc->DataLoc.Mapping) { ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation == FileInfo->Dloc->DataLoc.Mapping[0].extLocation); UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free FileInfo->Dloc->DataLoc.Mapping[1].extLocation = FileInfo->Dloc->DataLoc.Mapping[1].extLength = 0; FileInfo->Dloc->DataLoc.Mapping[0].extLocation = 0; FileInfo->Dloc->DataLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30; } if(FileInfo->Dloc->AllocLoc.Mapping) { ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation == FileInfo->Dloc->AllocLoc.Mapping[0].extLocation); UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0; FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0; FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30; } UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc)); } else { if(FileInfo->Dloc->AllocLoc.Mapping) { ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation == FileInfo->Dloc->AllocLoc.Mapping[0].extLocation); UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0; FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0; FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30; } UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc)); UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free } FileInfo->Dloc->DataLoc.Modified = FileInfo->Dloc->AllocLoc.Modified = FileInfo->Dloc->FELoc.Modified = FALSE; } // end UDFFreeFileAllocation() #endif //UDF_READ_ONLY_BUILD /* This routine packs physically sequential extents into single one */ void __fastcall UDFPackMapping( IN PVCB Vcb, IN PEXTENT_INFO ExtInfo // Extent array ) { PEXTENT_MAP NewMap, OldMap; uint32 i, j, l; uint32 LastLba, LastType, OldLen; uint32 OldSize, NewSize; #ifdef UDF_DBG int64 check_size; #endif //UDF_DBG AdPrint(("Pack ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); AdPrint((" Length %x\n", ExtInfo->Length)); OldMap = ExtInfo->Mapping; LastLba = OldMap[0].extLocation; OldLen = (OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits; LastType = OldMap[0].extLength >> 30; OldSize = NewSize = UDFGetMappingLength(OldMap); #ifdef UDF_DBG check_size = UDFGetExtentLength(ExtInfo->Mapping); ASSERT(!(check_size & (2048-1))); #endif //UDF_DBG l=OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK; // calculate required length for(i=1; OldMap[i].extLength; i++) { if((LastType == (OldMap[i].extLength >> 30)) && ((OldMap[i].extLocation == LastLba + OldLen) || (!OldMap[i].extLocation && !LastLba && (LastType == EXTENT_NOT_RECORDED_NOT_ALLOCATED))) && (l + (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) <= UDF_MAX_EXTENT_LENGTH)) { // we can pack two blocks in one l += OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK; NewSize -= sizeof(EXTENT_MAP); } else { l = OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK; } LastLba = OldMap[i].extLocation; LastType = OldMap[i].extLength >> 30; OldLen = (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits; } // no changes ? if(OldSize <= (NewSize + PACK_MAPPING_THRESHOLD)) { if(OldSize == NewSize) return; if(NewSize >= PACK_MAPPING_THRESHOLD) return; } AdPrint(("Pack ExtInfo %x, Mapping %x, realloc\n", ExtInfo, ExtInfo->Mapping)); NewMap = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , NewSize, MEM_EXTMAP_TAG); // can't alloc ? if(!NewMap) return; // Ok, lets pack it... j=0; NewMap[0] = OldMap[0]; LastLba = OldMap[0].extLocation; OldLen = (OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits; LastType = OldMap[0].extLength >> 30; for(i=1; OldMap[i].extLength; i++) { ExtPrint(("oShExt: type %x, loc %x, len %x\n", OldMap[i].extLength >> 30, OldMap[i].extLocation, OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK)); if((LastType == (OldMap[i].extLength >> 30)) && ((OldMap[i].extLocation == LastLba + OldLen) || (!OldMap[i].extLocation && !LastLba && (LastType == EXTENT_NOT_RECORDED_NOT_ALLOCATED))) && ((NewMap[j].extLength & UDF_EXTENT_LENGTH_MASK) + (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) <= UDF_MAX_EXTENT_LENGTH)) { NewMap[j].extLength += OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK; } else { j++; NewMap[j] = OldMap[i]; } ExtPrint(("nShExt: type %x, loc %x, len %x\n", NewMap[j].extLength >> 30, NewMap[j].extLocation, NewMap[j].extLength & UDF_EXTENT_LENGTH_MASK)); LastLba = OldMap[i].extLocation; LastType = OldMap[i].extLength >> 30; OldLen = (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits; } // write terminator j++; ASSERT(NewSize == (j+1)*sizeof(EXTENT_MAP)); NewMap[j].extLength = NewMap[j].extLocation = 0; #ifdef UDF_DBG ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping)); ASSERT(check_size == UDFGetExtentLength(NewMap)); #endif AdPrint(("Pack ExtInfo %x, NewMap %x, OldMap %x\n", ExtInfo, NewMap, OldMap)); ExtInfo->Mapping = NewMap; MyFreePool__(OldMap); AdPrint(("Pack ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); AdPrint((" Length %x\n", ExtInfo->Length)); } // end UDFPackMapping() /* This routine expands mapping to 'frag-per-LBlock' state */ OSSTATUS __fastcall UDFUnPackMapping( IN PVCB Vcb, IN PEXTENT_INFO ExtInfo // Extent array ) { PEXTENT_MAP NewMapping; PEXTENT_MAP Mapping = ExtInfo->Mapping; uint32 LBS = Vcb->LBlockSize; uint32 len = (uint32)(UDFGetExtentLength(Mapping) >> Vcb->LBlockSizeBits); uint32 i,j, type, base, d; LONG l; NewMapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (len+1)*sizeof(EXTENT_MAP), MEM_EXTMAP_TAG); if(!NewMapping) return STATUS_INSUFFICIENT_RESOURCES; j=0; d = LBS >> Vcb->BlockSizeBits; for(i=0; (l = (Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK)); i++) { base = Mapping[i].extLocation; type = Mapping[i].extLength & UDF_EXTENT_FLAG_MASK; for(; l>=(LONG)LBS; j++) { NewMapping[j].extLength = LBS | type; NewMapping[j].extLocation = base; base+=d; l-=LBS; } } // record terminator ASSERT(NewMapping); RtlZeroMemory(&(NewMapping[j]), sizeof(EXTENT_MAP)); MyFreePool__(Mapping); ExtInfo->Mapping = NewMapping; return STATUS_SUCCESS; } // end UDFUnPackMapping() /* Relocate a part of extent that starts from relative (inside extent) block number 'ExtBlock' and has length of 'BC' blocks to continuous run which starts at block 'Lba' */ OSSTATUS UDFRelocateExtent( IN PVCB Vcb, IN PEXTENT_INFO ExtInfo, IN uint32 ExtBlock, IN uint32 Lba, IN uint32 BC ) { return STATUS_ACCESS_DENIED; } /* This routine checks if all the data required is in cache. */ BOOLEAN UDFIsExtentCached( IN PVCB Vcb, IN PEXTENT_INFO ExtInfo, // Extent array IN int64 Offset, // offset in extent IN uint32 Length, IN BOOLEAN ForWrite ) { BOOLEAN retstat = FALSE; PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array uint32 to_read, Lba, sect_offs, flags, i; WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE/*FALSE*//*ForWrite*/); if(!ExtInfo || !ExtInfo->Mapping) goto EO_IsCached; if(!Length) { retstat = TRUE; goto EO_IsCached; } // prevent reading out of data space if(Offset > ExtInfo->Length) goto EO_IsCached; if(Offset+Length > ExtInfo->Length) goto EO_IsCached; Offset += ExtInfo->Offset; // used for in-ICB data // read maximal possible part of each frag of extent Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_read, &flags, &i); while(((LONG)Length) > 0) { // EOF check if(Lba == LBA_OUT_OF_EXTENT) goto EO_IsCached; Extent += (i + 1); // check for reading tail to_read = min(to_read, Length); if(flags == EXTENT_RECORDED_ALLOCATED) { retstat = UDFIsDataCached(Vcb, Lba, (to_read+sect_offs+Vcb->BlockSize-1)>>Vcb->BlockSizeBits); if(!retstat) goto EO_IsCached; } else if(ForWrite) { goto EO_IsCached; } Offset += to_read; Length -= to_read; Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &i); } retstat = TRUE; EO_IsCached: if(!retstat) { WCacheEODirect__(&(Vcb->FastCache), Vcb); } return retstat; } // end UDFIsExtentCached() /* This routine reads cached data only. */ /*OSSTATUS UDFReadExtentCached( IN PVCB Vcb, IN PEXTENT_INFO ExtInfo, // Extent array IN int64 Offset, // offset in extent IN uint32 Length, OUT int8* Buffer, OUT uint32* ReadBytes ) { (*ReadBytes) = 0; if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER; PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array uint32 to_read, Lba, sect_offs, flags, _ReadBytes; OSSTATUS status; // prevent reading out of data space if(Offset > ExtInfo->Length) return STATUS_END_OF_FILE; if(Offset+Length > ExtInfo->Length) Length = (uint32)(ExtInfo->Length - Offset); Offset += ExtInfo->Offset; // used for in-ICB data // read maximal possible part of each frag of extent while(((LONG)Length) > 0) { Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_read, &flags, NULL); // EOF check if(Lba == LBA_OUT_OF_EXTENT) return STATUS_END_OF_FILE; // check for reading tail to_read = (to_read < Length) ? to_read : Length; if(flags == EXTENT_RECORDED_ALLOCATED) { status = UDFReadDataCached(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_read, Buffer, &_ReadBytes); (*ReadBytes) += _ReadBytes; } else { RtlZeroMemory(Buffer, to_read); (*ReadBytes) += to_read; status = STATUS_SUCCESS; } if(!OS_SUCCESS(status)) return status; // prepare for reading next frag... Buffer += to_read; Offset += to_read; Length -= to_read; } return STATUS_SUCCESS; } // end UDFReadExtentCached()*/ /* This routine reads data at any offset from specified extent. */ OSSTATUS UDFReadExtent( IN PVCB Vcb, IN PEXTENT_INFO ExtInfo, // Extent array IN int64 Offset, // offset in extent IN uint32 Length, IN BOOLEAN Direct, OUT int8* Buffer, OUT uint32* ReadBytes ) { (*ReadBytes) = 0; if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER; ASSERT((uint32)Buffer > 0x1000); AdPrint(("Read ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array uint32 to_read, Lba, sect_offs, flags, _ReadBytes; OSSTATUS status; // prevent reading out of data space if(Offset > ExtInfo->Length) return STATUS_END_OF_FILE; if(Offset+Length > ExtInfo->Length) Length = (uint32)(ExtInfo->Length - Offset); Offset += ExtInfo->Offset; // used for in-ICB data // read maximal possible part of each frag of extent Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_read, &flags, &_ReadBytes); while(Length) { // EOF check if(Lba == LBA_OUT_OF_EXTENT) return STATUS_END_OF_FILE; Extent += (_ReadBytes + 1); // check for reading tail to_read = min(to_read, Length); if(flags == EXTENT_RECORDED_ALLOCATED) { status = UDFReadData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_read, Direct, Buffer, &_ReadBytes); (*ReadBytes) += _ReadBytes; if(!OS_SUCCESS(status)) return status; } else { RtlZeroMemory(Buffer, to_read); (*ReadBytes) += to_read; } // prepare for reading next frag... Length -= to_read; if(!Length) break; ASSERT(to_read); Buffer += to_read; // Offset += to_read; Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &_ReadBytes); sect_offs = 0; } return STATUS_SUCCESS; } // end UDFReadExtent() /* This routine reads and builds mapping for specified amount of data at any offset from specified extent. Size of output buffer is limited by *_SubExtInfoSz */ OSSTATUS UDFReadExtentLocation( IN PVCB Vcb, IN PEXTENT_INFO ExtInfo, // Extent array IN int64 Offset, // offset in extent to start SubExtent from OUT PEXTENT_MAP* _SubExtInfo, // SubExtent mapping array IN OUT uint32* _SubExtInfoSz, // IN: maximum number of fragments to get // OUT: actually obtained fragments OUT int64* _NextOffset // offset, caller can start from to continue ) { if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER; PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array PEXTENT_MAP SubExtInfo; uint32 to_read, Lba, sect_offs, flags, Skip_MapEntries; int32 SubExtInfoSz = *_SubExtInfoSz; int64 Length; int64 NextOffset; // OSSTATUS status = STATUS_BUFFER_OVERFLOW; (*_SubExtInfo) = NULL; (*_SubExtInfoSz) = 0; NextOffset = Offset; // prevent reading out of data space if(Offset >= ExtInfo->Length) return STATUS_END_OF_FILE; Length = ExtInfo->Length - Offset; Offset += ExtInfo->Offset; // used for in-ICB data // read maximal possible part of each frag of extent SubExtInfo = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , SubExtInfoSz*sizeof(EXTENT_MAP), MEM_EXTMAP_TAG); (*_SubExtInfo) = SubExtInfo; if(!SubExtInfo) return STATUS_INSUFFICIENT_RESOURCES; Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_read, &flags, &Skip_MapEntries); while(Length && SubExtInfoSz) { // EOF check if(Lba == LBA_OUT_OF_EXTENT) { BrutePoint(); return STATUS_END_OF_FILE; } Extent += (Skip_MapEntries + 1); // check for reading tail to_read = (int32)min((int64)to_read, Length); SubExtInfo->extLength = to_read; if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) { SubExtInfo->extLocation = LBA_NOT_ALLOCATED; } else if(flags == EXTENT_NOT_RECORDED_ALLOCATED) { ASSERT(!(Lba & 0x80000000)); SubExtInfo->extLocation = Lba | 0x80000000; } else { SubExtInfo->extLocation = Lba; } (*_SubExtInfoSz)++; SubExtInfoSz--; NextOffset += to_read; // prepare for reading next frag... Length -= to_read; if(!Length) { // status = STATUS_SUCCESS; break; } ASSERT(to_read); Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &Skip_MapEntries); sect_offs = 0; } (*_NextOffset) = NextOffset; return STATUS_SUCCESS; } // end UDFReadExtentLocation() #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4035) // re-enable below #endif uint32 UDFGetZeroLength( IN int8* Buffer, IN uint32 Length ) { uint32 i; Length /= sizeof(uint32); for(i=0; iMapping) return STATUS_INVALID_PARAMETER; PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array uint32 to_write, Lba, sect_offs, flags; OSSTATUS status; uint32 _WrittenBytes; BOOLEAN reread_lba; // BOOLEAN already_prepared = FALSE; // BOOLEAN prepare = !Buffer; AdPrint(("Write ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); Offset += ExtInfo->Offset; // used for in-ICB data // write maximal possible part of each frag of extent while(((LONG)Length) > 0) { UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); // EOF check if(Lba == LBA_OUT_OF_EXTENT) { return STATUS_END_OF_FILE; } /* if((to_write < Length) && !Direct && !prepare && !already_prepared) { // rebuild mapping, allocate space, etc. // to indicate this, set Buffer to NULL AdPrint(("UDFWriteExtent: Prepare\n")); BrutePoint(); _WrittenBytes = 0; status = UDFWriteExtent(Vcb, ExtInfo, Offset, Length, *//*Direct*//*FALSE, NULL, &_WrittenBytes); if(!OS_SUCCESS(status)) { return status; } Extent = ExtInfo->Mapping; Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); already_prepared = TRUE; }*/ if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) { // here we should allocate space for this extent if(!OS_SUCCESS(status = UDFMarkNotAllocatedAsAllocated(Vcb, Offset, to_write, ExtInfo))) return status; Extent = ExtInfo->Mapping; UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); if(Lba == LBA_OUT_OF_EXTENT) { return STATUS_END_OF_FILE; } // we have already re-read Lba reread_lba = FALSE; } else { // we may need to re-read Lba if some changes are // made while converting from Alloc-Not-Rec reread_lba = TRUE; } // check if writing to not recorded allocated // in this case we must pad blocks with zeros around // modified area // // ...|xxxxxxxx|xxxxxxxx|xxxxxxxx|... // . . // . || . // . \/ . // . . // ...|000ddddd|dddddddd|dd000000|... // . . // ^ ^ // sect_offs sect_offs+to_write // . . // .<-- to_write -->. // to_write = min(to_write, Length); if(flags == EXTENT_NOT_RECORDED_ALLOCATED) { if(!OS_SUCCESS(status = UDFMarkAllocatedAsRecorded(Vcb, Offset, to_write, ExtInfo))) return status; Extent = ExtInfo->Mapping; UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used if(reread_lba) { Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); to_write = min(to_write, Length); } /* we must fill 1st block with zeros in 1 of 2 cases: 1) start offset is not aligned on LBlock boundary OR 2) end offset is not aligned on LBlock boundary and lays in the same LBlock we must fill last block with zeros if both 1) end offset is not aligned on LBlock boundary AND 2) end offset DOESN'T lay in the 1st LBlock */ // if(!prepare) { // pad 1st logical block if((sect_offs || (sect_offs + to_write < Vcb->LBlockSize) ) && !Vcb->CDR_Mode) { status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits), Vcb->LBlockSize, Direct, Vcb->ZBuffer, &_WrittenBytes); if(!OS_SUCCESS(status)) return status; } // pad last logical block if((sect_offs + to_write > Vcb->LBlockSize) && (sect_offs + to_write) & (Vcb->LBlockSize - 1)) { status = UDFWriteData(Vcb, TRUE, (( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs + to_write) & ~((int64)(Vcb->LBlockSize)-1), Vcb->LBlockSize, Direct, Vcb->ZBuffer, &_WrittenBytes); } if(!OS_SUCCESS(status)) return status; /* } else { status = STATUS_SUCCESS; }*/ } ASSERT(to_write); // if(!prepare) { status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_write, Direct, Buffer, &_WrittenBytes); *WrittenBytes += _WrittenBytes; if(!OS_SUCCESS(status)) return status; /* } else { status = STATUS_SUCCESS; *WrittenBytes += to_write; }*/ // prepare for writing next frag... Buffer += to_write; Offset += to_write; Length -= to_write; } AdPrint(("Write: ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); return STATUS_SUCCESS; } // end UDFWriteExtent() //#if 0 /* This routine zeroes/deallocates data at any offset to specified extent. */ OSSTATUS UDFZeroExtent( IN PVCB Vcb, IN PEXTENT_INFO ExtInfo, // Extent array IN int64 Offset, // offset in extent IN uint32 Length, IN BOOLEAN Deallocate, // deallocate frag or just mark as unrecorded IN BOOLEAN Direct, // setting this flag delays flushing of given // data to indefinite term OUT uint32* WrittenBytes ) { if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER; PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array uint32 to_write, Lba, sect_offs, flags; OSSTATUS status; uint32 _WrittenBytes; uint32 LBS = Vcb->LBlockSize; AdPrint(("Zero ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); Offset += ExtInfo->Offset; // used for in-ICB data // fill/deallocate maximal possible part of each frag of extent while(((LONG)Length) > 0) { Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); // EOF check if(Lba == LBA_OUT_OF_EXTENT) { return STATUS_END_OF_FILE; } // check for writing tail to_write = min(to_write, Length); if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) { // here we should do nothing *WrittenBytes += to_write; } else if(flags == EXTENT_NOT_RECORDED_ALLOCATED) { // we should just deallocate this frag if(Deallocate) { if(!OS_SUCCESS(status = UDFMarkAllocatedAsNotAllocated(Vcb, Offset, to_write, ExtInfo))) return status; } Extent = ExtInfo->Mapping; *WrittenBytes += to_write; } else { // fill tail of the 1st Block with ZEROs if(sect_offs) { status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, min(to_write, LBS-sect_offs), Direct, Vcb->ZBuffer, &_WrittenBytes); *WrittenBytes += _WrittenBytes; if(!OS_SUCCESS(status)) return status; Offset += _WrittenBytes; Length -= _WrittenBytes; to_write -= _WrittenBytes; Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); ASSERT(flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED); ASSERT(flags != EXTENT_NOT_RECORDED_ALLOCATED); ASSERT(!sect_offs); } // deallocate Blocks if(to_write >= LBS) { // use 'sect_offs' as length of extent to be deallocated sect_offs = to_write & ~(LBS - 1); if(Deallocate) { status = UDFMarkAllocatedAsNotAllocated(Vcb, Offset, sect_offs, ExtInfo); } else { status = UDFMarkRecordedAsAllocated(Vcb, Offset, sect_offs, ExtInfo); } if(!OS_SUCCESS(status)) return status; // reload extent mapping Extent = ExtInfo->Mapping; Offset += sect_offs; Length -= sect_offs; *WrittenBytes += sect_offs; to_write -= sect_offs; Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); ASSERT(flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED); ASSERT(flags != EXTENT_NOT_RECORDED_ALLOCATED); ASSERT(!sect_offs); } // fill beginning of the last Block with ZEROs if(to_write) { status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits), to_write, Direct, Vcb->ZBuffer, &_WrittenBytes); *WrittenBytes += _WrittenBytes; if(!OS_SUCCESS(status)) return status; ASSERT(to_write == _WrittenBytes); } } AdPrint(("Zero... ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); // prepare for filling next frag... Offset += to_write; Length -= to_write; } AdPrint(("Zero: ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); return STATUS_SUCCESS; } // end UDFZeroExtent() //#endif //0 #endif //UDF_READ_ONLY_BUILD