mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
5596 lines
200 KiB
C++
5596 lines
200 KiB
C++
////////////////////////////////////////////////////////////////////
|
|
// 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:
|
|
|
|
udf_info.cpp
|
|
|
|
Abstract:
|
|
|
|
This file contains filesystem-specific routines
|
|
|
|
*/
|
|
|
|
#include "udf.h"
|
|
|
|
#define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO
|
|
|
|
#ifdef _X86_
|
|
static const int8 valid_char_arr[] =
|
|
{1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
|
|
1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
|
|
1,0,1,0, 0,0,0,0, 0,0,1,1, 1,0,0,1,
|
|
0,0,0,0, 0,0,0,0, 0,0,1,1, 1,1,1,1,
|
|
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // @ABCDE....
|
|
0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,0, // ....Z[/]^_
|
|
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // `abcde....
|
|
0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,1, // ....z{|}~
|
|
|
|
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
|
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
|
|
#else // NO X86 optimization , use generic C/C++
|
|
static const char valid_char_arr[] = {"*/:?\"<>|\\"};
|
|
#endif // _X86_
|
|
|
|
#define DOS_CRC_MODULUS 41
|
|
#define hexChar crcChar
|
|
static const char crcChar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#_~-@";
|
|
|
|
/* Used to convert hex digits to ASCII for readability. */
|
|
//static const char hexChar[] = "0123456789ABCDEF";
|
|
|
|
static const uint16 CrcTable[256] = {
|
|
0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U,
|
|
0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU,
|
|
0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U,
|
|
0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU,
|
|
0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U,
|
|
0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU,
|
|
0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U,
|
|
0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU,
|
|
0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U,
|
|
0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU,
|
|
0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U,
|
|
0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU,
|
|
0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U,
|
|
0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U,
|
|
0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U,
|
|
0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U,
|
|
0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU,
|
|
0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U,
|
|
0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU,
|
|
0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U,
|
|
0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU,
|
|
0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U,
|
|
0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU,
|
|
0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U,
|
|
0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU,
|
|
0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U,
|
|
0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU,
|
|
0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U,
|
|
0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U,
|
|
0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U,
|
|
0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U,
|
|
0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U
|
|
};
|
|
|
|
static const uint32 crc32_tab[] = {
|
|
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
|
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
|
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
|
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
|
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
|
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
|
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
|
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
|
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
|
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
|
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
|
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
|
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
|
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
|
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
|
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
|
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
|
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
|
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
|
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
|
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
|
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
|
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
|
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
|
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
|
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
|
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
|
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
|
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
|
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
|
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
|
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
|
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
|
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
|
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
|
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
|
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
|
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
|
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
|
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
|
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
|
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
|
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
|
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
|
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
|
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
|
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
|
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
|
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
|
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
|
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
|
0x2d02ef8dL
|
|
};
|
|
|
|
/*
|
|
This routine allocates new memory block, copies data there & free old one
|
|
*/
|
|
/*uint32
|
|
UDFMemRealloc(
|
|
int8* OldBuff,
|
|
uint32 OldLength,
|
|
int8** NewBuff,
|
|
uint32 NewLength
|
|
)
|
|
{
|
|
int8* new_buff;
|
|
|
|
(*NewBuff) = OldBuff;
|
|
if(OldLength == NewLength) return OldLength;
|
|
new_buff = (int8*)MyAllocatePool__(NonPagedPool, NewLength);
|
|
if(!new_buff) return 0;
|
|
if(OldLength > NewLength) OldLength = NewLength;
|
|
RtlCopyMemory(new_buff, OldBuff, OldLength);
|
|
MyFreePool__(OldBuff);
|
|
(*NewBuff) = new_buff;
|
|
return OldLength;
|
|
} // end UDFMemRealloc()*/
|
|
|
|
/*
|
|
This routine converts compressed Unicode to standard
|
|
*/
|
|
void
|
|
__fastcall
|
|
UDFDecompressUnicode(
|
|
IN OUT PUNICODE_STRING UName,
|
|
IN uint8* CS0,
|
|
IN SIZE_T Length,
|
|
OUT uint16* valueCRC
|
|
)
|
|
{
|
|
uint16 compID = CS0[0];
|
|
uint32 unicodeIndex = 0;
|
|
uint32 byteIndex = 1;
|
|
PWCHAR buff;
|
|
uint8* _CS0 = CS0+1;
|
|
|
|
if(!Length) goto return_empty_str;
|
|
// First check for valid compID.
|
|
switch(compID) {
|
|
case UDF_COMP_ID_8: {
|
|
|
|
buff = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (Length)*sizeof(WCHAR), MEM_FNAME_TAG);
|
|
if(!buff) goto return_empty_str;
|
|
UName->Buffer = buff;
|
|
|
|
// Loop through all the bytes.
|
|
while (byteIndex < Length) {
|
|
(*buff) = (*_CS0);
|
|
_CS0++;
|
|
byteIndex++;
|
|
buff++;
|
|
}
|
|
unicodeIndex = byteIndex-1;
|
|
break;
|
|
}
|
|
case UDF_COMP_ID_16: {
|
|
|
|
buff = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (Length-1)+sizeof(WCHAR), MEM_FNAME16_TAG);
|
|
if(!buff) goto return_empty_str;
|
|
UName->Buffer = buff;
|
|
|
|
// Loop through all the bytes.
|
|
while (byteIndex < Length) {
|
|
// Move the first byte to the high bits of the unicode char.
|
|
*buff = ((*_CS0) << 8) | (*(_CS0+1));
|
|
_CS0+=2;
|
|
byteIndex+=2;
|
|
unicodeIndex++;
|
|
buff++;
|
|
ASSERT(byteIndex <= Length);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
return_empty_str:
|
|
UName->Buffer = NULL;
|
|
UName->MaximumLength =
|
|
UName->Length = 0;
|
|
return;
|
|
}
|
|
}
|
|
UName->MaximumLength = (UName->Length = (((uint16)unicodeIndex)*sizeof(WCHAR))) + sizeof(WCHAR);
|
|
UName->Buffer[unicodeIndex] = 0;
|
|
if(valueCRC) {
|
|
*valueCRC = UDFCrc(CS0+1, Length-1);
|
|
}
|
|
} // end UDFDecompressUnicode()
|
|
|
|
/*
|
|
This routine converts standard Unicode to compressed
|
|
*/
|
|
void
|
|
__fastcall
|
|
UDFCompressUnicode(
|
|
IN PUNICODE_STRING UName,
|
|
IN OUT uint8** _CS0,
|
|
IN OUT PSIZE_T Length
|
|
)
|
|
{
|
|
uint8* CS0;
|
|
uint8 compID;
|
|
uint16 unicodeIndex;
|
|
uint32 i, len;
|
|
PWCHAR Buff;
|
|
|
|
len = (UName->Length) / sizeof(WCHAR);
|
|
compID = (!len) ? 0 : UDF_COMP_ID_8;
|
|
// check for uncompressable characters
|
|
Buff = UName->Buffer;
|
|
for(i=0; i<len; i++, Buff++) {
|
|
if((*Buff) & 0xff00) {
|
|
compID = UDF_COMP_ID_16;
|
|
break;
|
|
}
|
|
}
|
|
|
|
CS0 = (uint8*)MyAllocatePool__(NonPagedPool, *Length = (((compID==UDF_COMP_ID_8) ? 1 : 2)*len + 1) );
|
|
if(!CS0) return;
|
|
|
|
CS0[0] = compID;
|
|
*_CS0 = CS0;
|
|
// init loop
|
|
CS0++;
|
|
unicodeIndex = 0;
|
|
Buff = UName->Buffer;
|
|
if(compID == UDF_COMP_ID_16) {
|
|
// Loop through all the bytes.
|
|
while (unicodeIndex < len) {
|
|
// Move the 2nd byte to the low bits of the compressed unicode char.
|
|
*CS0 = (uint8)((*Buff) >> 8);
|
|
CS0++;
|
|
*CS0 = (uint8)(*Buff);
|
|
CS0++;
|
|
Buff++;
|
|
unicodeIndex++;
|
|
}
|
|
} else {
|
|
// Loop through all the bytes.
|
|
while (unicodeIndex < len) {
|
|
*CS0 = (uint8)(*Buff);
|
|
CS0++;
|
|
Buff++;
|
|
unicodeIndex++;
|
|
}
|
|
}
|
|
} // end UDFCompressUnicode()
|
|
|
|
/*
|
|
OSSTATUS UDFFindFile__(IN PVCB Vcb,
|
|
IN BOOLEAN IgnoreCase,
|
|
IN PUNICODE_STRING Name,
|
|
IN PUDF_FILE_INFO DirInfo)
|
|
see 'Udf_info.h'
|
|
*/
|
|
|
|
/*
|
|
This routine reads (Extended)FileEntry according to FileDesc
|
|
*/
|
|
OSSTATUS
|
|
UDFReadFileEntry(
|
|
IN PVCB Vcb,
|
|
IN long_ad* Icb,
|
|
IN OUT PFILE_ENTRY FileEntry, // here we can also get ExtendedFileEntry
|
|
IN OUT uint16* Ident
|
|
)
|
|
{
|
|
OSSTATUS status;
|
|
|
|
if(!OS_SUCCESS(status = UDFReadTagged(Vcb, (int8*)FileEntry,
|
|
UDFPartLbaToPhys(Vcb,&(Icb->extLocation)),
|
|
Icb->extLocation.logicalBlockNum,
|
|
Ident))) return status;
|
|
if((FileEntry->descTag.tagIdent != TID_FILE_ENTRY) &&
|
|
(FileEntry->descTag.tagIdent != TID_EXTENDED_FILE_ENTRY)) {
|
|
UDFPrint((" Not a FileEntry (lbn=%x, tag=%x)\n", Icb->extLocation.logicalBlockNum, FileEntry->descTag.tagIdent));
|
|
return STATUS_FILE_CORRUPT_ERROR;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
} // UDFReadFileEntry()
|
|
|
|
#if !defined (_X86_) || !defined (_MSC_VER)
|
|
/*
|
|
Decides if a Unicode character matches one of a list
|
|
of ASCII characters.
|
|
Used by DOS version of UDFIsIllegalChar for readability, since all of the
|
|
illegal characters above 0x0020 are in the ASCII subset of Unicode.
|
|
Works very similarly to the standard C function strchr().
|
|
*/
|
|
BOOLEAN
|
|
UDFUnicodeInString(
|
|
IN uint8* string, // String to search through.
|
|
IN WCHAR ch // Unicode char to search for.
|
|
)
|
|
{
|
|
BOOLEAN found = FALSE;
|
|
|
|
while(*string != '\0' && !found) {
|
|
// These types should compare, since both are unsigned numbers.
|
|
if(*string == ch) {
|
|
found = TRUE;
|
|
}
|
|
string++;
|
|
}
|
|
return(found);
|
|
} // end UDFUnicodeInString()
|
|
#endif // _X86_
|
|
|
|
/*
|
|
Decides whether character passed is an illegal character for a
|
|
DOS file name.
|
|
*/
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4035) // re-enable below
|
|
#endif
|
|
|
|
#ifdef _X86_
|
|
#ifdef _MSC_VER
|
|
__declspec (naked)
|
|
#endif
|
|
#endif // _X86_
|
|
BOOLEAN
|
|
__fastcall
|
|
UDFIsIllegalChar(
|
|
IN WCHAR chr // ECX
|
|
)
|
|
{
|
|
// Genuine illegal char's for DOS.
|
|
#if defined (_X86_) && defined (_MSC_VER)
|
|
_asm {
|
|
push ebx
|
|
|
|
xor eax,eax
|
|
// mov ax,chr
|
|
mov ax,cx
|
|
or ah,ah
|
|
jnz ERR_IIC
|
|
|
|
lea ebx,[valid_char_arr]
|
|
xlatb
|
|
jmp short ERR_IIC2
|
|
ERR_IIC:
|
|
mov al,1
|
|
ERR_IIC2:
|
|
|
|
pop ebx
|
|
ret
|
|
}
|
|
|
|
#else // NO X86 optimization , use generic C/C++
|
|
/* FIXME */
|
|
//return ((ch < 0x20) || UDFUnicodeInString((uint8*)&valid_char_arr, ch));
|
|
return ((chr < 0x20) || UDFUnicodeInString((uint8*)&valid_char_arr, chr));
|
|
#endif // _X86_
|
|
} // end UDFIsIllegalChar()
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop) // re-enable warning #4035
|
|
#endif
|
|
|
|
/*
|
|
Translate udfName to dosName using OSTA compliant.
|
|
dosName must be a unicode string with min length of 12.
|
|
*/
|
|
|
|
/*void UDFDOSName__(
|
|
IN PVCB Vcb,
|
|
IN OUT PUNICODE_STRING DosName,
|
|
IN PUNICODE_STRING UdfName,
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
BOOLEAN KeepIntact;
|
|
|
|
KeepIntact = (FileInfo && (FileInfo->Index < 2));
|
|
UDFDOSName(Vcb, DosName, UdfName, KeepIntact);
|
|
}*/
|
|
|
|
void
|
|
__fastcall
|
|
UDFDOSName(
|
|
IN PVCB Vcb,
|
|
IN OUT PUNICODE_STRING DosName,
|
|
IN PUNICODE_STRING UdfName,
|
|
IN BOOLEAN KeepIntact
|
|
)
|
|
{
|
|
#ifndef _CONSOLE
|
|
if(Vcb->CompatFlags & UDF_VCB_IC_OS_NATIVE_DOS_NAME) {
|
|
UDFDOSNameOsNative(DosName, UdfName, KeepIntact);
|
|
return;
|
|
}
|
|
#endif //_CONSOLE
|
|
|
|
switch(Vcb->CurrentUDFRev) {
|
|
case 0x0100:
|
|
case 0x0101:
|
|
case 0x0102:
|
|
UDFDOSName100(DosName, UdfName, KeepIntact);
|
|
break;
|
|
|
|
case 0x0150:
|
|
// in general, we need bytes-from-media to
|
|
// create valid UDF 1.50 name.
|
|
// Curently it is impossible, thus, we'll use
|
|
// UDF 2.00 translation algorithm
|
|
case 0x0200:
|
|
UDFDOSName200(DosName, UdfName, KeepIntact, Vcb->CurrentUDFRev == 0x0150);
|
|
break;
|
|
|
|
case 0x0201:
|
|
default:
|
|
UDFDOSName201(DosName, UdfName, KeepIntact);
|
|
}
|
|
}
|
|
|
|
void
|
|
__fastcall
|
|
UDFDOSName100(
|
|
IN OUT PUNICODE_STRING DosName,
|
|
IN PUNICODE_STRING UdfName,
|
|
IN BOOLEAN KeepIntact
|
|
)
|
|
{
|
|
PWCHAR dosName = DosName->Buffer;
|
|
PWCHAR udfName = UdfName->Buffer;
|
|
uint32 udfLen = UdfName->Length / sizeof(WCHAR);
|
|
|
|
uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex;
|
|
BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE;
|
|
uint32 valueCRC;
|
|
WCHAR ext[DOS_EXT_LEN], current;
|
|
|
|
if(KeepIntact &&
|
|
(udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
|
|
isParent = TRUE;
|
|
if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD))
|
|
isParent = FALSE;
|
|
}
|
|
|
|
for (index = 0 ; index < udfLen ; index++) {
|
|
current = udfName[index];
|
|
if (current == UNICODE_PERIOD && !isParent) {
|
|
if (dosIndex==0 || hasExt) {
|
|
// Ignore leading periods or any other than used for extension.
|
|
needsCRC = TRUE;
|
|
} else {
|
|
// First, find last character which is NOT a period or space.
|
|
lastPeriodIndex = udfLen - 1;
|
|
while(lastPeriodIndex >=0 &&
|
|
(udfName[lastPeriodIndex] == UNICODE_PERIOD ||
|
|
udfName[lastPeriodIndex] == UNICODE_SPACE))
|
|
lastPeriodIndex--;
|
|
// Now search for last remaining period.
|
|
while(lastPeriodIndex >= 0 &&
|
|
udfName[lastPeriodIndex] != UNICODE_PERIOD)
|
|
lastPeriodIndex--;
|
|
// See if the period we found was the last or not.
|
|
if (lastPeriodIndex != index)
|
|
needsCRC = TRUE; // If not, name needs translation.
|
|
// As long as the period was not trailing,
|
|
// the file name has an extension.
|
|
if (lastPeriodIndex >= 0) hasExt = TRUE;
|
|
}
|
|
} else {
|
|
if ((!hasExt && dosIndex == DOS_NAME_LEN) ||
|
|
extIndex == DOS_EXT_LEN) {
|
|
// File name or extension is too long for DOS.
|
|
needsCRC = TRUE;
|
|
} else {
|
|
if (current == UNICODE_SPACE) { // Ignore spaces.
|
|
needsCRC = TRUE;
|
|
} else {
|
|
// Look for illegal or unprintable characters.
|
|
if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) {
|
|
needsCRC = TRUE;
|
|
current = ILLEGAL_CHAR_MARK;
|
|
/* Skip Illegal characters(even spaces),
|
|
* but not periods.
|
|
*/
|
|
while(index+1 < udfLen &&
|
|
(UDFIsIllegalChar(udfName[index+1]) /*||
|
|
!UnicodeIsPrint(udfName[index+1])*/) &&
|
|
udfName[index+1] != UNICODE_PERIOD)
|
|
index++;
|
|
}
|
|
// Add current char to either file name or ext.
|
|
if (writingExt) {
|
|
ext[extIndex] = current;
|
|
extIndex++;
|
|
} else {
|
|
dosName[dosIndex] = current;
|
|
dosIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// See if we are done with file name, either because we reached
|
|
// the end of the file name length, or the final period.
|
|
if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN ||
|
|
index == lastPeriodIndex)) {
|
|
// If so, and the name has an extension, start reading it.
|
|
writingExt = TRUE;
|
|
// Extension starts after last period.
|
|
index = lastPeriodIndex;
|
|
}
|
|
}
|
|
//
|
|
if (needsCRC) {
|
|
// Add CRC to end of file name or at position 4.
|
|
if (dosIndex >4) dosIndex = 4;
|
|
valueCRC = UDFUnicodeCksum(udfName, udfLen);
|
|
// set CRC prefix
|
|
dosName[dosIndex] = UNICODE_CRC_MARK;
|
|
// Convert 12-bit CRC to hex characters.
|
|
dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8];
|
|
dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4];
|
|
dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)];
|
|
dosIndex+=4;
|
|
}
|
|
// Add extension, if any.
|
|
if (extIndex != 0) {
|
|
dosName[dosIndex] = UNICODE_PERIOD;
|
|
dosIndex++;
|
|
for (index = 0; index < extIndex; index++) {
|
|
dosName[dosIndex] = ext[index];
|
|
dosIndex++;
|
|
}
|
|
}
|
|
DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
|
|
RtlUpcaseUnicodeString(DosName, DosName, FALSE);
|
|
} // end UDFDOSName100()
|
|
|
|
void
|
|
__fastcall
|
|
UDFDOSName200(
|
|
IN OUT PUNICODE_STRING DosName,
|
|
IN PUNICODE_STRING UdfName,
|
|
IN BOOLEAN KeepIntact,
|
|
IN BOOLEAN Mode150
|
|
)
|
|
{
|
|
PWCHAR dosName = DosName->Buffer;
|
|
PWCHAR udfName = UdfName->Buffer;
|
|
uint32 udfLen = UdfName->Length / sizeof(WCHAR);
|
|
|
|
uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex;
|
|
BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE;
|
|
uint32 valueCRC;
|
|
WCHAR ext[DOS_EXT_LEN], current;
|
|
|
|
if(KeepIntact &&
|
|
(udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
|
|
isParent = TRUE;
|
|
if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD))
|
|
isParent = FALSE;
|
|
}
|
|
|
|
for (index = 0 ; index < udfLen ; index++) {
|
|
current = udfName[index];
|
|
if (current == UNICODE_PERIOD && !isParent) {
|
|
if (dosIndex==0 || hasExt) {
|
|
// Ignore leading periods or any other than used for extension.
|
|
needsCRC = TRUE;
|
|
} else {
|
|
// First, find last character which is NOT a period or space.
|
|
lastPeriodIndex = udfLen - 1;
|
|
while(lastPeriodIndex >=0 &&
|
|
(udfName[lastPeriodIndex] == UNICODE_PERIOD ||
|
|
udfName[lastPeriodIndex] == UNICODE_SPACE))
|
|
lastPeriodIndex--;
|
|
// Now search for last remaining period.
|
|
while(lastPeriodIndex >= 0 &&
|
|
udfName[lastPeriodIndex] != UNICODE_PERIOD)
|
|
lastPeriodIndex--;
|
|
// See if the period we found was the last or not.
|
|
if (lastPeriodIndex != index)
|
|
needsCRC = TRUE; // If not, name needs translation.
|
|
// As long as the period was not trailing,
|
|
// the file name has an extension.
|
|
if (lastPeriodIndex >= 0) hasExt = TRUE;
|
|
}
|
|
} else {
|
|
if ((!hasExt && dosIndex == DOS_NAME_LEN) ||
|
|
extIndex == DOS_EXT_LEN) {
|
|
// File name or extension is too long for DOS.
|
|
needsCRC = TRUE;
|
|
} else {
|
|
if (current == UNICODE_SPACE) { // Ignore spaces.
|
|
needsCRC = TRUE;
|
|
} else {
|
|
// Look for illegal or unprintable characters.
|
|
if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) {
|
|
needsCRC = TRUE;
|
|
current = ILLEGAL_CHAR_MARK;
|
|
/* Skip Illegal characters(even spaces),
|
|
* but not periods.
|
|
*/
|
|
while(index+1 < udfLen &&
|
|
(UDFIsIllegalChar(udfName[index+1]) /*||
|
|
!UnicodeIsPrint(udfName[index+1])*/) &&
|
|
udfName[index+1] != UNICODE_PERIOD)
|
|
index++;
|
|
}
|
|
// Add current char to either file name or ext.
|
|
if (writingExt) {
|
|
ext[extIndex] = current;
|
|
extIndex++;
|
|
} else {
|
|
dosName[dosIndex] = current;
|
|
dosIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// See if we are done with file name, either because we reached
|
|
// the end of the file name length, or the final period.
|
|
if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN ||
|
|
index == lastPeriodIndex)) {
|
|
// If so, and the name has an extension, start reading it.
|
|
writingExt = TRUE;
|
|
// Extension starts after last period.
|
|
index = lastPeriodIndex;
|
|
}
|
|
}
|
|
// Now handle CRC if needed.
|
|
if (needsCRC) {
|
|
// Add CRC to end of file name or at position 4.
|
|
if (dosIndex >4) dosIndex = 4;
|
|
valueCRC = Mode150 ? UDFUnicodeCksum150(udfName, udfLen) : UDFUnicodeCksum(udfName, udfLen);
|
|
// Convert 16-bit CRC to hex characters.
|
|
dosName[dosIndex] = hexChar[(valueCRC & 0xf000) >> 12];
|
|
dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8];
|
|
dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4];
|
|
dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)];
|
|
dosIndex+=4;
|
|
}
|
|
// Add extension, if any.
|
|
if (extIndex != 0) {
|
|
dosName[dosIndex] = UNICODE_PERIOD;
|
|
dosIndex++;
|
|
for (index = 0; index < extIndex; index++) {
|
|
dosName[dosIndex] = ext[index];
|
|
dosIndex++;
|
|
}
|
|
}
|
|
DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
|
|
RtlUpcaseUnicodeString(DosName, DosName, FALSE);
|
|
} // end UDFDOSName200()
|
|
|
|
|
|
void
|
|
__fastcall
|
|
UDFDOSName201(
|
|
IN OUT PUNICODE_STRING DosName,
|
|
IN PUNICODE_STRING UdfName,
|
|
IN BOOLEAN KeepIntact
|
|
)
|
|
{
|
|
PWCHAR dosName = DosName->Buffer;
|
|
PWCHAR udfName = UdfName->Buffer;
|
|
uint16 udfLen = UdfName->Length / sizeof(WCHAR);
|
|
|
|
uint16 index, dosIndex = 0;
|
|
//uint16 extIndex = 0;
|
|
BOOLEAN needsCRC = FALSE, isParent = FALSE;
|
|
//BOOLEAN hasExt = FALSE, writingExt = FALSE;
|
|
uint16 valueCRC;
|
|
WCHAR ext[DOS_EXT_LEN];
|
|
WCHAR current;
|
|
|
|
if(KeepIntact &&
|
|
(udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
|
|
isParent = TRUE;
|
|
if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD))
|
|
isParent = FALSE;
|
|
}
|
|
|
|
#define DOS_CRC_LEN 4
|
|
#define DOS_CRC_MODULUS 41
|
|
|
|
int16 crcIndex;
|
|
uint16 extLen;
|
|
uint16 nameLen;
|
|
uint16 charLen;
|
|
int16 overlayBytes;
|
|
int16 bytesLeft;
|
|
|
|
/* Start at the end of the UDF file name and scan for a period */
|
|
/* ('.'). This will be where the DOS extension starts (if */
|
|
/* any). */
|
|
index = udfLen;
|
|
while (index-- > 0) {
|
|
if (udfName[index] == '.')
|
|
break;
|
|
}
|
|
if ((index < 0) || isParent) {
|
|
/* There name was scanned to the beginning of the buffer */
|
|
/* and no extension was found. */
|
|
extLen = 0;
|
|
nameLen = udfLen;
|
|
} else {
|
|
/* A DOS extension was found, process it first. */
|
|
extLen = udfLen - index - 1;
|
|
nameLen = index;
|
|
dosIndex = 0;
|
|
bytesLeft = DOS_EXT_LEN;
|
|
while (++index < udfLen && bytesLeft > 0) {
|
|
/* Get the current character and convert it to upper */
|
|
/* case. */
|
|
current = udfName[index];
|
|
if (current == ' ') {
|
|
/* If a space is found, a CRC must be appended to */
|
|
/* the mangled file name. */
|
|
needsCRC = TRUE;
|
|
} else {
|
|
/* Determine if this is a valid file name char and */
|
|
/* calculate its corresponding BCS character byte */
|
|
/* length (zero if the char is not legal or */
|
|
/* undisplayable on this system). */
|
|
|
|
charLen = (UDFIsIllegalChar(current)
|
|
/*|| !UnicodeIsPrint(current)*/) ? 0 : 1;
|
|
|
|
/* If the char is larger than the available space */
|
|
/* in the buffer, pretend it is undisplayable. */
|
|
if (charLen > bytesLeft)
|
|
charLen = 0;
|
|
if (charLen == 0) {
|
|
/* Undisplayable or illegal characters are */
|
|
/* substituted with an underscore ("_"), and */
|
|
/* required a CRC code appended to the mangled */
|
|
/* file name. */
|
|
needsCRC = TRUE;
|
|
charLen = 1;
|
|
current = '_';
|
|
/* Skip over any following undiplayable or */
|
|
/* illegal chars. */
|
|
while (index +1 <udfLen &&
|
|
(UDFIsIllegalChar(udfName[index+1])
|
|
/*|| !UnicodeIsPrint(udfName[index+1])*/))
|
|
index++;
|
|
}
|
|
/* Assign the resulting char to the next index in */
|
|
/* the extension buffer and determine how many BCS */
|
|
/* bytes are left. */
|
|
ext[dosIndex++] = current;
|
|
bytesLeft -= charLen;
|
|
}
|
|
}
|
|
/* Save the number of Unicode characters in the extension */
|
|
extLen = dosIndex;
|
|
/* If the extension was too large, or it was zero length */
|
|
/* (i.e. the name ended in a period), a CRC code must be */
|
|
/* appended to the mangled name. */
|
|
if (index < udfLen || extLen == 0)
|
|
needsCRC = TRUE;
|
|
}
|
|
/* Now process the actual file name. */
|
|
index = 0;
|
|
dosIndex = 0;
|
|
crcIndex = 0;
|
|
overlayBytes = -1;
|
|
bytesLeft = DOS_NAME_LEN;
|
|
while (index < nameLen && bytesLeft > 0) {
|
|
/* Get the current character and convert it to upper case. */
|
|
current = udfName[index];
|
|
if (current ==' ' || (current == '.' && !isParent) ) {
|
|
/* Spaces and periods are just skipped, a CRC code */
|
|
/* must be added to the mangled file name. */
|
|
needsCRC = TRUE;
|
|
} else {
|
|
/* Determine if this is a valid file name char and */
|
|
/* calculate its corresponding BCS character byte */
|
|
/* length (zero if the char is not legal or */
|
|
/* undisplayable on this system). */
|
|
|
|
charLen = (UDFIsIllegalChar(current)
|
|
/*|| !UnicodeIsPrint(current)*/) ? 0 : 1;
|
|
|
|
/* If the char is larger than the available space in */
|
|
/* the buffer, pretend it is undisplayable. */
|
|
if (charLen > bytesLeft)
|
|
charLen = 0;
|
|
|
|
if (charLen == 0) {
|
|
/* Undisplayable or illegal characters are */
|
|
/* substituted with an underscore ("_"), and */
|
|
/* required a CRC code appended to the mangled */
|
|
/* file name. */
|
|
needsCRC = TRUE;
|
|
charLen = 1;
|
|
current = '_';
|
|
/* Skip over any following undisplayable or illegal */
|
|
/* chars. */
|
|
while (index +1 <nameLen &&
|
|
(UDFIsIllegalChar(udfName[index+1])
|
|
/*|| !UnicodeIsPrint(udfName[index+1])*/))
|
|
index++;
|
|
/* Terminate loop if at the end of the file name. */
|
|
if (index >= nameLen)
|
|
break;
|
|
}
|
|
/* Assign the resulting char to the next index in the */
|
|
/* file name buffer and determine how many BCS bytes */
|
|
/* are left. */
|
|
dosName[dosIndex++] = current;
|
|
bytesLeft -= charLen;
|
|
/* This figures out where the CRC code needs to start */
|
|
/* in the file name buffer. */
|
|
if (bytesLeft >= DOS_CRC_LEN) {
|
|
/* If there is enough space left, just tack it */
|
|
/* onto the end. */
|
|
crcIndex = dosIndex;
|
|
} else {
|
|
/* If there is not enough space left, the CRC */
|
|
/* must overlay a character already in the file */
|
|
/* name buffer. Once this condition has been */
|
|
/* met, the value will not change. */
|
|
if (overlayBytes < 0) {
|
|
/* Determine the index and save the length of */
|
|
/* the BCS character that is overlayed. It */
|
|
/* is possible that the CRC might overlay */
|
|
/* half of a two-byte BCS character depending */
|
|
/* upon how the character boundaries line up. */
|
|
overlayBytes = (bytesLeft + charLen > DOS_CRC_LEN)?1 :0;
|
|
crcIndex = dosIndex - 1;
|
|
}
|
|
}
|
|
}
|
|
/* Advance to the next character. */
|
|
index++;
|
|
}
|
|
/* If the scan did not reach the end of the file name, or the */
|
|
/* length of the file name is zero, a CRC code is needed. */
|
|
if (index < nameLen || index == 0)
|
|
needsCRC = TRUE;
|
|
|
|
/* If the name has illegal characters or and extension, it */
|
|
/* is not a DOS device name. */
|
|
|
|
/* if (needsCRC == FALSE && extLen == 0) { */
|
|
/* If this is the name of a DOS device, a CRC code should */
|
|
/* be appended to the file name.
|
|
if (IsDeviceName(udfName, udfLen))
|
|
needsCRC = TRUE;
|
|
}*/
|
|
|
|
/* Append the CRC code to the file name, if needed. */
|
|
if (needsCRC) {
|
|
/* Get the CRC value for the original Unicode string */
|
|
valueCRC = UDFUnicodeCksum(udfName, udfLen);
|
|
|
|
/* begin. */
|
|
dosIndex = crcIndex;
|
|
/* If the character being overlayed is a two-byte BCS */
|
|
/* character, replace the first byte with an underscore. */
|
|
if (overlayBytes > 0)
|
|
dosName[dosIndex++] = '_';
|
|
/* Append the encoded CRC value with delimiter. */
|
|
dosName[dosIndex++] = '#';
|
|
dosName[dosIndex++] =
|
|
crcChar[valueCRC / (DOS_CRC_MODULUS * DOS_CRC_MODULUS)];
|
|
valueCRC %= DOS_CRC_MODULUS * DOS_CRC_MODULUS;
|
|
dosName[dosIndex++] =
|
|
crcChar[valueCRC / DOS_CRC_MODULUS];
|
|
valueCRC %= DOS_CRC_MODULUS;
|
|
dosName[dosIndex++] = crcChar[valueCRC];
|
|
}
|
|
/* Append the extension, if any. */
|
|
if (extLen > 0) {
|
|
/* Tack on a period and each successive byte in the */
|
|
/* extension buffer. */
|
|
dosName[dosIndex++] = '.';
|
|
for (index = 0; index < extLen; index++)
|
|
dosName[dosIndex++] = ext[index];
|
|
}
|
|
/* Return the length of the resulting Unicode string. */
|
|
DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
|
|
RtlUpcaseUnicodeString(DosName, DosName, FALSE);
|
|
|
|
} // end UDFDOSName201()
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
/*
|
|
This routine initializes Tag structure. It must be called after all
|
|
manual settings to generate valid CRC & Checksum
|
|
*/
|
|
void
|
|
UDFSetUpTag(
|
|
IN PVCB Vcb,
|
|
IN tag* Tag,
|
|
IN uint16 DataLen, // total length of descriptor _including_ icbTag
|
|
IN uint32 TagLoc
|
|
)
|
|
{
|
|
uint32 i;
|
|
int8* tb;
|
|
|
|
AdPrint(("UDF: SetTag Loc=%x(%x), tagIdent=%x\n", TagLoc, Tag->tagLocation, Tag->tagIdent));
|
|
|
|
if(DataLen) DataLen -= sizeof(tag);
|
|
// int8* Data = ((int8*)Tag) + sizeof(tag);
|
|
// Ecma-167 states, that all implementations
|
|
// shall set this field to '3' even if
|
|
// disc contains descriptors recorded with
|
|
// value '2'
|
|
// But we should ignore this to make happy othe UDF implementations :(
|
|
Tag->descVersion = (Vcb->NSRDesc & VRS_NSR03_FOUND) ? 3 : 2;
|
|
Tag->tagLocation = TagLoc;
|
|
Tag->tagSerialNum = (uint16)(Vcb->SerialNumber + 1);
|
|
Tag->descCRCLength = DataLen;
|
|
Tag->descCRC = UDFCrc((uint8*)(Tag+1), DataLen);
|
|
Tag->tagChecksum = 0;
|
|
tb = ((int8*)Tag);
|
|
for (i=0; i<sizeof(tag); i++,tb++)
|
|
Tag->tagChecksum += (i!=4) ? (*tb) : 0;
|
|
} // end UDFSetUpTag()
|
|
|
|
/*
|
|
This routine builds FileEntry & associated AllocDescs for specified
|
|
extent.
|
|
*/
|
|
OSSTATUS
|
|
UDFBuildFileEntry(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO DirInfo,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN uint32 PartNum,
|
|
IN uint16 AllocMode, // short/long/ext/in-icb
|
|
IN uint32 ExtAttrSz,
|
|
IN BOOLEAN Extended
|
|
)
|
|
{
|
|
PFILE_ENTRY FileEntry;
|
|
OSSTATUS status;
|
|
// EntityID* eID;
|
|
uint32 l;
|
|
EXTENT_INFO _FEExtInfo;
|
|
uint16* lcp;
|
|
|
|
ASSERT(!PartNum);
|
|
ASSERT(!ExtAttrSz);
|
|
// calculate the length required
|
|
l = (Extended ? sizeof(EXTENDED_FILE_ENTRY) : sizeof(FILE_ENTRY)) + ExtAttrSz;
|
|
if(l > Vcb->LBlockSize) return STATUS_INVALID_PARAMETER;
|
|
// allocate block for FE
|
|
if(!OS_SUCCESS(status = UDFAllocateFESpace(Vcb, DirInfo, PartNum, &_FEExtInfo, l) ))
|
|
return status;
|
|
// remember FE location for future hard link creation
|
|
ASSERT(UDFFindDloc(Vcb, _FEExtInfo.Mapping[0].extLocation) == (-1));
|
|
if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, _FEExtInfo.Mapping[0].extLocation))) {
|
|
ASSERT(status != STATUS_SHARING_PAUSED);
|
|
UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free
|
|
MyFreePool__(_FEExtInfo.Mapping);
|
|
return status;
|
|
}
|
|
FileEntry = (PFILE_ENTRY)MyAllocatePoolTag__(NonPagedPool, l, MEM_FE_TAG);
|
|
if(!FileEntry) {
|
|
UDFRemoveDloc(Vcb, FileInfo->Dloc);
|
|
FileInfo->Dloc = NULL;
|
|
UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free
|
|
MyFreePool__(_FEExtInfo.Mapping);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
FileInfo->Dloc->FELoc = _FEExtInfo;
|
|
|
|
RtlZeroMemory((int8*)FileEntry, l);
|
|
// set up in-memory FE structure
|
|
FileEntry->icbTag.flags = AllocMode;
|
|
FileEntry->icbTag.fileType = UDF_FILE_TYPE_REGULAR;
|
|
FileEntry->icbTag.numEntries = 1;
|
|
// if(DirInfo && DirInfo->Dloc && DirInfo->Dloc
|
|
FileEntry->icbTag.strategyType = 4;
|
|
// FileEntry->icbTag.strategyParameter = 0;
|
|
FileEntry->descTag.tagIdent = Extended ? TID_EXTENDED_FILE_ENTRY : TID_FILE_ENTRY;
|
|
FileEntry->descTag.tagLocation = UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation);
|
|
FileEntry->uid = Vcb->DefaultUID;
|
|
FileEntry->gid = Vcb->DefaultGID;
|
|
|
|
if(Extended) {
|
|
// eID = &(((PEXTENDED_FILE_ENTRY)FileEntry)->impIdent);
|
|
lcp = &(((PEXTENDED_FILE_ENTRY)FileEntry)->fileLinkCount);
|
|
((PEXTENDED_FILE_ENTRY)FileEntry)->checkpoint = 1;
|
|
} else {
|
|
// eID = &(FileEntry->impIdent);
|
|
lcp = &(FileEntry->fileLinkCount);
|
|
((PFILE_ENTRY)FileEntry)->checkpoint = 1;
|
|
}
|
|
|
|
#if 0
|
|
UDFSetEntityID_imp(eID, UDF_ID_DEVELOPER);
|
|
#endif
|
|
|
|
/*RtlCopyMemory((int8*)&(eID->ident), UDF_ID_DEVELOPER, sizeof(UDF_ID_DEVELOPER) );
|
|
iis = (impIdentSuffix*)&(eID->identSuffix);
|
|
iis->OSClass = UDF_OS_CLASS_WINNT;
|
|
iis->OSIdent = UDF_OS_ID_WINNT;*/
|
|
|
|
*lcp = 0xffff;
|
|
|
|
FileInfo->Dloc->FileEntry = (tag*)FileEntry;
|
|
FileInfo->Dloc->FileEntryLen = l;
|
|
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
|
|
return STATUS_SUCCESS;
|
|
} // end UDFBuildFileEntry()
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
/*
|
|
This routine builds ExtentInfo for specified (Ex)FileEntry & associated
|
|
AllocDescs
|
|
*/
|
|
OSSTATUS
|
|
UDFLoadExtInfo(
|
|
IN PVCB Vcb,
|
|
IN PFILE_ENTRY fe,
|
|
IN PLONG_AD fe_loc,
|
|
IN OUT PEXTENT_INFO FExtInfo, // user data
|
|
IN OUT PEXTENT_INFO AExtInfo // alloc descs
|
|
)
|
|
{
|
|
EXTENT_AD TmpExt;
|
|
|
|
UDFPrint((" UDFLoadExtInfo:\n"));
|
|
FExtInfo->Mapping = UDFReadMappingFromXEntry(Vcb, fe_loc->extLocation.partitionReferenceNum,
|
|
(tag*)fe, &(FExtInfo->Offset), AExtInfo);
|
|
if(!(FExtInfo->Mapping)) {
|
|
if(!(FExtInfo->Offset))
|
|
return STATUS_UNSUCCESSFUL;
|
|
TmpExt.extLength = fe_loc->extLength;
|
|
TmpExt.extLocation = UDFPartLbaToPhys(Vcb, &(fe_loc->extLocation));
|
|
if(TmpExt.extLocation == LBA_OUT_OF_EXTENT)
|
|
return STATUS_FILE_CORRUPT_ERROR;
|
|
FExtInfo->Mapping = UDFExtentToMapping(&TmpExt);
|
|
}
|
|
if(fe->descTag.tagIdent == TID_FILE_ENTRY) {
|
|
// UDFPrint(("Standard FileEntry\n"));
|
|
FExtInfo->Length = fe->informationLength;
|
|
} else /*if(fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY) */ {
|
|
FExtInfo->Length = ((PEXTENDED_FILE_ENTRY)fe)->informationLength;
|
|
}
|
|
UDFPrint((" FExtInfo->Length %x\n", FExtInfo->Length));
|
|
ASSERT(FExtInfo->Length <= UDFGetExtentLength(FExtInfo->Mapping));
|
|
FExtInfo->Modified = FALSE;
|
|
|
|
return STATUS_SUCCESS;
|
|
} // end UDFLoadExtInfo()
|
|
|
|
/*
|
|
This routine builds FileIdent for specified FileEntry.
|
|
We shall call UDFSetUpTag after all other initializations
|
|
This structure is a precise copy of on-disk FileIdent
|
|
structure. All modifications of it (including memory block
|
|
size) are reflected on Directory extent. This, allocation of
|
|
too long block (without changes in ImpUseLen) will lead to
|
|
unreadable Directory
|
|
*/
|
|
OSSTATUS
|
|
UDFBuildFileIdent(
|
|
IN PVCB Vcb,
|
|
IN PUNICODE_STRING fn,
|
|
IN PLONG_AD FileEntryIcb, // virtual address of FileEntry
|
|
IN uint32 ImpUseLen,
|
|
OUT PFILE_IDENT_DESC* _FileId,
|
|
OUT uint32* FileIdLen
|
|
)
|
|
{
|
|
PFILE_IDENT_DESC FileId;
|
|
uint8* CS0;
|
|
SIZE_T Nlen;
|
|
uint32 l;
|
|
// prepare filename
|
|
UDFCompressUnicode(fn, &CS0, &Nlen);
|
|
if(!CS0) return STATUS_INSUFFICIENT_RESOURCES;
|
|
if(Nlen < 2) {
|
|
Nlen = 0;
|
|
} else
|
|
if(Nlen > UDF_NAME_LEN) {
|
|
if(CS0) MyFreePool__(CS0);
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
}
|
|
// allocate memory for FI
|
|
l = (sizeof(FILE_IDENT_DESC) + Nlen + ImpUseLen + 3) & ~((uint32)3);
|
|
FileId = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, l, MEM_FID_TAG);
|
|
if(!FileId) {
|
|
if(CS0) MyFreePool__(CS0);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
// fill FI structure
|
|
RtlZeroMemory( (int8*)FileId, l);
|
|
RtlCopyMemory( ((int8*)(FileId+1))+ImpUseLen, CS0, Nlen);
|
|
FileId->descTag.tagIdent = TID_FILE_IDENT_DESC;
|
|
FileId->fileVersionNum = 1;
|
|
FileId->lengthOfImpUse = (uint16)ImpUseLen;
|
|
FileId->lengthFileIdent = (uint8)Nlen;
|
|
FileId->icb = *FileEntryIcb;
|
|
*_FileId = FileId;
|
|
*FileIdLen = l;
|
|
|
|
if(CS0) MyFreePool__(CS0);
|
|
return STATUS_SUCCESS;
|
|
} // end UDFBuildFileIdent()
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
/*
|
|
This routine sets informationLength field in (Ext)FileEntry
|
|
*/
|
|
void
|
|
UDFSetFileSize(
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN int64 Size
|
|
)
|
|
{
|
|
uint16 Ident;
|
|
// PDIR_INDEX_ITEM DirIndex;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
AdPrint(("UDFSetFileSize: %I64x, FI %x\n", Size, FileInfo));
|
|
|
|
//AdPrint((" Dloc %x\n", FileInfo->Dloc));
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
//AdPrint((" FileEntry %x\n", FileInfo->Dloc->FileEntry));
|
|
Ident = FileInfo->Dloc->FileEntry->tagIdent;
|
|
//AdPrint((" Ident %x\n", Ident));
|
|
if(Ident == TID_FILE_ENTRY) {
|
|
PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
//AdPrint((" fe %x\n", fe));
|
|
fe->informationLength = Size;
|
|
} else if(Ident == TID_EXTENDED_FILE_ENTRY) {
|
|
PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
//AdPrint((" ext-fe %x\n", fe));
|
|
fe->informationLength = Size;
|
|
}
|
|
/* if(DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index) ) {
|
|
DirIndex->FileSize = Size;
|
|
}*/
|
|
//AdPrint(("UDFSetFileSize: ok\n"));
|
|
return;
|
|
} // end UDFSetFileSize()
|
|
|
|
void
|
|
UDFSetFileSizeInDirNdx(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN int64* ASize
|
|
)
|
|
{
|
|
uint16 Ident;
|
|
PDIR_INDEX_ITEM DirIndex;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
if(ASize) {
|
|
AdPrint(("UDFSetFileSizeInDirNdx: %I64x\n", *ASize));
|
|
} else {
|
|
AdPrint(("UDFSetFileSizeInDirNdx: sync\n"));
|
|
}
|
|
|
|
DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index);
|
|
if(!DirIndex)
|
|
return;
|
|
|
|
Ident = FileInfo->Dloc->FileEntry->tagIdent;
|
|
if(Ident == TID_FILE_ENTRY) {
|
|
PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
DirIndex->FileSize = fe->informationLength;
|
|
if(ASize) {
|
|
DirIndex->AllocationSize = *ASize;
|
|
// } else {
|
|
// DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1);
|
|
}
|
|
} else if(Ident == TID_EXTENDED_FILE_ENTRY) {
|
|
PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
DirIndex->FileSize = fe->informationLength;
|
|
if(ASize) {
|
|
DirIndex->AllocationSize = *ASize;
|
|
// } else {
|
|
// DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1);
|
|
}
|
|
}
|
|
return;
|
|
} // end UDFSetFileSizeInDirNdx()
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
/*
|
|
This routine gets informationLength field in (Ext)FileEntry
|
|
*/
|
|
int64
|
|
UDFGetFileSize(
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
uint16 Ident;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
Ident = FileInfo->Dloc->FileEntry->tagIdent;
|
|
if(Ident == TID_FILE_ENTRY) {
|
|
PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
return fe->informationLength;
|
|
} else if(Ident == TID_EXTENDED_FILE_ENTRY) {
|
|
PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
return fe->informationLength;
|
|
}
|
|
return (-1);
|
|
} // end UDFGetFileSize()
|
|
|
|
int64
|
|
UDFGetFileSizeFromDirNdx(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
PDIR_INDEX_ITEM DirIndex;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index);
|
|
if(!DirIndex)
|
|
return -1;
|
|
|
|
return DirIndex->FileSize;
|
|
} // end UDFGetFileSizeFromDirNdx()
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
/*
|
|
This routine sets lengthAllocDesc field in (Ext)FileEntry
|
|
*/
|
|
void
|
|
UDFSetAllocDescLen(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
uint16 Ident;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
Ident = FileInfo->Dloc->FileEntry->tagIdent;
|
|
if(Ident == TID_FILE_ENTRY) {
|
|
PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
if(FileInfo->Dloc->AllocLoc.Length) {
|
|
fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength -
|
|
FileInfo->Dloc->AllocLoc.Offset,
|
|
(uint32)(FileInfo->Dloc->AllocLoc.Length));
|
|
} else
|
|
if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
|
|
fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length);
|
|
}
|
|
} else if(Ident == TID_EXTENDED_FILE_ENTRY) {
|
|
PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
if(FileInfo->Dloc->AllocLoc.Length) {
|
|
fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength -
|
|
FileInfo->Dloc->AllocLoc.Offset,
|
|
(uint32)(FileInfo->Dloc->AllocLoc.Length));
|
|
} else
|
|
if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
|
|
fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length);
|
|
}
|
|
}
|
|
} // end UDFSetAllocDescLen()
|
|
|
|
/*
|
|
This routine changes fileLinkCount field in (Ext)FileEntry
|
|
*/
|
|
void
|
|
UDFChangeFileLinkCount(
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN BOOLEAN Increase
|
|
)
|
|
{
|
|
uint16 Ident;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
Ident = FileInfo->Dloc->FileEntry->tagIdent;
|
|
if(Ident == TID_FILE_ENTRY) {
|
|
PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
if(Increase) {
|
|
fe->fileLinkCount++;
|
|
} else {
|
|
fe->fileLinkCount--;
|
|
}
|
|
if(fe->fileLinkCount & 0x8000)
|
|
fe->fileLinkCount = 0xffff;
|
|
return;
|
|
} else if(Ident == TID_EXTENDED_FILE_ENTRY) {
|
|
PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
if(Increase) {
|
|
fe->fileLinkCount++;
|
|
} else {
|
|
fe->fileLinkCount--;
|
|
}
|
|
if(fe->fileLinkCount & 0x8000)
|
|
fe->fileLinkCount = 0xffff;
|
|
return;
|
|
}
|
|
return;
|
|
} // end UDFChangeFileLinkCount()
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
/*
|
|
This routine gets fileLinkCount field from (Ext)FileEntry
|
|
*/
|
|
uint16
|
|
UDFGetFileLinkCount(
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
uint16 Ident;
|
|
uint16 d;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
if(!FileInfo->Dloc->FileEntry)
|
|
return 1;
|
|
Ident = FileInfo->Dloc->FileEntry->tagIdent;
|
|
// UDF engine assumes that LinkCount is a counter
|
|
// of FileIdents, referencing this FE.
|
|
// UDF 2.0 states, that it should be counter of ALL
|
|
// references (including SDir) - 1.
|
|
// Thus we'll write to media UDF-required value, but return
|
|
// cooked value to callers
|
|
d = UDFHasAStreamDir(FileInfo) ? 0 : 1;
|
|
if(Ident == TID_FILE_ENTRY) {
|
|
return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d;
|
|
} else if(Ident == TID_EXTENDED_FILE_ENTRY) {
|
|
return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d;
|
|
}
|
|
return UDF_INVALID_LINK_COUNT;
|
|
} // end UDFGetFileLinkCount()
|
|
|
|
#ifdef UDF_CHECK_UTIL
|
|
/*
|
|
This routine sets fileLinkCount field in (Ext)FileEntry
|
|
*/
|
|
void
|
|
UDFSetFileLinkCount(
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
uint16 LinkCount
|
|
)
|
|
{
|
|
uint16 Ident;
|
|
uint16 d;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
if(!FileInfo->Dloc->FileEntry)
|
|
return;
|
|
Ident = FileInfo->Dloc->FileEntry->tagIdent;
|
|
// UDF engine assumes that LinkCount is a counter
|
|
// of FileIdents, referencing this FE.
|
|
// UDF 2.0 states, that it should be counter of ALL
|
|
// references (including SDir) - 1.
|
|
// Thus we'll write to media UDF-required value, but return
|
|
// cooked value to callers
|
|
d = UDFHasAStreamDir(FileInfo) ? 0 : 1;
|
|
if(Ident == TID_FILE_ENTRY) {
|
|
((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d;
|
|
} else if(Ident == TID_EXTENDED_FILE_ENTRY) {
|
|
((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d;
|
|
}
|
|
return;
|
|
} // end UDFGetFileLinkCount()
|
|
#endif //UDF_CHECK_UTIL
|
|
|
|
/*
|
|
This routine gets lengthExtendedAttr field in (Ext)FileEntry
|
|
*/
|
|
uint32
|
|
UDFGetFileEALength(
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
uint16 Ident;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
if(!FileInfo->Dloc->FileEntry)
|
|
return 1;
|
|
Ident = FileInfo->Dloc->FileEntry->tagIdent;
|
|
|
|
if(Ident == TID_FILE_ENTRY) {
|
|
return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr;
|
|
} else if(Ident == TID_EXTENDED_FILE_ENTRY) {
|
|
return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr;
|
|
}
|
|
return 0;
|
|
} // end UDFGetFileEALength()
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
/*
|
|
This routine sets UniqueID field in (Ext)FileEntry
|
|
*/
|
|
int64
|
|
UDFAssingNewFUID(
|
|
IN PVCB Vcb
|
|
)
|
|
{
|
|
Vcb->NextUniqueId++;
|
|
if(!((uint32)(Vcb->NextUniqueId)))
|
|
Vcb->NextUniqueId += 16;
|
|
return Vcb->NextUniqueId;
|
|
}
|
|
|
|
void
|
|
UDFSetFileUID(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
uint16 Ident;
|
|
int64 UID;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
UID = UDFAssingNewFUID(Vcb);
|
|
|
|
/* UID = FileInfo->Dloc->FELoc.Mapping[0].extLocation |
|
|
( FileInfo->ParentFile ? (((int64)(FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation)) << 32) : 0);*/
|
|
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
Ident = FileInfo->Dloc->FileEntry->tagIdent;
|
|
if(Ident == TID_FILE_ENTRY) {
|
|
PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
fe->uniqueID = UID;
|
|
} else if(Ident == TID_EXTENDED_FILE_ENTRY) {
|
|
PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
fe->uniqueID = UID;
|
|
}
|
|
if(FileInfo->FileIdent)
|
|
((FidADImpUse*)&(FileInfo->FileIdent->icb.impUse))->uniqueID = (uint32)UID;
|
|
return;
|
|
} // end UDFSetFileUID()
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
/*
|
|
This routine gets UniqueID field in (Ext)FileEntry
|
|
*/
|
|
__inline
|
|
int64
|
|
UDFGetFileUID_(
|
|
IN tag* FileEntry
|
|
)
|
|
{
|
|
uint16 Ident;
|
|
|
|
Ident = FileEntry->tagIdent;
|
|
if(Ident == TID_FILE_ENTRY) {
|
|
PFILE_ENTRY fe = (PFILE_ENTRY)(FileEntry);
|
|
return fe->uniqueID;
|
|
} else if(Ident == TID_EXTENDED_FILE_ENTRY) {
|
|
PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileEntry);
|
|
return fe->uniqueID;
|
|
}
|
|
return (-1);
|
|
} // end UDFGetFileUID()
|
|
|
|
int64
|
|
UDFGetFileUID(
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
return UDFGetFileUID_(FileInfo->Dloc->FileEntry);
|
|
} // end UDFGetFileUID()
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
void
|
|
UDFChangeFileCounter(
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN FileCounter,
|
|
IN BOOLEAN Increase
|
|
)
|
|
{
|
|
uint32* counter;
|
|
|
|
counter = FileCounter ?
|
|
&(Vcb->numFiles) :
|
|
&(Vcb->numDirs);
|
|
if(*counter == (ULONG)-1)
|
|
return;
|
|
if(Increase) {
|
|
UDFInterlockedIncrement((int32*)counter);
|
|
} else {
|
|
UDFInterlockedDecrement((int32*)counter);
|
|
}
|
|
|
|
} // end UDFChangeFileCounter()
|
|
|
|
void
|
|
UDFSetEntityID_imp_(
|
|
IN EntityID* eID,
|
|
IN uint8* Str,
|
|
IN uint32 Len
|
|
)
|
|
{
|
|
impIdentSuffix* iis;
|
|
|
|
RtlCopyMemory( (int8*)&(eID->ident), Str, Len );
|
|
iis = (impIdentSuffix*)&(eID->identSuffix);
|
|
iis->OSClass = UDF_OS_CLASS_WINNT;
|
|
iis->OSIdent = UDF_OS_ID_WINNT;
|
|
|
|
} // end UDFSetEntityID_imp_()
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
void
|
|
UDFReadEntityID_Domain(
|
|
PVCB Vcb,
|
|
EntityID* eID
|
|
)
|
|
{
|
|
domainIdentSuffix* dis;
|
|
uint8 flags;
|
|
|
|
dis = (domainIdentSuffix*)&(eID->identSuffix);
|
|
|
|
UDFPrint(("UDF: Entity Id:\n"));
|
|
UDFPrint(("flags: %x\n", eID->flags));
|
|
UDFPrint(("ident[0]: %x\n", eID->ident[0]));
|
|
UDFPrint(("ident[1]: %x\n", eID->ident[1]));
|
|
UDFPrint(("ident[2]: %x\n", eID->ident[2]));
|
|
UDFPrint(("ident[3]: %x\n", eID->ident[3]));
|
|
UDFPrint(("UDF: Entity Id Domain:\n"));
|
|
// Get current UDF revision
|
|
Vcb->CurrentUDFRev = max(dis->currentRev, Vcb->CurrentUDFRev);
|
|
UDFPrint(("Effective Revision: %x\n", Vcb->CurrentUDFRev));
|
|
// Get Read-Only flags
|
|
flags = dis->flags;
|
|
UDFPrint(("Flags: %x\n", flags));
|
|
if((flags & ENTITYID_FLAGS_SOFT_RO) &&
|
|
(Vcb->CompatFlags & UDF_VCB_IC_SOFT_RO)) {
|
|
Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
|
|
Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_SOFT_RO;
|
|
UDFPrint((" Soft-RO\n"));
|
|
}
|
|
if((flags & ENTITYID_FLAGS_HARD_RO) &&
|
|
(Vcb->CompatFlags & UDF_VCB_IC_HW_RO)) {
|
|
Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_READ_ONLY;
|
|
Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_HW_RO;
|
|
UDFPrint((" Hard-RO\n"));
|
|
}
|
|
|
|
} // end UDFReadEntityID_Domain()
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
/*
|
|
This routine writes data to file & increases it if necessary.
|
|
In case of increasing AllocDescs will be rebuilt & flushed to disc
|
|
(via driver's cache, of cource). Free space map will be updated only
|
|
durring global media flush.
|
|
*/
|
|
OSSTATUS
|
|
UDFWriteFile__(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN int64 Offset,
|
|
IN SIZE_T Length,
|
|
IN BOOLEAN Direct,
|
|
IN int8* Buffer,
|
|
OUT PSIZE_T WrittenBytes
|
|
)
|
|
{
|
|
int64 t, elen;
|
|
OSSTATUS status;
|
|
int8* OldInIcb = NULL;
|
|
ValidateFileInfo(FileInfo);
|
|
SIZE_T ReadBytes;
|
|
SIZE_T _WrittenBytes;
|
|
PUDF_DATALOC_INFO Dloc;
|
|
// unwind staff
|
|
BOOLEAN WasInIcb = FALSE;
|
|
uint64 OldLen;
|
|
|
|
// ASSERT(FileInfo->RefCount >= 1);
|
|
|
|
Dloc = FileInfo->Dloc;
|
|
ASSERT(Dloc->FELoc.Mapping[0].extLocation);
|
|
uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Dloc->FELoc.Mapping[0].extLocation);
|
|
(*WrittenBytes) = 0;
|
|
|
|
AdPrint(("UDFWriteFile__ FE %x, FileInfo %x, ExtInfo %x, Mapping %x\n",
|
|
Dloc->FELoc.Mapping[0].extLocation, FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping));
|
|
|
|
t = Offset + Length;
|
|
// UDFUpdateModifyTime(Vcb, FileInfo);
|
|
if(t <= Dloc->DataLoc.Length) {
|
|
// write Alloc-Rec area
|
|
ExtPrint((" WAlloc-Rec: %I64x <= %I64x\n", t, Dloc->DataLoc.Length));
|
|
status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes);
|
|
return status;
|
|
}
|
|
elen = UDFGetExtentLength(Dloc->DataLoc.Mapping);
|
|
ExtPrint((" DataLoc Offs %x, Len %I64x\n",
|
|
Dloc->DataLoc.Offset, Dloc->DataLoc.Length));
|
|
if(t <= (elen - Dloc->DataLoc.Offset)) {
|
|
// write Alloc-Not-Rec area
|
|
ExtPrint((" WAlloc-Not-Rec: %I64x <= %I64x (%I64x - %I64x)\n",
|
|
t, elen - Dloc->DataLoc.Offset - Dloc->DataLoc.Length,
|
|
elen - Dloc->DataLoc.Offset,
|
|
Dloc->DataLoc.Length));
|
|
UDFSetFileSize(FileInfo, t);
|
|
if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
|
|
ExtPrint((" w2k-compat -> rebuild allocs\n"));
|
|
Dloc->DataLoc.Modified = TRUE;
|
|
} else
|
|
if((ULONG)((elen+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits) != (ULONG)((t+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits)) {
|
|
ExtPrint((" LBS boundary crossed -> rebuild allocs\n"));
|
|
Dloc->DataLoc.Modified = TRUE;
|
|
}
|
|
Dloc->DataLoc.Length = t;
|
|
return UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes);
|
|
}
|
|
// We should not get here if Direct=TRUE
|
|
if(Direct) return STATUS_INVALID_PARAMETER;
|
|
OldLen = Dloc->DataLoc.Length;
|
|
if(Dloc->DataLoc.Offset && Dloc->DataLoc.Length) {
|
|
// read in-icb data. it'll be replaced after resize
|
|
ExtPrint((" read in-icb data\n"));
|
|
OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length));
|
|
if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES;
|
|
status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &ReadBytes);
|
|
if(!OS_SUCCESS(status)) {
|
|
MyFreePool__(OldInIcb);
|
|
return status;
|
|
}
|
|
}
|
|
// init Alloc mode
|
|
ExtPrint((" init Alloc mode\n"));
|
|
if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
|
|
((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
|
|
((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode;
|
|
WasInIcb = TRUE;
|
|
}
|
|
// increase extent
|
|
ExtPrint((" %s %s %s\n",
|
|
UDFIsADirectory(FileInfo) ? "DIR" : "FILE",
|
|
WasInIcb ? "In-Icb" : "",
|
|
Vcb->LowFreeSpace ? "LowSpace" : ""));
|
|
if(UDFIsADirectory(FileInfo) && !WasInIcb && !Vcb->LowFreeSpace) {
|
|
FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_ALLOC_SEQUENTIAL;
|
|
status = UDFResizeExtent(Vcb, PartNum, (t*2+Vcb->WriteBlockSize-1) & ~(SIZE_T)(Vcb->WriteBlockSize-1), FALSE, &(Dloc->DataLoc));
|
|
if(OS_SUCCESS(status)) {
|
|
AdPrint((" preallocated space for Dir\n"));
|
|
FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_PREALLOCATED;
|
|
//UDFSetFileSize(FileInfo, t);
|
|
Dloc->DataLoc.Length = t;
|
|
} else
|
|
if(status == STATUS_DISK_FULL) {
|
|
status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc));
|
|
}
|
|
} else {
|
|
status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc));
|
|
}
|
|
ExtPrint((" DataLoc Offs %x, Len %I64x\n",
|
|
Dloc->DataLoc.Offset, Dloc->DataLoc.Length));
|
|
AdPrint(("UDFWriteFile__ (2) FileInfo %x, ExtInfo %x, Mapping %x\n", FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping));
|
|
if(!OS_SUCCESS(status)) {
|
|
// rollback
|
|
ExtPrint((" err -> rollback\n"));
|
|
if(WasInIcb) {
|
|
// restore Alloc mode
|
|
((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
|
|
((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB;
|
|
if(Dloc->AllocLoc.Mapping) {
|
|
MyFreePool__(Dloc->AllocLoc.Mapping);
|
|
Dloc->AllocLoc.Mapping = NULL;
|
|
}
|
|
}
|
|
if(OldInIcb) {
|
|
UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes);
|
|
MyFreePool__(OldInIcb);
|
|
}
|
|
if((int64)OldLen != Dloc->DataLoc.Length) {
|
|
// restore file size
|
|
AdPrint((" restore alloc\n"));
|
|
FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED;
|
|
UDFResizeExtent(Vcb, PartNum, OldLen, FALSE, &(Dloc->DataLoc));
|
|
FileInfo->Dloc->DataLoc.Flags &= ~EXTENT_FLAG_CUT_PREALLOCATED;
|
|
}
|
|
return status;
|
|
}
|
|
if(OldInIcb) {
|
|
// replace data from ICB (if any) & free buffer
|
|
ExtPrint((" write old in-icd data\n"));
|
|
status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes);
|
|
MyFreePool__(OldInIcb);
|
|
if(!OS_SUCCESS(status))
|
|
return status;
|
|
}
|
|
// ufff...
|
|
// & now we'll write out data to well prepared extent...
|
|
// ... like all normal people do...
|
|
ExtPrint((" write user data\n"));
|
|
if(!OS_SUCCESS(status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, FALSE, Buffer, WrittenBytes)))
|
|
return status;
|
|
UDFSetFileSize(FileInfo, t);
|
|
Dloc->DataLoc.Modified = TRUE;
|
|
#ifdef UDF_DBG
|
|
if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
|
|
ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
|
|
} else {
|
|
ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
|
|
((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
|
|
}
|
|
#endif // UDF_DBG
|
|
return STATUS_SUCCESS;
|
|
} // end UDFWriteFile__()
|
|
|
|
/*
|
|
This routine marks file as deleted & decrements file link counter.
|
|
It can optionaly free allocation space
|
|
*/
|
|
OSSTATUS
|
|
UDFUnlinkFile__(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN BOOLEAN FreeSpace
|
|
)
|
|
{
|
|
uint_di Index; // index of file to be deleted
|
|
uint16 lc;
|
|
PUDF_DATALOC_INFO Dloc;
|
|
PUDF_FILE_INFO DirInfo;
|
|
PUDF_FILE_INFO SDirInfo;
|
|
PDIR_INDEX_HDR hDirNdx;
|
|
PDIR_INDEX_HDR hCurDirNdx;
|
|
PDIR_INDEX_ITEM DirNdx;
|
|
OSSTATUS status;
|
|
BOOLEAN IsSDir;
|
|
|
|
AdPrint(("UDFUnlinkFile__:\n"));
|
|
if(!FileInfo) return STATUS_SUCCESS;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
#ifndef _CONSOLE
|
|
// now we can't call this if there is no OS-specific File Desc. present
|
|
if(FileInfo->Fcb)
|
|
UDFRemoveFileId__(Vcb, FileInfo);
|
|
#endif //_CONSOLE
|
|
// check references
|
|
Dloc = FileInfo->Dloc;
|
|
if((FileInfo->OpenCount /*> (uint32)(UDFHasAStreamDir(FileInfo) ? 1 : 0)*/) ||
|
|
(FileInfo->RefCount>1)) return STATUS_CANNOT_DELETE;
|
|
if(Dloc->SDirInfo)
|
|
return STATUS_CANNOT_DELETE;
|
|
ASSERT(FileInfo->RefCount == 1);
|
|
DirInfo = FileInfo->ParentFile;
|
|
// root dir or self
|
|
if(!DirInfo || ((FileInfo->Index < 2) && !UDFIsAStreamDir(FileInfo))) return STATUS_CANNOT_DELETE;
|
|
hDirNdx = DirInfo->Dloc->DirIndex;
|
|
Index = FileInfo->Index;
|
|
// we can't delete modified file
|
|
// it should be closed & reopened (or flushed) before deletion
|
|
DirNdx = UDFDirIndex(hDirNdx,Index);
|
|
#if defined UDF_DBG || defined PRINT_ALWAYS
|
|
if(DirNdx && DirNdx->FName.Buffer) {
|
|
AdPrint(("Unlink: %ws\n",DirNdx->FName.Buffer));
|
|
}
|
|
#endif // UDF_DBG
|
|
if(FreeSpace &&
|
|
((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
|
|
Dloc->DataLoc.Modified ||
|
|
Dloc->AllocLoc.Modified ||
|
|
Dloc->FELoc.Modified ||
|
|
(DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) )) {
|
|
// BrutePoint();
|
|
return STATUS_CANNOT_DELETE;
|
|
}
|
|
SDirInfo = Dloc->SDirInfo;
|
|
/* if(FreeSpace && SDirInfo) {
|
|
UDFPrint(("Unlink: SDirInfo should be NULL !!!\n"));
|
|
BrutePoint();
|
|
return STATUS_CANNOT_DELETE;
|
|
}*/
|
|
// stream directory can be deleted even being not empty
|
|
// otherwise we should perform some checks
|
|
if(!(IsSDir = UDFIsAStreamDir(FileInfo))) {
|
|
// check if not empty direcory
|
|
if((DirNdx->FileCharacteristics & FILE_DIRECTORY) &&
|
|
(hCurDirNdx = Dloc->DirIndex) &&
|
|
FreeSpace) {
|
|
if(!UDFIsDirEmpty(hCurDirNdx))
|
|
return STATUS_DIRECTORY_NOT_EMPTY;
|
|
}
|
|
DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
|
|
DirNdx->FileCharacteristics |= FILE_DELETED;
|
|
FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
|
|
hDirNdx->DelCount++;
|
|
UDFChangeFileCounter(Vcb, !UDFIsADirectory(FileInfo), FALSE);
|
|
}
|
|
UDFDecFileLinkCount(FileInfo); // decrease
|
|
lc = UDFGetFileLinkCount(FileInfo);
|
|
if(DirNdx && FreeSpace) {
|
|
// FileIdent marked as 'deleted' should have an empty ICB
|
|
// We shall do it only if object has parent Dir
|
|
// (for ex. SDir has parent object, but has no parent Dir)
|
|
DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
|
|
DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
|
|
// Root Files (Root/SDir/Vat/etc.) has no FileIdent...
|
|
if(FileInfo->FileIdent)
|
|
RtlZeroMemory(&(FileInfo->FileIdent->icb), sizeof(long_ad));
|
|
}
|
|
// caller wishes to free allocation, but we can't do it due to
|
|
// alive links. In this case we should just remove reference
|
|
if(FreeSpace && lc) {
|
|
((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum = 0;
|
|
((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = 0;
|
|
Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
} else
|
|
// if caller wishes to free file allocation &
|
|
// there are no more references(links) to this file, lets do it >;->
|
|
if(FreeSpace && !lc) {
|
|
if(UDFHasAStreamDir(FileInfo) &&
|
|
!UDFIsSDirDeleted(Dloc->SDirInfo) ) {
|
|
// we have a Stream Dir associated...
|
|
PUDF_FILE_INFO SFileInfo;
|
|
// ... try to open it
|
|
if(Dloc->SDirInfo) {
|
|
UDFFlushFile__(Vcb, FileInfo);
|
|
return STATUS_CANNOT_DELETE;
|
|
}
|
|
// open SDir
|
|
status = UDFOpenStreamDir__(Vcb, FileInfo, &(Dloc->SDirInfo));
|
|
if(!OS_SUCCESS(status)) {
|
|
// abort Unlink on error
|
|
SFileInfo = Dloc->SDirInfo;
|
|
cleanup_SDir:
|
|
UDFCleanUpFile__(Vcb, SFileInfo);
|
|
if(SFileInfo) MyFreePool__(SFileInfo);
|
|
UDFFlushFile__(Vcb, FileInfo);
|
|
return status;
|
|
}
|
|
SDirInfo = Dloc->SDirInfo;
|
|
// try to perform deltree for Streams
|
|
status = UDFUnlinkAllFilesInDir(Vcb, SDirInfo);
|
|
if(!OS_SUCCESS(status)) {
|
|
// abort Unlink on error
|
|
UDFCloseFile__(Vcb, SDirInfo);
|
|
SFileInfo = SDirInfo;
|
|
BrutePoint();
|
|
goto cleanup_SDir;
|
|
}
|
|
// delete SDir
|
|
UDFFlushFile__(Vcb, SDirInfo);
|
|
AdPrint((" "));
|
|
UDFUnlinkFile__(Vcb, SDirInfo, TRUE);
|
|
// close SDir
|
|
UDFCloseFile__(Vcb, SDirInfo);
|
|
if(UDFCleanUpFile__(Vcb, SDirInfo)) {
|
|
MyFreePool__(SDirInfo);
|
|
#ifdef UDF_DBG
|
|
} else {
|
|
BrutePoint();
|
|
#endif // UDF_DBG
|
|
}
|
|
// update FileInfo
|
|
ASSERT(Dloc->FileEntry);
|
|
RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad));
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
} else
|
|
if(IsSDir) {
|
|
// do deltree for Streams
|
|
status = UDFUnlinkAllFilesInDir(Vcb, FileInfo);
|
|
if(!OS_SUCCESS(status)) {
|
|
UDFFlushFile__(Vcb, FileInfo);
|
|
return status;
|
|
}
|
|
// update parent FileInfo
|
|
ASSERT(FileInfo->ParentFile->Dloc->FileEntry);
|
|
RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(FileInfo->ParentFile->Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad));
|
|
FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR;
|
|
FileInfo->ParentFile->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED |
|
|
UDF_FE_FLAG_HAS_DEL_SDIR);
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_DEL_SDIR;
|
|
UDFDecFileLinkCount(FileInfo->ParentFile);
|
|
}
|
|
if(Dloc->DirIndex) {
|
|
UDFFlushFESpace(Vcb, Dloc, FLUSH_FE_FOR_DEL);
|
|
}
|
|
// flush file
|
|
UDFFlushFile__(Vcb, FileInfo);
|
|
UDFUnlinkDloc(Vcb, Dloc);
|
|
// free allocation
|
|
UDFFreeFileAllocation(Vcb, DirInfo, FileInfo);
|
|
ASSERT(!(FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED));
|
|
FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
} // end UDFUnlinkFile__()
|
|
|
|
OSSTATUS
|
|
UDFUnlinkAllFilesInDir(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO DirInfo
|
|
)
|
|
{
|
|
PDIR_INDEX_HDR hCurDirNdx;
|
|
PDIR_INDEX_ITEM CurDirNdx;
|
|
PUDF_FILE_INFO FileInfo;
|
|
OSSTATUS status;
|
|
uint_di i;
|
|
|
|
hCurDirNdx = DirInfo->Dloc->DirIndex;
|
|
// check if we can delete all files
|
|
for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) {
|
|
// try to open Stream
|
|
if(CurDirNdx->FileInfo)
|
|
return STATUS_CANNOT_DELETE;
|
|
}
|
|
// start deletion
|
|
for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) {
|
|
// try to open Stream
|
|
status = UDFOpenFile__(Vcb, FALSE, TRUE, NULL, DirInfo, &FileInfo, &i);
|
|
if(status == STATUS_FILE_DELETED) {
|
|
// we should not release on-disk allocation for
|
|
// deleted streams twice
|
|
if(CurDirNdx->FileInfo) {
|
|
BrutePoint();
|
|
goto err_del_stream;
|
|
}
|
|
goto skip_del_stream;
|
|
} else
|
|
if(!OS_SUCCESS(status)) {
|
|
// Error :(((
|
|
err_del_stream:
|
|
UDFCleanUpFile__(Vcb, FileInfo);
|
|
if(FileInfo)
|
|
MyFreePool__(FileInfo);
|
|
return status;
|
|
}
|
|
|
|
UDFFlushFile__(Vcb, FileInfo);
|
|
AdPrint((" "));
|
|
UDFUnlinkFile__(Vcb, FileInfo, TRUE);
|
|
UDFCloseFile__(Vcb, FileInfo);
|
|
skip_del_stream:
|
|
if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) {
|
|
MyFreePool__(FileInfo);
|
|
}
|
|
}
|
|
return STATUS_SUCCESS;
|
|
} // end UDFUnlinkAllFilesInDir()
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
/*
|
|
This routine inits UDF_FILE_INFO structure for specified file
|
|
If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
|
|
for returned pointer *WITHOUT* using UDFCloseFile__
|
|
*/
|
|
OSSTATUS
|
|
UDFOpenFile__(
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN IgnoreCase,
|
|
IN BOOLEAN NotDeleted,
|
|
IN PUNICODE_STRING fn,
|
|
IN PUDF_FILE_INFO DirInfo,
|
|
OUT PUDF_FILE_INFO* _FileInfo,// this is to be filled & doesn't contain
|
|
// any pointers
|
|
IN uint_di* IndexToOpen
|
|
)
|
|
{
|
|
OSSTATUS status;
|
|
uint_di i=0;
|
|
EXTENT_AD FEExt;
|
|
uint16 Ident;
|
|
PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex;
|
|
PDIR_INDEX_ITEM DirNdx;
|
|
PUDF_FILE_INFO FileInfo;
|
|
PUDF_FILE_INFO ParFileInfo;
|
|
SIZE_T ReadBytes;
|
|
*_FileInfo = NULL;
|
|
if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
|
|
|
|
// find specified file in directory index
|
|
// if it is already known, skip this foolish code
|
|
if(IndexToOpen) {
|
|
i=*IndexToOpen;
|
|
} else
|
|
if(!OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, NotDeleted, fn, DirInfo, &i)))
|
|
return status;
|
|
// do this check for OpenByIndex
|
|
// some routines may send invalid Index
|
|
if(!(DirNdx = UDFDirIndex(hDirNdx,i)))
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
if((FileInfo = DirNdx->FileInfo)) {
|
|
// file is already opened.
|
|
if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) {
|
|
AdPrint((" FILE_DELETED on open\n"));
|
|
return STATUS_FILE_DELETED;
|
|
}
|
|
if((FileInfo->ParentFile != DirInfo) &&
|
|
(FileInfo->Index >= 2)) {
|
|
ParFileInfo = UDFLocateParallelFI(DirInfo, i, FileInfo);
|
|
BrutePoint();
|
|
if(ParFileInfo->ParentFile != DirInfo) {
|
|
FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG);
|
|
*_FileInfo = FileInfo;
|
|
if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES;
|
|
RtlCopyMemory(FileInfo, DirNdx->FileInfo, sizeof(UDF_FILE_INFO));
|
|
// FileInfo->NextLinkedFile = DirNdx->FileInfo->NextLinkedFile; // is already done
|
|
UDFInsertLinkedFile(FileInfo, DirNdx->FileInfo);
|
|
DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED;
|
|
FileInfo->RefCount = 0;
|
|
FileInfo->ParentFile = DirInfo;
|
|
FileInfo->Fcb = NULL;
|
|
} else {
|
|
FileInfo = ParFileInfo;
|
|
}
|
|
}
|
|
// Just increase some counters & exit
|
|
UDFReferenceFile__(FileInfo);
|
|
|
|
ASSERT(FileInfo->ParentFile == DirInfo);
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
*_FileInfo = FileInfo;
|
|
return STATUS_SUCCESS;
|
|
} else
|
|
if(IndexToOpen) {
|
|
if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) {
|
|
AdPrint((" FILE_DELETED on open (2)\n"));
|
|
return STATUS_FILE_DELETED;
|
|
}
|
|
}
|
|
FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG);
|
|
*_FileInfo = FileInfo;
|
|
if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES;
|
|
RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
|
|
// init horizontal links
|
|
FileInfo->NextLinkedFile =
|
|
FileInfo->PrevLinkedFile = FileInfo;
|
|
// read FileIdent
|
|
FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG);
|
|
if(!(FileInfo->FileIdent)) return STATUS_INSUFFICIENT_RESOURCES;
|
|
FileInfo->FileIdentLen = DirNdx->Length;
|
|
if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset,
|
|
DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) ))
|
|
return status;
|
|
if(FileInfo->FileIdent->descTag.tagIdent != TID_FILE_IDENT_DESC) {
|
|
BrutePoint();
|
|
return STATUS_FILE_CORRUPT_ERROR;
|
|
}
|
|
// check for opened links
|
|
if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation)))))
|
|
return status;
|
|
// init pointer to parent object
|
|
FileInfo->Index = i;
|
|
FileInfo->ParentFile = DirInfo;
|
|
// init pointers to linked files (if any)
|
|
if(FileInfo->Dloc->LinkedFileInfo != FileInfo)
|
|
UDFInsertLinkedFile(FileInfo, FileInfo->Dloc->LinkedFileInfo);
|
|
if(FileInfo->Dloc->FileEntry)
|
|
goto init_tree_entry;
|
|
// read (Ex)FileEntry
|
|
FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, Vcb->LBlockSize, MEM_FE_TAG);
|
|
if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES;
|
|
if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileInfo->FileIdent->icb), (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident)))
|
|
return status;
|
|
// build mappings for Data & AllocDescs
|
|
if(!FileInfo->Dloc->AllocLoc.Mapping) {
|
|
FEExt.extLength = FileInfo->FileIdent->icb.extLength;
|
|
FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation) );
|
|
if(FEExt.extLocation == LBA_OUT_OF_EXTENT)
|
|
return STATUS_FILE_CORRUPT_ERROR;
|
|
FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt);
|
|
if(!(FileInfo->Dloc->AllocLoc.Mapping))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
// read location info
|
|
status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &(FileInfo->FileIdent->icb),
|
|
&(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) );
|
|
if(!OS_SUCCESS(status))
|
|
return status;
|
|
// init (Ex)FileEntry mapping
|
|
FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset :
|
|
FileInfo->Dloc->AllocLoc.Offset;
|
|
// FileInfo->Dloc->FELoc.Offset = 0;
|
|
FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt);
|
|
FileInfo->Dloc->FileEntryLen = (uint32)(FileInfo->Dloc->FELoc.Length);
|
|
// we get here immediately when opened link encountered
|
|
init_tree_entry:
|
|
// init back pointer from parent object
|
|
ASSERT(!DirNdx->FileInfo);
|
|
DirNdx->FileInfo = FileInfo;
|
|
// init DirIndex
|
|
if(UDFGetFileLinkCount(FileInfo) > 1) {
|
|
DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED;
|
|
} else {
|
|
DirNdx->FI_Flags &= ~UDF_FI_FLAG_LINKED;
|
|
}
|
|
// resize FE cache (0x800 instead of 0x40 is not a good idea)
|
|
if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), Vcb->LBlockSize,
|
|
(int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
// check if this file has a SDir
|
|
if((FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) &&
|
|
((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength )
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR;
|
|
if(!(FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) {
|
|
UDFReferenceFile__(FileInfo);
|
|
ASSERT(FileInfo->ParentFile == DirInfo);
|
|
UDFReleaseDloc(Vcb, FileInfo->Dloc);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
|
|
|
|
// build index for directories
|
|
if(!FileInfo->Dloc->DirIndex) {
|
|
status = UDFIndexDirectory(Vcb, FileInfo);
|
|
if(!OS_SUCCESS(status))
|
|
return status;
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) &&
|
|
!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {
|
|
status = UDFPackDirectory__(Vcb, FileInfo);
|
|
if(!OS_SUCCESS(status))
|
|
return status;
|
|
}
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
}
|
|
UDFReferenceFile__(FileInfo);
|
|
UDFReleaseDloc(Vcb, FileInfo->Dloc);
|
|
ASSERT(FileInfo->ParentFile == DirInfo);
|
|
|
|
return status;
|
|
} // end UDFOpenFile__()
|
|
|
|
|
|
/*
|
|
This routine inits UDF_FILE_INFO structure for root directory
|
|
*/
|
|
OSSTATUS
|
|
UDFOpenRootFile__(
|
|
IN PVCB Vcb,
|
|
IN lb_addr* RootLoc,
|
|
OUT PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
uint32 RootLBA;
|
|
OSSTATUS status;
|
|
// uint32 PartNum = RootLoc->partitionReferenceNum;
|
|
uint32 LBS = Vcb->LBlockSize;
|
|
uint16 Ident;
|
|
LONG_AD FELoc;
|
|
EXTENT_AD FEExt;
|
|
uint8 FileType;
|
|
|
|
RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
|
|
RootLBA = UDFPartLbaToPhys(Vcb,RootLoc);
|
|
if(RootLBA == LBA_OUT_OF_EXTENT)
|
|
return STATUS_FILE_CORRUPT_ERROR;
|
|
FELoc.extLocation = *RootLoc;
|
|
FELoc.extLength = LBS;
|
|
// init horizontal links
|
|
FileInfo->NextLinkedFile =
|
|
FileInfo->PrevLinkedFile = FileInfo;
|
|
// check for opened links
|
|
if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, RootLBA)))
|
|
return status;
|
|
if(FileInfo->Dloc->FileEntry)
|
|
goto init_tree_entry;
|
|
// read (Ex)FileEntry
|
|
FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, LBS, MEM_FE_TAG);
|
|
if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &FELoc, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident)))
|
|
return status;
|
|
// build mappings for Data & AllocDescs
|
|
FEExt.extLength = LBS;
|
|
FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FELoc.extLocation) );
|
|
if(FEExt.extLocation == LBA_OUT_OF_EXTENT)
|
|
return STATUS_FILE_CORRUPT_ERROR;
|
|
FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt);
|
|
if(!(FileInfo->Dloc->FELoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
|
|
// build mappings for AllocDescs
|
|
if(!FileInfo->Dloc->AllocLoc.Mapping) {
|
|
FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt);
|
|
if(!(FileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
if(!OS_SUCCESS(status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &FELoc,
|
|
&(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) ) ))
|
|
return status;
|
|
FileInfo->Dloc->FileEntryLen = (uint32)
|
|
(FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset :
|
|
FileInfo->Dloc->AllocLoc.Offset);
|
|
init_tree_entry:
|
|
// resize FE cache (0x800 instead of 0x40 is not a good idea)
|
|
if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), LBS,
|
|
(int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen))
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
// init DirIndex
|
|
if( (FileType = ((icbtag*)((FileInfo->Dloc->FileEntry)+1))->fileType) != UDF_FILE_TYPE_DIRECTORY &&
|
|
(FileType != UDF_FILE_TYPE_STREAMDIR) ) {
|
|
UDFReferenceFile__(FileInfo);
|
|
UDFReleaseDloc(Vcb, FileInfo->Dloc);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
// build index for directories
|
|
if(!FileInfo->Dloc->DirIndex) {
|
|
status = UDFIndexDirectory(Vcb, FileInfo);
|
|
if(!OS_SUCCESS(status))
|
|
return status;
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) &&
|
|
!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {
|
|
status = UDFPackDirectory__(Vcb, FileInfo);
|
|
if(!OS_SUCCESS(status))
|
|
return status;
|
|
}
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
}
|
|
UDFReferenceFile__(FileInfo);
|
|
UDFReleaseDloc(Vcb, FileInfo->Dloc);
|
|
|
|
return status;
|
|
} // end UDFOpenRootFile__()
|
|
|
|
/*
|
|
This routine frees all memory blocks referenced by given FileInfo
|
|
*/
|
|
uint32
|
|
UDFCleanUpFile__(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
PUDF_DATALOC_INFO Dloc;
|
|
uint32 lc = 0;
|
|
BOOLEAN IsASDir;
|
|
BOOLEAN KeepDloc;
|
|
PDIR_INDEX_ITEM DirNdx, DirNdx2;
|
|
BOOLEAN Parallel = FALSE;
|
|
BOOLEAN Linked = FALSE;
|
|
#ifdef UDF_DBG
|
|
BOOLEAN Modified = FALSE;
|
|
PDIR_INDEX_HDR hDirNdx;
|
|
uint_di Index;
|
|
PUDF_FILE_INFO DirInfo;
|
|
#endif // UDF_DBG
|
|
|
|
if(!FileInfo) return UDF_FREE_FILEINFO;
|
|
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
if(FileInfo->OpenCount || FileInfo->RefCount) {
|
|
UDFPrint(("UDF: not all references are closed\n"));
|
|
UDFPrint((" Skipping cleanup\n"));
|
|
UDFPrint(("UDF: OpenCount = %x, RefCount = %x, LinkRefCount = %x\n",
|
|
FileInfo->OpenCount,FileInfo->RefCount,FileInfo->Dloc->LinkRefCount));
|
|
return UDF_FREE_NOTHING;
|
|
}
|
|
if(FileInfo->Fcb) {
|
|
UDFPrint(("Operating System still has references to this file\n"));
|
|
UDFPrint((" Skipping cleanup\n"));
|
|
// BrutePoint();
|
|
return UDF_FREE_NOTHING;
|
|
}
|
|
|
|
IsASDir = UDFIsAStreamDir(FileInfo);
|
|
|
|
if((Dloc = FileInfo->Dloc)) {
|
|
|
|
#ifdef UDF_DBG
|
|
DirInfo = FileInfo->ParentFile;
|
|
if(DirInfo) {
|
|
hDirNdx = DirInfo->Dloc->DirIndex;
|
|
Index = FileInfo->Index;
|
|
// we can't delete modified file
|
|
// it should be closed & reopened (or flushed) before deletion
|
|
DirNdx = UDFDirIndex(hDirNdx,Index);
|
|
UDFPrint(("Cleanup Mod: %s%s%s%s%s%s\n",
|
|
(Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ? "FE " : "",
|
|
(Dloc->DataLoc.Modified) ? "DataLoc " : "",
|
|
(Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) ? "Data-PreAlloc " : "",
|
|
(Dloc->AllocLoc.Modified) ? "AllocLoc " : "",
|
|
(Dloc->FELoc.Modified) ? "FELoc " : "",
|
|
(DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) ? "FI " : ""
|
|
));
|
|
Modified = ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
|
|
Dloc->DataLoc.Modified ||
|
|
(Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) ||
|
|
Dloc->AllocLoc.Modified ||
|
|
Dloc->FELoc.Modified ||
|
|
(DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) );
|
|
}
|
|
#endif // UDF_DBG
|
|
|
|
PUDF_FILE_INFO ParFileInfo = UDFLocateAnyParallelFI(FileInfo);
|
|
|
|
Parallel = (ParFileInfo != NULL);
|
|
Linked = (FileInfo->NextLinkedFile != FileInfo);
|
|
|
|
// Parallel = (FileInfo->NextLinkedFile != FileInfo);
|
|
ASSERT(FileInfo->NextLinkedFile);
|
|
// ASSERT(!Parallel);
|
|
KeepDloc = (Dloc->LinkRefCount ||
|
|
Dloc->CommonFcb ||
|
|
Linked ) ?
|
|
TRUE : FALSE;
|
|
|
|
if(Dloc->DirIndex) {
|
|
uint_di i;
|
|
for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) {
|
|
if(DirNdx->FileInfo) {
|
|
if(!KeepDloc) {
|
|
BrutePoint();
|
|
UDFPrint(("UDF: Found not cleaned up reference.\n"));
|
|
UDFPrint((" Skipping cleanup (1)\n"));
|
|
// BrutePoint();
|
|
return UDF_FREE_NOTHING;
|
|
}
|
|
// The file being cleaned up may have not closed Dirs
|
|
// (linked Dir). In this case each of them may have
|
|
// reference to FileInfo in DirIndex[1]
|
|
// Here we'll check it and change for valid value if
|
|
// necessary (Update Child Objects - I)
|
|
if(DirNdx->FileInfo->Dloc) {
|
|
// we can get here only when (Parallel == TRUE)
|
|
DirNdx2 = UDFDirIndex(DirNdx->FileInfo->Dloc->DirIndex, 1);
|
|
// It is enough to check DirNdx2->FileInfo only.
|
|
// If one of Parallel FI's has reference (and equal)
|
|
// to the FI being removed, it'll be removed from
|
|
// the chain & nothing wrong will happen.
|
|
if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) {
|
|
if(FileInfo->PrevLinkedFile == FileInfo) {
|
|
BrutePoint();
|
|
DirNdx2->FileInfo = NULL;
|
|
} else {
|
|
DirNdx2->FileInfo = Parallel ?
|
|
ParFileInfo : FileInfo->PrevLinkedFile;
|
|
}
|
|
ASSERT(!DirNdx2->FileInfo->RefCount);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(Dloc->SDirInfo) {
|
|
UDFPrint(("UDF: Found not cleaned up reference (SDir).\n"));
|
|
|
|
// (Update Child Objects - II)
|
|
if(Dloc->SDirInfo->ParentFile == FileInfo) {
|
|
BrutePoint();
|
|
ASSERT(ParFileInfo);
|
|
Dloc->SDirInfo->ParentFile = ParFileInfo;
|
|
}
|
|
// We should break Cleanup process if alive reference detected
|
|
// and there is no possibility to store pointer in some other
|
|
// place (in parallel object)
|
|
if(!KeepDloc) {
|
|
BrutePoint();
|
|
UDFPrint((" Skipping cleanup\n"));
|
|
return UDF_FREE_NOTHING;
|
|
}
|
|
|
|
if(!UDFIsSDirDeleted(Dloc->SDirInfo) &&
|
|
Dloc->SDirInfo->Dloc) {
|
|
DirNdx2 = UDFDirIndex(Dloc->SDirInfo->Dloc->DirIndex, 1);
|
|
if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) {
|
|
DirNdx2->FileInfo =
|
|
Parallel ? ParFileInfo : NULL;
|
|
ASSERT(!DirNdx2->FileInfo->RefCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!KeepDloc) {
|
|
|
|
#ifdef UDF_DBG
|
|
ASSERT(!Modified);
|
|
#endif
|
|
|
|
#ifndef UDF_TRACK_ONDISK_ALLOCATION
|
|
if(Dloc->DataLoc.Mapping) MyFreePool__(Dloc->DataLoc.Mapping);
|
|
if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping);
|
|
if(Dloc->FELoc.Mapping) MyFreePool__(Dloc->FELoc.Mapping);
|
|
if(Dloc->FileEntry) {
|
|
// plain file
|
|
lc = UDFGetFileLinkCount(FileInfo);
|
|
MyFreePool__(Dloc->FileEntry);
|
|
Dloc->FileEntry = NULL;
|
|
} else if(FileInfo->Index >= 2) {
|
|
// error durring open operation
|
|
lc = UDF_INVALID_LINK_COUNT;
|
|
}
|
|
#endif //UDF_TRACK_ONDISK_ALLOCATION
|
|
if(FileInfo->Dloc->DirIndex) {
|
|
uint_di i;
|
|
for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) {
|
|
ASSERT(!DirNdx->FileInfo);
|
|
if(DirNdx->FName.Buffer)
|
|
MyFreePool__(DirNdx->FName.Buffer);
|
|
}
|
|
// The only place where we can free FE_Charge extent is here
|
|
UDFFlushFESpace(Vcb, Dloc);
|
|
UDFDirIndexFree(Dloc->DirIndex);
|
|
Dloc->DirIndex = NULL;
|
|
#ifdef UDF_TRACK_ONDISK_ALLOCATION
|
|
UDFIndexDirectory(Vcb, FileInfo);
|
|
if(FileInfo->Dloc->DirIndex) {
|
|
for(i=2; DirNdx = UDFDirIndex(Dloc->DirIndex,i); i++) {
|
|
ASSERT(!DirNdx->FileInfo);
|
|
if(DirNdx->FName.Buffer)
|
|
MyFreePool__(DirNdx->FName.Buffer);
|
|
}
|
|
UDFDirIndexFree(Dloc->DirIndex);
|
|
Dloc->DirIndex = NULL;
|
|
}
|
|
#endif //UDF_TRACK_ONDISK_ALLOCATION
|
|
}
|
|
|
|
#ifdef UDF_TRACK_ONDISK_ALLOCATION
|
|
if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping);
|
|
if(Dloc->FELoc.Mapping) MyFreePool__(Dloc->FELoc.Mapping);
|
|
if(Dloc->FileEntry) {
|
|
// plain file
|
|
lc = UDFGetFileLinkCount(FileInfo);
|
|
MyFreePool__(Dloc->FileEntry);
|
|
Dloc->FileEntry = NULL;
|
|
} else if(FileInfo->Index >= 2) {
|
|
// error durring open operation
|
|
lc = UDF_INVALID_LINK_COUNT;
|
|
}
|
|
if(Dloc->DataLoc.Mapping) {
|
|
if(lc && (lc != UDF_INVALID_LINK_COUNT)) {
|
|
UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_USED); // check if used
|
|
} else {
|
|
UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_FREE); // check if free
|
|
}
|
|
MyFreePool__(Dloc->DataLoc.Mapping);
|
|
}
|
|
#endif //UDF_TRACK_ONDISK_ALLOCATION
|
|
|
|
if(lc && (lc != UDF_INVALID_LINK_COUNT)) {
|
|
UDFRemoveDloc(Vcb, Dloc);
|
|
} else {
|
|
UDFFreeDloc(Vcb, Dloc);
|
|
}
|
|
} else // KeepDloc cannot be FALSE if (Linked == TRUE)
|
|
if(Linked) {
|
|
// BrutePoint();
|
|
// Update pointers in ParentObject (if any)
|
|
if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo)
|
|
FileInfo->ParentFile->Dloc->SDirInfo = FileInfo->PrevLinkedFile;
|
|
DirNdx = UDFDirIndex(FileInfo->Dloc->DirIndex, 0);
|
|
if(DirNdx && (DirNdx->FileInfo == FileInfo))
|
|
DirNdx->FileInfo = FileInfo->PrevLinkedFile;
|
|
DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index);
|
|
if(DirNdx && (DirNdx->FileInfo == FileInfo))
|
|
DirNdx->FileInfo = ParFileInfo;
|
|
// remove from linked chain
|
|
FileInfo->NextLinkedFile->PrevLinkedFile = FileInfo->PrevLinkedFile;
|
|
FileInfo->PrevLinkedFile->NextLinkedFile = FileInfo->NextLinkedFile;
|
|
// update pointer in Dloc
|
|
if(FileInfo->Dloc->LinkedFileInfo == FileInfo)
|
|
FileInfo->Dloc->LinkedFileInfo = FileInfo->PrevLinkedFile;
|
|
}
|
|
FileInfo->Dloc = NULL;
|
|
} else {
|
|
KeepDloc = FALSE;
|
|
}
|
|
|
|
// Cleanup pointers in ParentObject (if any)
|
|
if(IsASDir) {
|
|
if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo) {
|
|
ASSERT(!Linked);
|
|
FileInfo->ParentFile->Dloc->SDirInfo = NULL;
|
|
FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_DEL_SDIR;
|
|
}
|
|
} else
|
|
if(FileInfo->ParentFile) {
|
|
ASSERT(FileInfo->ParentFile->Dloc);
|
|
DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index);
|
|
ASSERT(DirNdx);
|
|
#ifdef UDF_DBG
|
|
PUDF_FILE_INFO OldFI;
|
|
if(Parallel) {
|
|
ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) ||
|
|
!(OldFI == FileInfo));
|
|
} else {
|
|
ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) ||
|
|
(OldFI == FileInfo));
|
|
}
|
|
#endif
|
|
if( DirNdx && (DirNdx->FileInfo == FileInfo) ) {
|
|
if(!Parallel)
|
|
DirNdx->FileInfo = NULL;
|
|
#ifdef UDF_DBG
|
|
} else {
|
|
// We can get here after incomplete Open
|
|
if(!Parallel && DirNdx->FileInfo)
|
|
BrutePoint();
|
|
#endif
|
|
}
|
|
#ifdef UDF_DBG
|
|
} else {
|
|
// BrutePoint();
|
|
#endif
|
|
}
|
|
|
|
if(!Parallel && FileInfo->FileIdent)
|
|
MyFreePool__(FileInfo->FileIdent);
|
|
FileInfo->FileIdent = NULL;
|
|
// Kill reference to parent object
|
|
FileInfo->ParentFile = NULL;
|
|
// Kill references to parallel object(s) since it has no reference to
|
|
// this one now
|
|
FileInfo->NextLinkedFile =
|
|
FileInfo->PrevLinkedFile = FileInfo;
|
|
if(FileInfo->ListPtr)
|
|
FileInfo->ListPtr->FileInfo = NULL;;
|
|
return KeepDloc ? UDF_FREE_FILEINFO : (UDF_FREE_FILEINFO | UDF_FREE_DLOC);
|
|
} // end UDFCleanUpFile__()
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
/*
|
|
This routine creates FileIdent record in destination directory &
|
|
allocates FileEntry with in-ICB zero-sized data
|
|
If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
|
|
for returned pointer *WITHOUT* using UDFCloseFile__
|
|
*/
|
|
OSSTATUS
|
|
UDFCreateFile__(
|
|
IN PVCB Vcb,
|
|
// IN uint16 AllocMode, // short/long/ext/in-icb // always in-ICB
|
|
IN BOOLEAN IgnoreCase,
|
|
IN PUNICODE_STRING _fn,
|
|
IN uint32 ExtAttrSz,
|
|
IN uint32 ImpUseLen,
|
|
IN BOOLEAN Extended,
|
|
IN BOOLEAN CreateNew,
|
|
IN OUT PUDF_FILE_INFO DirInfo,
|
|
OUT PUDF_FILE_INFO* _FileInfo
|
|
)
|
|
{
|
|
uint32 l, d;
|
|
uint_di i, j;
|
|
OSSTATUS status;
|
|
LONG_AD FEicb;
|
|
UDF_DIR_SCAN_CONTEXT ScanContext;
|
|
PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex;
|
|
PDIR_INDEX_ITEM DirNdx;
|
|
uint32 LBS = Vcb->LBlockSize;
|
|
PUDF_FILE_INFO FileInfo;
|
|
*_FileInfo = NULL;
|
|
BOOLEAN undel = FALSE;
|
|
SIZE_T ReadBytes;
|
|
// BOOLEAN PackDir = FALSE;
|
|
BOOLEAN FEAllocated = FALSE;
|
|
|
|
ValidateFileInfo(DirInfo);
|
|
*_FileInfo = NULL;
|
|
|
|
ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
|
|
i = 0;
|
|
|
|
_SEH2_TRY {
|
|
|
|
// check if exists
|
|
status = UDFFindFile(Vcb, IgnoreCase, FALSE, _fn, DirInfo, &i);
|
|
DirNdx = UDFDirIndex(hDirNdx,i);
|
|
if(OS_SUCCESS(status)) {
|
|
// file is a Cur(Parent)Dir
|
|
if(i<2) try_return (status = STATUS_ACCESS_DENIED);
|
|
// file deleted
|
|
if(UDFIsDeleted(DirNdx)) {
|
|
j=0;
|
|
if(OS_SUCCESS(UDFFindFile(Vcb, IgnoreCase, TRUE, _fn, DirInfo, &j))) {
|
|
i=j;
|
|
DirNdx = UDFDirIndex(hDirNdx,i);
|
|
goto CreateBothFound;
|
|
}
|
|
// we needn't allocating new FileIdent inside Dir stream
|
|
// perform 'undel'
|
|
if(DirNdx->FileInfo) {
|
|
// BrutePoint();
|
|
status = UDFPretendFileDeleted__(Vcb, DirNdx->FileInfo);
|
|
if(!OS_SUCCESS(status))
|
|
try_return (status = STATUS_FILE_DELETED);
|
|
} else {
|
|
undel = TRUE;
|
|
}
|
|
// BrutePoint();
|
|
goto CreateUndel;
|
|
}
|
|
CreateBothFound:
|
|
// file already exists
|
|
if(CreateNew) try_return (status = STATUS_ACCESS_DENIED);
|
|
// try to open it
|
|
BrutePoint();
|
|
status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, _fn, DirInfo, _FileInfo,&i);
|
|
// *_FileInfo = FileInfo; // OpenFile__ has already done it, so update it...
|
|
DirNdx = UDFDirIndex(hDirNdx,i);
|
|
DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
|
|
FileInfo = *_FileInfo;
|
|
if(!OS_SUCCESS(status)) {
|
|
// :(( can't open....
|
|
if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) {
|
|
MyFreePool__(FileInfo);
|
|
*_FileInfo = NULL;
|
|
}
|
|
BrutePoint();
|
|
try_return (status);
|
|
}
|
|
// check if we can delete this file
|
|
if(FileInfo->OpenCount || (FileInfo->RefCount > 1)) {
|
|
BrutePoint();
|
|
UDFCloseFile__(Vcb, FileInfo);
|
|
try_return (status = STATUS_CANNOT_DELETE);
|
|
}
|
|
BrutePoint();
|
|
// remove DIRECTORY flag
|
|
DirNdx->FileCharacteristics &= ~FILE_DIRECTORY;
|
|
FileInfo->FileIdent->fileCharacteristics &= ~FILE_DIRECTORY;
|
|
DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
|
|
// truncate file size to ZERO
|
|
status = UDFResizeFile__(Vcb, FileInfo, 0);
|
|
if(!OS_SUCCESS(status)) {
|
|
BrutePoint();
|
|
UDFCloseFile__(Vcb, FileInfo);
|
|
}
|
|
// set NORMAL flag
|
|
FileInfo->FileIdent->fileCharacteristics = 0;
|
|
DirNdx->FileCharacteristics = 0;
|
|
// update DeletedFiles counter in Directory... (for PackDir)
|
|
if(undel && OS_SUCCESS(status))
|
|
hDirNdx->DelCount--;
|
|
try_return (status);
|
|
}
|
|
|
|
CreateUndel:
|
|
|
|
// allocate FileInfo
|
|
FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FE_TAG);
|
|
*_FileInfo = FileInfo;
|
|
if(!FileInfo)
|
|
try_return (status = STATUS_INSUFFICIENT_RESOURCES);
|
|
ImpUseLen = (ImpUseLen + 3) & ~((uint16)3);
|
|
|
|
RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
|
|
// init horizontal links
|
|
FileInfo->NextLinkedFile =
|
|
FileInfo->PrevLinkedFile = FileInfo;
|
|
// allocate space for FileEntry
|
|
if(!OS_SUCCESS(status =
|
|
UDFBuildFileEntry(Vcb, DirInfo, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) )) {
|
|
BrutePoint();
|
|
try_return (status);
|
|
}
|
|
FEAllocated = TRUE;
|
|
FEicb.extLength = LBS;
|
|
ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
FEicb.extLocation.partitionReferenceNum = (uint16)PartNum;
|
|
RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse));
|
|
|
|
if(!undel) {
|
|
// build FileIdent
|
|
if(!OS_SUCCESS(status =
|
|
UDFBuildFileIdent(Vcb, _fn, &FEicb, ImpUseLen,
|
|
&(FileInfo->FileIdent), &(FileInfo->FileIdentLen)) ))
|
|
try_return (status);
|
|
} else {
|
|
// read FileIdent
|
|
FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG);
|
|
if(!(FileInfo->FileIdent)) try_return (status = STATUS_INSUFFICIENT_RESOURCES);
|
|
FileInfo->FileIdentLen = DirNdx->Length;
|
|
if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset,
|
|
DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) ))
|
|
try_return (status);
|
|
FileInfo->FileIdent->fileCharacteristics = 0;
|
|
FileInfo->FileIdent->icb = FEicb;
|
|
ImpUseLen = FileInfo->FileIdent->lengthOfImpUse;
|
|
DirNdx->FileCharacteristics = 0;
|
|
}
|
|
// init 'parentICBLocation' & so on in FE
|
|
((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum =
|
|
UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum;
|
|
// ((icbtag*)(FileInfo->Dloc->FileEntry+1))->strategyType = 4;
|
|
// ((icbtag*)(FileInfo->Dloc->FileEntry+1))->numEntries = 1;
|
|
// try to find suitable unused FileIdent in DirIndex
|
|
l = FileInfo->FileIdentLen;
|
|
if(undel) goto CrF__2;
|
|
#ifndef UDF_LIMIT_DIR_SIZE
|
|
if(Vcb->CDR_Mode) {
|
|
#endif // UDF_LIMIT_DIR_SIZE
|
|
// search for suitable unused entry
|
|
if(UDFDirIndexInitScan(DirInfo, &ScanContext, 2)) {
|
|
while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) {
|
|
if((DirNdx->Length == l) && UDFIsDeleted(DirNdx) &&
|
|
!DirNdx->FileInfo ) {
|
|
// free unicode-buffer with old name
|
|
if(DirNdx->FName.Buffer) {
|
|
MyFreePool__(DirNdx->FName.Buffer);
|
|
DirNdx->FName.Buffer = NULL;
|
|
}
|
|
i = ScanContext.i;
|
|
goto CrF__1;
|
|
}
|
|
}
|
|
}
|
|
#ifndef UDF_LIMIT_DIR_SIZE
|
|
} else {
|
|
#endif // UDF_LIMIT_DIR_SIZE
|
|
i = UDFDirIndexGetLastIndex(hDirNdx); // 'i' points beyond EO DirIndex
|
|
#ifndef UDF_LIMIT_DIR_SIZE
|
|
}
|
|
#endif // UDF_LIMIT_DIR_SIZE
|
|
|
|
// append entry
|
|
if(!OS_SUCCESS(status = UDFDirIndexGrow(&(DirInfo->Dloc->DirIndex), 1))) {
|
|
try_return (status);
|
|
}
|
|
|
|
// init offset of new FileIdent in directory Data extent
|
|
hDirNdx = DirInfo->Dloc->DirIndex;
|
|
if(i-1) {
|
|
DirNdx = UDFDirIndex(hDirNdx,i-1);
|
|
UDFDirIndex(hDirNdx,i)->Offset = DirNdx->Offset + DirNdx->Length;
|
|
DirNdx = UDFDirIndex(hDirNdx,i);
|
|
} else {
|
|
DirNdx = UDFDirIndex(hDirNdx,i);
|
|
DirNdx->Offset = 0;
|
|
}
|
|
// new terminator is recorded by UDFDirIndexGrow()
|
|
if( ((d = ((LBS - (DirNdx->Offset + l + DirInfo->Dloc->DataLoc.Offset)) & (LBS-1) )) < sizeof(FILE_IDENT_DESC)) &&
|
|
d ) {
|
|
// insufficient space at the end of last sector for
|
|
// next FileIdent's tag. fill it with ImpUse data
|
|
|
|
// generally, all data should be DWORD-aligned, but if it is not so
|
|
// this opearation will help us to avoid glitches
|
|
d = (d+3) & ~((uint32)3);
|
|
|
|
uint32 IUl, FIl;
|
|
if(!MyReallocPool__((int8*)(FileInfo->FileIdent), l,
|
|
(int8**)&(FileInfo->FileIdent), (l+d+3) & ~((uint32)(3)) ))
|
|
try_return (status = STATUS_INSUFFICIENT_RESOURCES);
|
|
l += d;
|
|
IUl = FileInfo->FileIdent->lengthOfImpUse;
|
|
FIl = FileInfo->FileIdent->lengthFileIdent;
|
|
// move filename to higher addr
|
|
RtlMoveMemory(((int8*)(FileInfo->FileIdent+1))+IUl+d,
|
|
((int8*)(FileInfo->FileIdent+1))+IUl, FIl);
|
|
RtlZeroMemory(((int8*)(FileInfo->FileIdent+1))+IUl, d);
|
|
FileInfo->FileIdent->lengthOfImpUse += (uint16)d;
|
|
FileInfo->FileIdentLen = l;
|
|
}
|
|
DirNdx->Length = l;
|
|
CrF__1:
|
|
// clone unicode string
|
|
// it **<<MUST>>** be allocated with internal memory manager
|
|
DirNdx->FName.Buffer = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (DirNdx->FName.MaximumLength = _fn->Length + sizeof(WCHAR)), MEM_FNAMECPY_TAG);
|
|
DirNdx->FName.Length = _fn->Length;
|
|
if(!DirNdx->FName.Buffer)
|
|
try_return (status = STATUS_INSUFFICIENT_RESOURCES);
|
|
RtlCopyMemory(DirNdx->FName.Buffer, _fn->Buffer, _fn->Length);
|
|
DirNdx->FName.Buffer[_fn->Length/sizeof(WCHAR)] = 0;
|
|
CrF__2:
|
|
DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL);
|
|
// we get here immediately when 'undel' occured
|
|
FileInfo->Index = i;
|
|
DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
|
|
DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
|
|
ASSERT(!DirNdx->FileInfo);
|
|
DirNdx->FileInfo = FileInfo;
|
|
DirNdx->FileEntryLoc = FEicb.extLocation;
|
|
// mark file as 'deleted' for now
|
|
DirNdx->FileCharacteristics = FILE_DELETED;
|
|
FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
|
|
FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0]));
|
|
if(!(FileInfo->Dloc->DataLoc.Mapping)) {
|
|
UDFFlushFI(Vcb, FileInfo, PartNum);
|
|
try_return (status = STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
FileInfo->Dloc->DataLoc.Length = 0;
|
|
FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
|
|
FileInfo->ParentFile = DirInfo;
|
|
// init FileEntry
|
|
UDFSetFileUID(Vcb, FileInfo);
|
|
UDFSetFileSize(FileInfo, 0);
|
|
UDFIncFileLinkCount(FileInfo); // increase to 1
|
|
UDFUpdateCreateTime(Vcb, FileInfo);
|
|
UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index),
|
|
FileInfo->Dloc->FileEntry, Vcb->DefaultAttr);
|
|
FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
|
|
FileInfo->Dloc->DataLoc.Modified = TRUE;
|
|
FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
|
|
// zero sector for FileEntry
|
|
if(!Vcb->CDR_Mode) {
|
|
status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, LBS, FALSE, Vcb->ZBuffer, &ReadBytes);
|
|
if(!OS_SUCCESS(status)) {
|
|
UDFFlushFI(Vcb, FileInfo, PartNum);
|
|
try_return (status);
|
|
}
|
|
}
|
|
#if 0
|
|
if((i >= 2) && (DirNdx->FName.Buffer[0] == L'.')) {
|
|
BrutePoint();
|
|
}
|
|
#endif
|
|
|
|
#ifdef UDF_CHECK_DISK_ALLOCATION
|
|
if( /*FileInfo->Fcb &&*/
|
|
UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
|
|
|
|
if(!FileInfo->FileIdent ||
|
|
!(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
|
|
AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
|
|
BrutePoint();
|
|
}
|
|
}
|
|
#endif // UDF_CHECK_DISK_ALLOCATION
|
|
|
|
// make FileIdent valid
|
|
FileInfo->FileIdent->fileCharacteristics = 0;
|
|
DirNdx->FileCharacteristics = 0;
|
|
UDFReferenceFile__(FileInfo);
|
|
UDFFlushFE(Vcb, FileInfo, PartNum);
|
|
if(undel)
|
|
hDirNdx->DelCount--;
|
|
UDFReleaseDloc(Vcb, FileInfo->Dloc);
|
|
UDFIncFileCounter(Vcb);
|
|
|
|
UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
|
|
|
|
try_return (status = STATUS_SUCCESS);
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} _SEH2_FINALLY {
|
|
if(!OS_SUCCESS(status)) {
|
|
if(FEAllocated)
|
|
UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc));
|
|
}
|
|
} _SEH2_END
|
|
return status;
|
|
|
|
} // end UDFCreateFile__()
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
/*
|
|
This routine reads data from file described by FileInfo
|
|
*/
|
|
/*__inline
|
|
OSSTATUS
|
|
UDFReadFile__(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN int64 Offset, // offset in extent
|
|
IN SIZE_T Length,
|
|
IN BOOLEAN Direct,
|
|
OUT int8* Buffer,
|
|
OUT PSIZE_T ReadBytes
|
|
)
|
|
{
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
return UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, Buffer, ReadBytes);
|
|
} // end UDFReadFile__()*/
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
/*
|
|
This routine zeros data in file described by FileInfo
|
|
*/
|
|
__inline
|
|
OSSTATUS
|
|
UDFZeroFile__(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN int64 Offset, // offset in extent
|
|
IN SIZE_T Length,
|
|
IN BOOLEAN Direct,
|
|
OUT PSIZE_T ReadBytes
|
|
)
|
|
{
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
return UDFZeroExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes);
|
|
} // end UDFZeroFile__()*/
|
|
|
|
/*
|
|
This routine makes sparse area in file described by FileInfo
|
|
*/
|
|
__inline
|
|
OSSTATUS
|
|
UDFSparseFile__(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN int64 Offset, // offset in extent
|
|
IN SIZE_T Length,
|
|
IN BOOLEAN Direct,
|
|
OUT PSIZE_T ReadBytes
|
|
)
|
|
{
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
return UDFSparseExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes);
|
|
} // end UDFSparseFile__()*/
|
|
|
|
/*
|
|
This routine fills tails of the last sector in extent with ZEROs
|
|
*/
|
|
OSSTATUS
|
|
UDFPadLastSector(
|
|
IN PVCB Vcb,
|
|
IN PEXTENT_INFO ExtInfo
|
|
)
|
|
{
|
|
if(!ExtInfo || !(ExtInfo->Mapping) || !(ExtInfo->Length)) return STATUS_INVALID_PARAMETER;
|
|
|
|
PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
|
|
SIZE_T to_write, WrittenBytes;
|
|
uint32 Lba, sect_offs, flags;
|
|
OSSTATUS status;
|
|
// Length should not be zero
|
|
int64 Offset = ExtInfo->Length + ExtInfo->Offset;
|
|
// data is sector-size-aligned, we needn't any padding
|
|
if(Offset && !((uint32)Offset & (Vcb->LBlockSize-1) )) return STATUS_SUCCESS;
|
|
// get Lba of the last sector
|
|
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL);
|
|
// EOF check. If we have valid ExtInfo this will not happen, but who knows..
|
|
if((Lba == (uint32)-1) ||
|
|
(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED))
|
|
return STATUS_END_OF_FILE;
|
|
// write tail
|
|
status = UDFWriteData(Vcb, TRUE, (((int64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_write, FALSE, Vcb->ZBuffer, &WrittenBytes);
|
|
return status;
|
|
} // UDFPadLastSector()
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
/*
|
|
This routine updates AllocDesc sequence, FileIdent & FileEntry
|
|
for given file
|
|
*/
|
|
OSSTATUS
|
|
UDFCloseFile__(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
if(!FileInfo) return STATUS_SUCCESS;
|
|
if(FileInfo->Index<2 && (FileInfo->ParentFile) && !UDFIsAStreamDir(FileInfo)) {
|
|
UDFPrint(("Closing Current or Parent Directory... :-\\\n"));
|
|
if(FileInfo->RefCount) {
|
|
UDFInterlockedDecrement((PLONG)&(FileInfo->RefCount));
|
|
ASSERT(FileInfo->Dloc);
|
|
if(FileInfo->Dloc)
|
|
UDFInterlockedDecrement((PLONG)&(FileInfo->Dloc->LinkRefCount));
|
|
#ifdef UDF_DBG
|
|
} else {
|
|
BrutePoint();
|
|
UDFPrint(("ERROR: Closing unreferenced file!\n"));
|
|
#endif // UDF_DBG
|
|
}
|
|
if(FileInfo->ParentFile->OpenCount) {
|
|
UDFInterlockedDecrement((PLONG)&(FileInfo->ParentFile->OpenCount));
|
|
#ifdef UDF_DBG
|
|
} else {
|
|
BrutePoint();
|
|
UDFPrint(("ERROR: Closing unopened file!\n"));
|
|
#endif // UDF_DBG
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
PUDF_FILE_INFO DirInfo = FileInfo->ParentFile;
|
|
OSSTATUS status;
|
|
uint32 PartNum;
|
|
if(FileInfo->RefCount) {
|
|
UDFInterlockedDecrement((PLONG)&(FileInfo->RefCount));
|
|
ASSERT(FileInfo->Dloc);
|
|
if(FileInfo->Dloc)
|
|
UDFInterlockedDecrement((PLONG)&(FileInfo->Dloc->LinkRefCount));
|
|
#ifdef UDF_DBG
|
|
} else {
|
|
BrutePoint();
|
|
UDFPrint(("ERROR: Closing unreferenced file!\n"));
|
|
#endif // UDF_DBG
|
|
}
|
|
if(DirInfo) {
|
|
// validate DirInfo
|
|
ValidateFileInfo(DirInfo);
|
|
|
|
if(DirInfo->OpenCount) {
|
|
UDFInterlockedDecrement((PLONG)&(DirInfo->OpenCount));
|
|
#ifdef UDF_DBG
|
|
} else {
|
|
BrutePoint();
|
|
UDFPrint(("ERROR: Closing unopened file!\n"));
|
|
#endif // UDF_DBG
|
|
}
|
|
}
|
|
// If the file has gone (unlinked) we should return STATUS_SUCCESS here.
|
|
if(!FileInfo->Dloc) return STATUS_SUCCESS;
|
|
|
|
if(FileInfo->RefCount ||
|
|
FileInfo->OpenCount ||
|
|
!(FileInfo->Dloc->FELoc.Mapping)) return STATUS_SUCCESS;
|
|
// ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
if(PartNum == (uint32)-1) {
|
|
UDFPrint((" Is DELETED ?\n"));
|
|
if(DirInfo) {
|
|
PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
} else {
|
|
BrutePoint();
|
|
}
|
|
}
|
|
#ifdef UDF_CHECK_DISK_ALLOCATION
|
|
if( FileInfo->Fcb &&
|
|
UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
|
|
|
|
//ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
if(UDFIsAStreamDir(FileInfo)) {
|
|
if(!UDFIsSDirDeleted(FileInfo)) {
|
|
UDFPrint((" Not DELETED SDir\n"));
|
|
BrutePoint();
|
|
}
|
|
ASSERT(!FileInfo->Dloc->FELoc.Modified);
|
|
} else
|
|
if(!FileInfo->FileIdent ||
|
|
!(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
|
|
if(!FileInfo->FileIdent) {
|
|
AdPrint((" No FileIdent\n"));
|
|
}
|
|
if(FileInfo->FileIdent &&
|
|
!(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED))
|
|
AdPrint((" Not DELETED\n"));
|
|
ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
|
|
BrutePoint();
|
|
} else {
|
|
UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free
|
|
UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_FREE); // check if free
|
|
}
|
|
} else {
|
|
if(!FileInfo->Dloc->FELoc.Mapping[0].extLocation ||
|
|
UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
|
|
UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free
|
|
} else {
|
|
UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
|
|
}
|
|
}
|
|
#endif // UDF_CHECK_DISK_ALLOCATION
|
|
// check if we should update parentICBLocation
|
|
if( !((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum &&
|
|
!((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum &&
|
|
DirInfo &&
|
|
!Vcb->CDR_Mode &&
|
|
Vcb->Modified &&
|
|
UDFGetFileLinkCount(FileInfo) ) {
|
|
ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum =
|
|
UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum;
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
}
|
|
|
|
// we needn't flushing FE & Allocs untill all links are closed...
|
|
if(!FileInfo->Dloc->LinkRefCount) {
|
|
|
|
// flush FE and pre-allocation charge for directories
|
|
if(FileInfo->Dloc &&
|
|
FileInfo->Dloc->DirIndex) {
|
|
|
|
UDFFlushFESpace(Vcb, FileInfo->Dloc);
|
|
if(FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) {
|
|
FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED;
|
|
status = UDFResizeExtent(Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc));
|
|
FileInfo->Dloc->DataLoc.Flags &= ~(EXTENT_FLAG_PREALLOCATED | EXTENT_FLAG_CUT_PREALLOCATED);
|
|
if(OS_SUCCESS(status)) {
|
|
AdPrint(("Dir pre-alloc truncated (Close)\n"));
|
|
FileInfo->Dloc->DataLoc.Modified = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!OS_SUCCESS(status = UDFFlushFE(Vcb, FileInfo, PartNum))) {
|
|
UDFPrint(("Error flushing FE\n"));
|
|
//flush_recovery:
|
|
BrutePoint();
|
|
if(FileInfo->Index >= 2) {
|
|
PDIR_INDEX_ITEM DirNdx;
|
|
DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index);
|
|
if(DirNdx) {
|
|
UDFPrint(("Recovery: mark as deleted & flush FI\n"));
|
|
DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
|
|
DirNdx->FileCharacteristics |= FILE_DELETED;
|
|
FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
|
|
UDFFlushFI(Vcb, FileInfo, PartNum);
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
}
|
|
// ... but FI must be updated (if any)
|
|
if(!OS_SUCCESS(status = UDFFlushFI(Vcb, FileInfo, PartNum))) {
|
|
UDFPrint(("Error flushing FI\n"));
|
|
return status;
|
|
}
|
|
#ifdef UDF_DBG
|
|
// ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
if((FileInfo->Dloc->FileEntry->descVersion != 2) &&
|
|
(FileInfo->Dloc->FileEntry->descVersion != 3)) {
|
|
ASSERT(UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation));
|
|
}
|
|
#endif // UDF_DBG
|
|
return STATUS_SUCCESS;
|
|
} // end UDFCloseFile__()
|
|
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
/*
|
|
This routine moves file from DirInfo1 to DirInfo2 & renames it to fn
|
|
*/
|
|
OSSTATUS
|
|
UDFRenameMoveFile__(
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN IgnoreCase,
|
|
IN OUT BOOLEAN* Replace, // replace if destination file exists
|
|
IN PUNICODE_STRING fn, // destination
|
|
IN OUT PUDF_FILE_INFO DirInfo1,
|
|
IN OUT PUDF_FILE_INFO DirInfo2,
|
|
IN OUT PUDF_FILE_INFO FileInfo // source (opened)
|
|
)
|
|
{
|
|
PUDF_FILE_INFO FileInfo2;
|
|
OSSTATUS status;
|
|
PDIR_INDEX_ITEM DirNdx1;
|
|
PDIR_INDEX_ITEM DirNdx2;
|
|
uint_di i,j;
|
|
BOOLEAN Recovery = FALSE;
|
|
BOOLEAN SameFE = FALSE;
|
|
uint32 NTAttr = 0;
|
|
|
|
// validate FileInfo
|
|
ValidateFileInfo(DirInfo1);
|
|
ValidateFileInfo(DirInfo2);
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
i = j = 0;
|
|
if(DirInfo1 == DirInfo2) {
|
|
if(OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &j)) &&
|
|
(j==FileInfo->Index) ) {
|
|
// case-only rename
|
|
uint8* CS0;
|
|
SIZE_T Nlen, /* l, FIXME ReactOS */ IUl;
|
|
|
|
// prepare filename
|
|
UDFCompressUnicode(fn, &CS0, &Nlen);
|
|
if(!CS0) return STATUS_INSUFFICIENT_RESOURCES;
|
|
/* if(Nlen > UDF_NAME_LEN) {
|
|
if(CS0) MyFreePool__(CS0);
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
}*/
|
|
// allocate memory for FI
|
|
DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex,j);
|
|
IUl = DirNdx2->FileInfo->FileIdent->lengthOfImpUse;
|
|
#if 0
|
|
l = (sizeof(FILE_IDENT_DESC) + Nlen + IUl + 3) & ~((uint32)3);
|
|
#endif
|
|
|
|
RtlCopyMemory( ((uint8*)(DirNdx2->FileInfo->FileIdent+1))+IUl, CS0, Nlen);
|
|
RtlCopyMemory(DirNdx2->FName.Buffer, fn->Buffer, fn->Length);
|
|
|
|
if(CS0) MyFreePool__(CS0);
|
|
|
|
DirNdx2->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
|
|
UDFBuildHashEntry(Vcb, &(DirNdx2->FName), &(DirNdx2->hashes), HASH_ALL);
|
|
return STATUS_SUCCESS;
|
|
/* } else
|
|
if(!OS_SUCCESS(status) && (fn->Length == UDFDirIndex(DirInfo2->Dloc->DirIndex, j=FileInfo->Index)->FName.Length)) {
|
|
// target file doesn't exist, but name lengthes are equal
|
|
RtlCopyMemory((DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex,j))->FName.Buffer, fn->Buffer, fn->Length);
|
|
DirNdx1->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
|
|
UDFBuildHashEntry(Vcb, &(DirNdx1->FName), &(DirNdx1->hashes), HASH_ALL);
|
|
return STATUS_SUCCESS;*/
|
|
}
|
|
}
|
|
|
|
// PHASE 0
|
|
// try to create new FileIdent & FileEntry in Dir2
|
|
|
|
RenameRetry:
|
|
if(!OS_SUCCESS(status = UDFCreateFile__(Vcb, IgnoreCase, fn, UDFGetFileEALength(FileInfo),
|
|
0, (FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY),
|
|
TRUE, DirInfo2, &FileInfo2))) {
|
|
UDFCleanUpFile__(Vcb, FileInfo2);
|
|
if(FileInfo2) MyFreePool__(FileInfo2);
|
|
if(status == STATUS_ACCESS_DENIED) {
|
|
// try to recover >;->
|
|
if((*Replace) && !Recovery) {
|
|
Recovery = TRUE;
|
|
status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL);
|
|
if(OS_SUCCESS(status)) {
|
|
status = UDFDoesOSAllowFileToBeTargetForRename__(FileInfo2);
|
|
if(!OS_SUCCESS(status)) {
|
|
UDFCloseFile__(Vcb, FileInfo2);
|
|
goto cleanup_and_abort_rename;
|
|
}
|
|
status = UDFUnlinkFile__(Vcb, FileInfo2, TRUE);
|
|
// UDFPretendFileDeleted__(Vcb, FileInfo2);
|
|
UDFCloseFile__(Vcb, FileInfo2);
|
|
if(UDFCleanUpFile__(Vcb, FileInfo2)) {
|
|
MyFreePool__(FileInfo2);
|
|
FileInfo2 = NULL;
|
|
if(SameFE)
|
|
return status;
|
|
} else {
|
|
// we get here if the FileInfo has associated
|
|
// system-specific Fcb
|
|
// Such fact means that not all system references
|
|
// has already gone (except Linked file case)
|
|
/* if(SameFE)
|
|
return status;*/
|
|
// UDFRemoveOSReferences__(FileInfo2);
|
|
if(!OS_SUCCESS(status) ||
|
|
(UDFGetFileLinkCount(FileInfo2) < 1))
|
|
status = STATUS_ACCESS_DENIED;
|
|
}
|
|
if(OS_SUCCESS(status)) goto RenameRetry;
|
|
}
|
|
cleanup_and_abort_rename:
|
|
if(FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) {
|
|
MyFreePool__(FileInfo2);
|
|
FileInfo2 = NULL;
|
|
}
|
|
} else {
|
|
status = STATUS_OBJECT_NAME_COLLISION;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
// update pointers
|
|
DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex, i = FileInfo->Index);
|
|
DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex, j = FileInfo2->Index);
|
|
|
|
// copy file attributes to newly created FileIdent
|
|
NTAttr = UDFAttributesToNT(DirNdx1, FileInfo->Dloc->FileEntry);
|
|
FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
|
|
// unlink source FileIdent
|
|
if(!OS_SUCCESS(status = UDFUnlinkFile__(Vcb, FileInfo, FALSE))) {
|
|
// kill newly created entry
|
|
UDFFlushFile__(Vcb, FileInfo2);
|
|
UDFUnlinkFile__(Vcb, FileInfo2, TRUE);
|
|
UDFCloseFile__(Vcb, FileInfo2);
|
|
UDFCleanUpFile__(Vcb, FileInfo2);
|
|
MyFreePool__(FileInfo2);
|
|
return status;
|
|
}
|
|
|
|
// PHASE 1
|
|
// drop all unnecessary info from FileInfo & flush FI
|
|
|
|
DirNdx1->FileInfo = NULL;
|
|
ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
UDFFlushFI(Vcb, FileInfo, UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation));
|
|
UDFInterlockedExchangeAdd((PLONG)&(DirInfo1->OpenCount),
|
|
-((LONG)(FileInfo->RefCount)));
|
|
// PHASE 2
|
|
// copy all necessary info from FileInfo to FileInfo2
|
|
|
|
FileInfo2->FileIdent->icb = FileInfo->FileIdent->icb;
|
|
FileInfo2->FileIdent->fileCharacteristics = FileInfo->FileIdent->fileCharacteristics;
|
|
FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
|
|
MyFreePool__(FileInfo->FileIdent);
|
|
FileInfo->FileIdent = NULL;
|
|
|
|
// PHASE 3
|
|
// copy all necessary info from FileInfo2 to FileInfo
|
|
|
|
DirNdx2->FileInfo = FileInfo;
|
|
DirNdx2->FileCharacteristics = DirNdx1->FileCharacteristics & ~FILE_DELETED;
|
|
DirNdx2->FileEntryLoc = DirNdx1->FileEntryLoc;
|
|
DirNdx2->FI_Flags = (DirNdx1->FI_Flags & ~UDF_FI_FLAG_SYS_ATTR) | UDF_FI_FLAG_FI_MODIFIED;
|
|
UDFInterlockedExchangeAdd((PLONG)&(DirInfo2->OpenCount),
|
|
FileInfo->RefCount - FileInfo2->RefCount);
|
|
|
|
UDFAttributesToUDF(DirNdx2, FileInfo2->Dloc->FileEntry, NTAttr);
|
|
|
|
FileInfo->Index = j;
|
|
FileInfo->FileIdent = FileInfo2->FileIdent;
|
|
FileInfo->FileIdentLen = FileInfo2->FileIdentLen;
|
|
FileInfo->ParentFile = DirInfo2;
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
|
|
((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation =
|
|
((icbtag*)(FileInfo2->Dloc->FileEntry+1))->parentICBLocation;
|
|
|
|
UDFIncFileLinkCount(FileInfo); // increase to 1
|
|
|
|
// UDFUpdateModifyTime(Vcb, FileInfo);
|
|
|
|
// PHASE 4
|
|
// drop all unnecessary info from FileInfo2
|
|
|
|
UDFFreeFESpace(Vcb, DirInfo2, &(FileInfo2->Dloc->FELoc));
|
|
UDFUnlinkDloc(Vcb, FileInfo2->Dloc);
|
|
UDFDecFileLinkCount(FileInfo2);
|
|
|
|
FileInfo2->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED;
|
|
/* MyFreePool__(FileInfo2->Dloc->FileEntry);
|
|
FileInfo2->Dloc->FileEntry = NULL;*/
|
|
FileInfo2->ParentFile = NULL;
|
|
FileInfo2->FileIdent = NULL;
|
|
FileInfo2->RefCount = 0;
|
|
FileInfo2->Dloc->LinkRefCount = 0;
|
|
ASSERT(FileInfo2->Dloc->DataLoc.Mapping);
|
|
FileInfo2->Dloc->DataLoc.Mapping[0].extLocation = 0;
|
|
FileInfo2->Dloc->DataLoc.Mapping[0].extLength = 0;
|
|
|
|
UDFCleanUpFile__(Vcb, FileInfo2);
|
|
MyFreePool__(FileInfo2);
|
|
|
|
// return 'delete target' status
|
|
(*Replace) = Recovery;
|
|
|
|
return STATUS_SUCCESS;
|
|
} // end UDFRenameMoveFile__()
|
|
|
|
/*
|
|
This routine transforms zero-sized file to directory
|
|
*/
|
|
OSSTATUS
|
|
UDFRecordDirectory__(
|
|
IN PVCB Vcb,
|
|
IN OUT PUDF_FILE_INFO DirInfo // source (opened)
|
|
)
|
|
{
|
|
OSSTATUS status;
|
|
LONG_AD FEicb;
|
|
UDF_FILE_INFO FileInfo;
|
|
UDF_DATALOC_INFO Dloc;
|
|
UNICODE_STRING PName;
|
|
uint32 PartNum;
|
|
SIZE_T WrittenBytes;
|
|
PDIR_INDEX_ITEM CurDirNdx;
|
|
uint32 lba;
|
|
|
|
// validate DirInfo
|
|
ValidateFileInfo(DirInfo);
|
|
if(DirInfo->ParentFile && UDFIsAStreamDir(DirInfo->ParentFile))
|
|
return STATUS_ACCESS_DENIED;
|
|
// file should be empty
|
|
if(UDFGetFileSize(DirInfo)) {
|
|
if( DirInfo->FileIdent &&
|
|
(DirInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) return STATUS_FILE_IS_A_DIRECTORY;
|
|
return STATUS_NOT_A_DIRECTORY;
|
|
}
|
|
if(DirInfo->Dloc->DirIndex) return STATUS_FILE_IS_A_DIRECTORY;
|
|
// create empty DirIndex
|
|
if(DirInfo->FileIdent) DirInfo->FileIdent->fileCharacteristics |= FILE_DIRECTORY;
|
|
if((CurDirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(DirInfo),DirInfo->Index)))
|
|
CurDirNdx->FileCharacteristics |= FILE_DIRECTORY;
|
|
((icbtag*)(DirInfo->Dloc->FileEntry+1))->fileType = UDF_FILE_TYPE_DIRECTORY;
|
|
// init temporary FileInfo
|
|
RtlZeroMemory(&FileInfo, sizeof(UDF_FILE_INFO));
|
|
FileInfo.Dloc = &Dloc;
|
|
FileInfo.Dloc->FileEntry = DirInfo->ParentFile->Dloc->FileEntry;
|
|
FileInfo.Dloc->FileEntryLen = DirInfo->ParentFile->Dloc->FileEntryLen;
|
|
FileInfo.Dloc->DataLoc = DirInfo->Dloc->DataLoc;
|
|
FileInfo.Dloc->FELoc = DirInfo->Dloc->FELoc;
|
|
FileInfo.ParentFile = DirInfo;
|
|
// prepare FileIdent for 'parent Dir'
|
|
lba = DirInfo->Dloc->FELoc.Mapping[0].extLocation;
|
|
ASSERT(lba);
|
|
PartNum = UDFGetPartNumByPhysLba(Vcb, lba);
|
|
FEicb.extLength = Vcb->LBlockSize;
|
|
FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, lba);
|
|
FEicb.extLocation.partitionReferenceNum = (uint16)PartNum;
|
|
RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse));
|
|
PName.Buffer = (PWCH)L"";
|
|
PName.Length = (PName.MaximumLength = sizeof(L"")) - sizeof(WCHAR);
|
|
if(!OS_SUCCESS(status =
|
|
UDFBuildFileIdent(Vcb, &PName, &FEicb, 0,
|
|
&(FileInfo.FileIdent), &(FileInfo.FileIdentLen)) ))
|
|
return status;
|
|
FileInfo.FileIdent->fileCharacteristics |= (FILE_PARENT | FILE_DIRECTORY);
|
|
UDFDecFileCounter(Vcb);
|
|
UDFIncDirCounter(Vcb);
|
|
// init structure
|
|
UDFSetUpTag(Vcb, &(FileInfo.FileIdent->descTag), (uint16)(FileInfo.FileIdentLen),
|
|
FEicb.extLocation.logicalBlockNum);
|
|
FileInfo.Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY; // for metadata
|
|
// flush
|
|
status = UDFWriteFile__(Vcb, DirInfo, 0, FileInfo.FileIdentLen, FALSE, (int8*)(FileInfo.FileIdent), &WrittenBytes);
|
|
// status = UDFFlushFI(Vcb, &FileInfo, PartNum);
|
|
|
|
#ifdef UDF_DBG
|
|
if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
|
|
ASSERT(UDFGetFileSize(DirInfo) <= UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping));
|
|
} else {
|
|
ASSERT(((UDFGetFileSize(DirInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
|
|
((UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
|
|
}
|
|
#endif // UDF_DBG
|
|
|
|
MyFreePool__(FileInfo.FileIdent);
|
|
if(!OS_SUCCESS(status)) return status;
|
|
if(CurDirNdx) CurDirNdx->FileCharacteristics =
|
|
DirInfo->FileIdent->fileCharacteristics;
|
|
return UDFIndexDirectory(Vcb, DirInfo);
|
|
} // end UDFRecordDirectory__()
|
|
|
|
/*
|
|
This routine changes file size (on disc)
|
|
*/
|
|
OSSTATUS
|
|
UDFResizeFile__(
|
|
IN PVCB Vcb,
|
|
IN OUT PUDF_FILE_INFO FileInfo,
|
|
IN int64 NewLength
|
|
)
|
|
{
|
|
SIZE_T WrittenBytes;
|
|
OSSTATUS status;
|
|
uint32 PartNum;
|
|
int8* OldInIcb = NULL;
|
|
PEXTENT_MAP NewMap;
|
|
|
|
UDFPrint(("UDFResizeFile__: FI %x, -> %I64x\n", FileInfo, NewLength));
|
|
ValidateFileInfo(FileInfo);
|
|
// ASSERT(FileInfo->RefCount >= 1);
|
|
|
|
if((NewLength >> Vcb->LBlockSizeBits) > Vcb->TotalAllocUnits) {
|
|
UDFPrint(("STATUS_DISK_FULL\n"));
|
|
return STATUS_DISK_FULL;
|
|
}
|
|
if (NewLength == FileInfo->Dloc->DataLoc.Length) return STATUS_SUCCESS;
|
|
if(FileInfo->ParentFile && (FileInfo->Index >= 2)) {
|
|
UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex,FileInfo->Index)->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
|
|
}
|
|
if(NewLength > FileInfo->Dloc->DataLoc.Length) {
|
|
// grow file
|
|
return UDFWriteFile__(Vcb, FileInfo, NewLength, 0, FALSE, NULL, &WrittenBytes);
|
|
}
|
|
// truncate file
|
|
if(NewLength <= (Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen)) {
|
|
// check if we are already in IN_ICB mode
|
|
if((((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) != ICB_FLAG_AD_IN_ICB) {
|
|
// read data from old location
|
|
if(NewLength) {
|
|
OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)NewLength);
|
|
if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES;
|
|
status = UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes);
|
|
if(!OS_SUCCESS(status)) {
|
|
MyFreePool__(OldInIcb);
|
|
return status;
|
|
}
|
|
} else {
|
|
OldInIcb = NULL;
|
|
}
|
|
// allocate storage for new mapping
|
|
NewMap = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , 2*sizeof(EXTENT_MAP),
|
|
MEM_EXTMAP_TAG);
|
|
if(!(NewMap)) {
|
|
MyFreePool__(OldInIcb);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
// free old location...
|
|
if(FileInfo->Dloc->DataLoc.Mapping[0].extLocation !=
|
|
FileInfo->Dloc->FELoc.Mapping[0].extLocation) {
|
|
ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
mark_data_map_0:
|
|
UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free
|
|
} else {
|
|
if((FileInfo->Dloc->DataLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK)
|
|
> Vcb->LBlockSize) {
|
|
BrutePoint();
|
|
FileInfo->Dloc->DataLoc.Mapping[0].extLength -= Vcb->LBlockSize;
|
|
FileInfo->Dloc->DataLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits);
|
|
goto mark_data_map_0;
|
|
}
|
|
UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free
|
|
}
|
|
if(FileInfo->Dloc->AllocLoc.Mapping) {
|
|
if((FileInfo->Dloc->AllocLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK)
|
|
> Vcb->LBlockSize) {
|
|
FileInfo->Dloc->AllocLoc.Mapping[0].extLength -= Vcb->LBlockSize;
|
|
FileInfo->Dloc->AllocLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits);
|
|
UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->AllocLoc.Mapping, AS_DISCARDED); // free
|
|
} else {
|
|
UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
|
|
}
|
|
MyFreePool__(FileInfo->Dloc->AllocLoc.Mapping);
|
|
}
|
|
MyFreePool__(FileInfo->Dloc->DataLoc.Mapping);
|
|
FileInfo->Dloc->AllocLoc.Mapping = NULL;
|
|
FileInfo->Dloc->AllocLoc.Length = 0;
|
|
FileInfo->Dloc->AllocLoc.Offset = 0;
|
|
FileInfo->Dloc->AllocLoc.Modified = TRUE;
|
|
// switch to IN_ICB mode
|
|
((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
|
|
((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB;
|
|
// init new data location descriptors
|
|
FileInfo->Dloc->DataLoc.Mapping = NewMap;
|
|
RtlZeroMemory((int8*)(FileInfo->Dloc->DataLoc.Mapping), 2*sizeof(EXTENT_MAP));
|
|
FileInfo->Dloc->DataLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0];
|
|
FileInfo->Dloc->DataLoc.Length = NewLength;
|
|
FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
|
|
// write data to new location
|
|
if(OldInIcb) {
|
|
status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes);
|
|
} else {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
FileInfo->Dloc->DataLoc.Modified = TRUE;
|
|
if(OldInIcb) MyFreePool__(OldInIcb);
|
|
} else {
|
|
// just modify Length field
|
|
FileInfo->Dloc->DataLoc.Length = NewLength;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
// resize extent
|
|
ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
status = UDFResizeExtent(Vcb, PartNum, NewLength, FALSE, &(FileInfo->Dloc->DataLoc));
|
|
FileInfo->Dloc->DataLoc.Modified = TRUE;
|
|
FileInfo->Dloc->AllocLoc.Modified = TRUE;
|
|
}
|
|
if(OS_SUCCESS(status)) {
|
|
UDFSetFileSize(FileInfo, NewLength);
|
|
}
|
|
|
|
#ifdef UDF_DBG
|
|
if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
|
|
ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
|
|
} else {
|
|
ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
|
|
((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
|
|
}
|
|
#endif // UDF_DBG
|
|
|
|
return status;
|
|
} // end UDFResizeFile__()
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
/*
|
|
This routine loads VAT.
|
|
*/
|
|
OSSTATUS
|
|
UDFLoadVAT(
|
|
IN PVCB Vcb,
|
|
IN uint32 PartNdx
|
|
)
|
|
{
|
|
lb_addr VatFELoc;
|
|
OSSTATUS status;
|
|
PUDF_FILE_INFO VatFileInfo;
|
|
uint32 len, i=0, j, to_read;
|
|
uint32 Offset, hdrOffset;
|
|
SIZE_T ReadBytes;
|
|
uint32 root;
|
|
uint16 PartNum;
|
|
// uint32 VatFirstLba = 0;
|
|
int8* VatOldData;
|
|
uint32 VatLba[6] = { Vcb->LastLBA,
|
|
Vcb->LastLBA - 2,
|
|
Vcb->LastLBA - 3,
|
|
Vcb->LastLBA - 5,
|
|
Vcb->LastLBA - 7,
|
|
0 };
|
|
|
|
if(Vcb->Vat) return STATUS_SUCCESS;
|
|
if(!Vcb->CDR_Mode) return STATUS_SUCCESS;
|
|
// disable VAT for now. We'll reenable it if VAT is successfuly loaded
|
|
Vcb->CDR_Mode = FALSE;
|
|
PartNum = Vcb->Partitions[PartNdx].PartitionNum;
|
|
root = Vcb->Partitions[PartNdx].PartitionRoot;
|
|
if(Vcb->LBlockSize != Vcb->BlockSize) {
|
|
// don't know how to operate... :(((
|
|
return STATUS_UNRECOGNIZED_VOLUME;
|
|
}
|
|
if((Vcb->LastTrackNum > 1) &&
|
|
(Vcb->LastLBA == Vcb->TrackMap[Vcb->LastTrackNum-1].LastLba)) {
|
|
UDFPrint(("Hardware Read-only volume\n"));
|
|
Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
|
|
}
|
|
|
|
VatFileInfo = Vcb->VatFileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT, sizeof(UDF_FILE_INFO), MEM_VATFINF_TAG);
|
|
if(!VatFileInfo) return STATUS_INSUFFICIENT_RESOURCES;
|
|
// load VAT FE (we know its location)
|
|
VatFELoc.partitionReferenceNum = PartNum;
|
|
retry_load_vat:
|
|
VatFELoc.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, VatLba[i]);
|
|
if(!OS_SUCCESS(status = UDFOpenRootFile__(Vcb, &VatFELoc, VatFileInfo))) {
|
|
UDFCleanUpFile__(Vcb, VatFileInfo);
|
|
// try another location
|
|
i++;
|
|
if( VatLba[i] &&
|
|
(status != STATUS_FILE_CORRUPT_ERROR) &&
|
|
(status != STATUS_CRC_ERROR)) goto retry_load_vat;
|
|
MyFreePool__(VatFileInfo);
|
|
Vcb->VatFileInfo = NULL;
|
|
return status;
|
|
}
|
|
len = (uint32)UDFGetFileSize(VatFileInfo);
|
|
if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP15) {
|
|
// load Vat 1.50 header
|
|
UDFPrint(("Load VAT 1.50\n"));
|
|
VirtualAllocationTable15* Buf;
|
|
if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT15) {
|
|
status = STATUS_FILE_CORRUPT_ERROR;
|
|
goto err_vat_15;
|
|
}
|
|
Buf = (VirtualAllocationTable15*)MyAllocatePool__(NonPagedPool, sizeof(VirtualAllocationTable15));
|
|
if(!Buf) {
|
|
err_vat_15_2:
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
err_vat_15:
|
|
UDFCloseFile__(Vcb, VatFileInfo);
|
|
UDFCleanUpFile__(Vcb, VatFileInfo);
|
|
MyFreePool__(VatFileInfo);
|
|
Vcb->VatFileInfo = NULL;
|
|
return status;
|
|
}
|
|
Offset = 0;
|
|
to_read =
|
|
hdrOffset = len - sizeof(VirtualAllocationTable15);
|
|
MyFreePool__(Buf);
|
|
|
|
Vcb->minUDFReadRev =
|
|
Vcb->minUDFWriteRev =
|
|
Vcb->maxUDFWriteRev = 0x0150;
|
|
|
|
Vcb->numFiles =
|
|
Vcb->numDirs = -1;
|
|
|
|
} else
|
|
if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP20) {
|
|
// load Vat 2.00 header
|
|
UDFPrint(("Load VAT 2.00\n"));
|
|
VirtualAllocationTable20* Buf;
|
|
if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT20) {
|
|
status = STATUS_FILE_CORRUPT_ERROR;
|
|
goto err_vat_15;
|
|
}
|
|
Buf = (VirtualAllocationTable20*)MyAllocatePool__(NonPagedPool, sizeof(VirtualAllocationTable20));
|
|
if(!Buf) goto err_vat_15_2;
|
|
Offset = Buf->lengthHeader;
|
|
to_read = len - Offset;
|
|
hdrOffset = 0;
|
|
MyFreePool__(Buf);
|
|
|
|
Vcb->minUDFReadRev = Buf->minReadRevision;
|
|
Vcb->minUDFWriteRev = Buf->minWriteRevision;
|
|
Vcb->maxUDFWriteRev = Buf->maxWriteRevision;
|
|
|
|
Vcb->numFiles = Buf->numFIDSFiles;
|
|
Vcb->numDirs = Buf->numFIDSDirectories;
|
|
|
|
} else {
|
|
// unknown (or wrong) VAT format
|
|
UDFPrint(("unknown (or wrong) VAT format\n"));
|
|
status = STATUS_FILE_CORRUPT_ERROR;
|
|
goto err_vat_15;
|
|
}
|
|
// read VAT & remember old version
|
|
Vcb->Vat = (uint32*)DbgAllocatePool(NonPagedPool, (Vcb->LastPossibleLBA+1)*sizeof(uint32) );
|
|
if(!Vcb->Vat) {
|
|
goto err_vat_15_2;
|
|
}
|
|
// store base version of VAT in memory
|
|
VatOldData = (int8*)DbgAllocatePool(PagedPool, len);
|
|
if(!VatOldData) {
|
|
DbgFreePool(Vcb->Vat);
|
|
Vcb->Vat = NULL;
|
|
goto err_vat_15_2;
|
|
}
|
|
status = UDFReadFile__(Vcb, VatFileInfo, 0, len, FALSE, VatOldData, &ReadBytes);
|
|
if(!OS_SUCCESS(status)) {
|
|
UDFCloseFile__(Vcb, VatFileInfo);
|
|
UDFCleanUpFile__(Vcb, VatFileInfo);
|
|
MyFreePool__(VatFileInfo);
|
|
DbgFreePool(Vcb->Vat);
|
|
DbgFreePool(VatOldData);
|
|
Vcb->Vat = NULL;
|
|
Vcb->VatFileInfo = NULL;
|
|
} else {
|
|
// initialize VAT
|
|
// !!! NOTE !!!
|
|
// Both VAT copies - in-memory & on-disc
|
|
// contain _relative_ addresses
|
|
len = Vcb->NWA - root;
|
|
for(i=0; i<=len; i++) {
|
|
Vcb->Vat[i] = i;
|
|
}
|
|
RtlCopyMemory(Vcb->Vat, VatOldData+Offset, to_read);
|
|
Vcb->InitVatCount =
|
|
Vcb->VatCount = to_read/sizeof(uint32);
|
|
Vcb->VatPartNdx = PartNdx;
|
|
Vcb->CDR_Mode = TRUE;
|
|
len = Vcb->VatCount;
|
|
RtlFillMemory(&(Vcb->Vat[Vcb->NWA-root]), (Vcb->LastPossibleLBA-Vcb->NWA+1)*sizeof(uint32), 0xff);
|
|
// sync VAT and FSBM
|
|
for(i=0; i<len; i++) {
|
|
if(Vcb->Vat[i] == UDF_VAT_FREE_ENTRY) {
|
|
UDFSetFreeBit(Vcb->FSBM_Bitmap, root+i);
|
|
}
|
|
}
|
|
len = Vcb->LastPossibleLBA;
|
|
// "pre-format" reserved area
|
|
for(i=Vcb->NWA; i<len;) {
|
|
for(j=0; (j<PACKETSIZE_UDF) && (i<len); j++, i++)
|
|
UDFSetFreeBit(Vcb->FSBM_Bitmap, i);
|
|
for(j=0; (j<7) && (i<len); j++, i++)
|
|
UDFSetUsedBit(Vcb->FSBM_Bitmap, i);
|
|
}
|
|
DbgFreePool(VatOldData);
|
|
}
|
|
return status;
|
|
} // end UDFLoadVAT()
|
|
|
|
/*
|
|
Reads Extended Attributes
|
|
Caller should use UDFGetFileEALength to allocate Buffer of sufficient
|
|
size
|
|
*//*
|
|
OSSTATUS
|
|
UDFReadFileEA(
|
|
IN PVCB Vcb,
|
|
IN PDIR_INDEX FileDirNdx,
|
|
OUT int8* Buffer
|
|
)
|
|
{
|
|
PFILE_ENTRY FileEntry;
|
|
OSSTATUS status;
|
|
|
|
if(FileDirNdx->FileInfo) {
|
|
FileEntry = (PFILE_ENTRY)(FileDirNdx->FileInfo->Dloc->FileEntry);
|
|
} else {
|
|
FileEntry = (PFILE_ENTRY)MyAllocatePool__(NonPagedPool, Vcb->BlockSize);
|
|
if(!FileEntry) return;
|
|
if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileDirNdx->FileEntry), FileEntry, &Ident))) {
|
|
MyFreePool__(FileEntry);
|
|
return status;
|
|
}
|
|
}
|
|
}*/
|
|
/*
|
|
This dumb routine checks if the file has been found is deleted
|
|
It is introduced to make main modules FS-type independent
|
|
*/
|
|
/*BOOLEAN
|
|
UDFIsDeleted(
|
|
IN PDIR_INDEX DirNdx
|
|
)
|
|
{
|
|
return (DirNdx->FileCharacteristics & FILE_DELETED);
|
|
} */
|
|
|
|
/*BOOLEAN
|
|
UDFIsADirectory(
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
if(!FileInfo) return FALSE;
|
|
if(FileInfo->Dloc->DirIndex) return TRUE;
|
|
if(!(FileInfo->FileIdent)) return FALSE;
|
|
return (FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY);
|
|
} */
|
|
/*
|
|
This routine calculates actual allocation size
|
|
*/
|
|
/*int64
|
|
UDFGetFileAllocationSize(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
return UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping);// +
|
|
// UDFGetExtentLength(FileInfo->Dloc->FELoc.Mapping) +
|
|
// UDFGetExtentLength(FileInfo->Dloc->AllocLoc.Mapping) - Vcb->BlockSize;
|
|
}*/
|
|
|
|
/*
|
|
This routine checks if the directory is empty
|
|
*/
|
|
BOOLEAN
|
|
UDFIsDirEmpty(
|
|
IN PDIR_INDEX_HDR hCurDirNdx
|
|
)
|
|
{
|
|
uint32 fc;
|
|
uint_di i;
|
|
PDIR_INDEX_ITEM CurDirNdx;
|
|
// not empty
|
|
for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) {
|
|
fc = CurDirNdx->FileCharacteristics;
|
|
if(!(fc & (FILE_PARENT | FILE_DELETED)) &&
|
|
CurDirNdx->Length)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
} // end UDFIsDirEmpty()
|
|
|
|
/*
|
|
*/
|
|
OSSTATUS
|
|
UDFFlushFE(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN uint32 PartNum
|
|
)
|
|
{
|
|
int8* NewAllocDescs;
|
|
OSSTATUS status;
|
|
SIZE_T WrittenBytes;
|
|
uint16 AllocMode;
|
|
uint32 lba;
|
|
|
|
AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
|
|
#ifdef UDF_DBG
|
|
/* if(UDFIsADirectory(FileInfo) && (UDFGetFileSize(FileInfo) < 0x28) &&
|
|
!UDFIsDeleted(UDFDirIndex(DirInfo->Dloc->DirIndex, FileInfo->Index)) ) {
|
|
BrutePoint();
|
|
}*/
|
|
// ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
if(FileInfo->Dloc->FELoc.Offset) {
|
|
BrutePoint();
|
|
}
|
|
if(FileInfo->Dloc->AllocLoc.Mapping) {
|
|
ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB);
|
|
}
|
|
#endif // UDF_DBG
|
|
retry_flush_FE:
|
|
UDFPrint((" FlushFE: %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
UDFReTagDirectory(Vcb, FileInfo);
|
|
if(FileInfo->Dloc->DataLoc.Modified ||
|
|
FileInfo->Dloc->AllocLoc.Modified) {
|
|
ASSERT(PartNum != (uint32)(-1));
|
|
// prepare new AllocDescs for flushing...
|
|
if(!OS_SUCCESS(status = UDFBuildAllocDescs(Vcb, PartNum, FileInfo, &NewAllocDescs))) {
|
|
UDFPrint((" FlushFE: UDFBuildAllocDescs() faliled (%x)\n", status));
|
|
if(NewAllocDescs)
|
|
MyFreePool__(NewAllocDescs);
|
|
return status;
|
|
}
|
|
#ifdef UDF_DBG
|
|
if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
|
|
ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
|
|
} else {
|
|
ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
|
|
((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
|
|
}
|
|
AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
|
|
#endif // UDF_DBG
|
|
// initiate update of lengthAllocDescs
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
if(NewAllocDescs) {
|
|
ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB);
|
|
status = UDFPadLastSector(Vcb, &(FileInfo->Dloc->AllocLoc));
|
|
// ... and flush it
|
|
status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->AllocLoc), 0, (uint32)(FileInfo->Dloc->AllocLoc.Length), FALSE, NewAllocDescs, &WrittenBytes);
|
|
MyFreePool__(NewAllocDescs);
|
|
if(!OS_SUCCESS(status)) {
|
|
UDFPrint((" FlushFE: UDFWriteExtent() faliled (%x)\n", status));
|
|
return status;
|
|
}
|
|
#ifdef UDF_DBG
|
|
} else {
|
|
ASSERT(AllocMode == ICB_FLAG_AD_IN_ICB);
|
|
#endif // UDF_DBG
|
|
}
|
|
FileInfo->Dloc->DataLoc.Modified = FALSE;
|
|
FileInfo->Dloc->AllocLoc.Modified = FALSE;
|
|
} else {
|
|
#if defined(UDF_DBG) && !defined(UDF_CHECK_UTIL)
|
|
if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
|
|
ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
|
|
} else {
|
|
ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
|
|
((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
|
|
}
|
|
#endif // UDF_DBG
|
|
}
|
|
/* if(FileInfo->Fcb &&
|
|
((FileInfo->Dloc->FELoc.Mapping[0].extLocation > Vcb->LastLBA) ||
|
|
UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) ) {
|
|
BrutePoint();
|
|
}*/
|
|
/* if(FileInfo->Dloc->FELoc.Mapping[0].extLocation) {
|
|
ASSERT( FileInfo->Dloc->FileEntry->tagLocation ==
|
|
(FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580));
|
|
}*/
|
|
if((FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
|
|
FileInfo->Dloc->FELoc.Modified) {
|
|
ASSERT(PartNum != (uint32)(-1));
|
|
ASSERT(!PartNum);
|
|
if(PartNum == (uint32)(-1) || PartNum == (uint32)(-2)) {
|
|
UDFPrint((" bad PartNum: %d\n", PartNum));
|
|
}
|
|
// update lengthAllocDescs in FE
|
|
UDFSetAllocDescLen(Vcb, FileInfo);
|
|
/* ASSERT( FileInfo->Dloc->FileEntry->tagLocation ==
|
|
(FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580));*/
|
|
// flush FileEntry
|
|
|
|
// if FE is located in remapped block, place it to reliable space
|
|
lba = FileInfo->Dloc->FELoc.Mapping[0].extLocation;
|
|
if(Vcb->BSBM_Bitmap) {
|
|
if(UDFGetBadBit((uint32*)(Vcb->BSBM_Bitmap), lba)) {
|
|
AdPrint((" bad block under FE @%x\n", lba));
|
|
goto relocate_FE;
|
|
}
|
|
}
|
|
|
|
AdPrint((" setup tag: @%x\n", lba));
|
|
ASSERT( lba );
|
|
UDFSetUpTag(Vcb, FileInfo->Dloc->FileEntry, (uint16)(FileInfo->Dloc->FileEntryLen),
|
|
UDFPhysLbaToPart(Vcb, PartNum, lba));
|
|
status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->FELoc), 0,
|
|
(uint32)(FileInfo->Dloc->FELoc.Length), FALSE,
|
|
(int8*)(FileInfo->Dloc->FileEntry), &WrittenBytes);
|
|
if(!OS_SUCCESS(status)) {
|
|
UDFPrint((" FlushFE: UDFWriteExtent(2) faliled (%x)\n", status));
|
|
if(status == STATUS_DEVICE_DATA_ERROR) {
|
|
relocate_FE:
|
|
UDFPrint((" try to relocate\n"));
|
|
|
|
EXTENT_INFO _FEExtInfo;
|
|
// calculate the length required
|
|
|
|
// allocate block for FE
|
|
if(OS_SUCCESS(UDFAllocateFESpace(Vcb, FileInfo->ParentFile, PartNum, &_FEExtInfo, (uint32)(FileInfo->Dloc->FELoc.Length)) )) {
|
|
UDFPrint((" relocate %x -> %x\n",
|
|
lba,
|
|
_FEExtInfo.Mapping[0].extLocation));
|
|
|
|
UDFMarkSpaceAsXXX(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_BAD);
|
|
|
|
UDFRelocateDloc(Vcb, FileInfo->Dloc, _FEExtInfo.Mapping[0].extLocation);
|
|
MyFreePool__(FileInfo->Dloc->FELoc.Mapping);
|
|
FileInfo->Dloc->FELoc.Mapping = _FEExtInfo.Mapping;
|
|
|
|
FileInfo->Dloc->FELoc.Modified = TRUE;
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
|
|
AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
|
|
if(AllocMode == ICB_FLAG_AD_IN_ICB) {
|
|
UDFPrint((" IN-ICB data lost\n"));
|
|
FileInfo->Dloc->DataLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation;
|
|
FileInfo->Dloc->DataLoc.Modified = TRUE;
|
|
} else {
|
|
FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation;
|
|
FileInfo->Dloc->AllocLoc.Modified = TRUE;
|
|
}
|
|
|
|
if(FileInfo->Index >= 2) {
|
|
PDIR_INDEX_ITEM DirNdx;
|
|
DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index);
|
|
if(DirNdx) {
|
|
UDFPrint((" update reference in FI\n"));
|
|
DirNdx->FileEntryLoc.logicalBlockNum =
|
|
FileInfo->FileIdent->icb.extLocation.logicalBlockNum =
|
|
UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation);
|
|
DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
|
|
}
|
|
}
|
|
// this will update
|
|
UDFPrint((" retry flush...\n"));
|
|
goto retry_flush_FE;
|
|
}
|
|
}
|
|
BrutePoint();
|
|
return status;
|
|
}
|
|
FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED;
|
|
FileInfo->Dloc->FELoc.Modified = FALSE;
|
|
} else {
|
|
ASSERT((FileInfo->Dloc->FileEntry->descVersion == 2) ||
|
|
(FileInfo->Dloc->FileEntry->descVersion == 3));
|
|
}
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
#ifdef UDF_DBG
|
|
if(FileInfo->Dloc->AllocLoc.Mapping) {
|
|
ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB);
|
|
} else {
|
|
ASSERT(AllocMode == ICB_FLAG_AD_IN_ICB);
|
|
}
|
|
#endif // UDF_DBG
|
|
return STATUS_SUCCESS;
|
|
} // end UDFFlushFE()
|
|
|
|
OSSTATUS
|
|
UDFFlushFI(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN uint32 PartNum
|
|
)
|
|
{
|
|
PUDF_FILE_INFO DirInfo = FileInfo->ParentFile;
|
|
PDIR_INDEX_ITEM DirNdx;
|
|
OSSTATUS status;
|
|
SIZE_T WrittenBytes;
|
|
// use WrittenBytes variable to store LBA of FI to be recorded
|
|
#define lba WrittenBytes
|
|
|
|
// ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
// some files has no FI
|
|
if(!DirInfo || UDFIsAStreamDir(FileInfo))
|
|
return STATUS_SUCCESS;
|
|
DirNdx = UDFDirIndex(DirInfo->Dloc->DirIndex, FileInfo->Index);
|
|
// ASSERT(FileInfo->FileIdent->lengthFileIdent < 0x80);
|
|
#ifdef UDF_DBG
|
|
if(DirNdx->FileCharacteristics & FILE_DELETED) {
|
|
ASSERT(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED);
|
|
}
|
|
#endif // UDF_DBG
|
|
UDFPrint((" FlushFI: offs %x\n", (ULONG)(DirNdx->Offset)));
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
if((DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) {
|
|
// flush FileIdent
|
|
ASSERT(PartNum != (uint32)(-1));
|
|
FileInfo->FileIdent->fileCharacteristics = DirNdx->FileCharacteristics;
|
|
lba = UDFExtentOffsetToLba(Vcb, DirInfo->Dloc->DataLoc.Mapping,
|
|
DirNdx->Offset, NULL, NULL, NULL, NULL);
|
|
AdPrint((" FI lba %x\n", lba));
|
|
// check if requested Offset is allocated
|
|
if(lba == (uint32)LBA_OUT_OF_EXTENT) {
|
|
// write 1 byte
|
|
if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, 1, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) {
|
|
BrutePoint();
|
|
return status;
|
|
}
|
|
lba = UDFExtentOffsetToLba(Vcb, DirInfo->Dloc->DataLoc.Mapping,
|
|
DirNdx->Offset, NULL, NULL, NULL, NULL);
|
|
AdPrint((" allocated FI lba %x\n", lba));
|
|
// check if requested Offset is allocated
|
|
if(lba == (uint32)LBA_OUT_OF_EXTENT) {
|
|
BrutePoint();
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
// init structure
|
|
UDFSetUpTag(Vcb, &(FileInfo->FileIdent->descTag), (uint16)(FileInfo->FileIdentLen),
|
|
UDFPhysLbaToPart(Vcb, PartNum, lba));
|
|
// record data
|
|
if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, FileInfo->FileIdentLen, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) {
|
|
BrutePoint();
|
|
return status;
|
|
}
|
|
DirNdx->FI_Flags &= ~UDF_FI_FLAG_FI_MODIFIED;
|
|
}
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
return STATUS_SUCCESS;
|
|
} // end UDFFlushFI()
|
|
|
|
/*
|
|
This routine updates AllocDesc sequence, FileIdent & FileEntry
|
|
for given file
|
|
*/
|
|
OSSTATUS
|
|
UDFFlushFile__(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN ULONG FlushFlags
|
|
)
|
|
{
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
if(!FileInfo) return STATUS_SUCCESS;
|
|
OSSTATUS status;
|
|
uint32 PartNum;
|
|
|
|
ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
if(PartNum == (uint32)-1) {
|
|
UDFPrint((" Is DELETED ?\n"));
|
|
if(FileInfo->ParentFile) {
|
|
PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation);
|
|
} else {
|
|
BrutePoint();
|
|
}
|
|
}
|
|
#ifdef UDF_CHECK_DISK_ALLOCATION
|
|
if( FileInfo->Fcb &&
|
|
UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
|
|
|
|
if(UDFIsAStreamDir(FileInfo)) {
|
|
if(!UDFIsSDirDeleted(FileInfo)) {
|
|
UDFPrint((" Not DELETED SDir\n"));
|
|
BrutePoint();
|
|
}
|
|
ASSERT(!FileInfo->Dloc->FELoc.Modified);
|
|
} else
|
|
if(!FileInfo->FileIdent ||
|
|
!(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
|
|
if(!FileInfo->FileIdent)
|
|
AdPrint((" No FileIdent\n"));
|
|
if(FileInfo->FileIdent &&
|
|
!(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED))
|
|
AdPrint((" Not DELETED\n"));
|
|
AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
|
|
BrutePoint();
|
|
}
|
|
}
|
|
#endif // UDF_CHECK_DISK_ALLOCATION
|
|
|
|
// flush FE and pre-allocation charge for directories
|
|
if(FileInfo->Dloc &&
|
|
FileInfo->Dloc->DirIndex) {
|
|
// if Lite Flush is used, keep preallocations
|
|
if(!(FlushFlags & UDF_FLUSH_FLAGS_LITE)) {
|
|
full_flush:
|
|
UDFFlushFESpace(Vcb, FileInfo->Dloc);
|
|
if(FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) {
|
|
FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED;
|
|
status = UDFResizeExtent(Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc));
|
|
FileInfo->Dloc->DataLoc.Flags &= ~(EXTENT_FLAG_PREALLOCATED | EXTENT_FLAG_CUT_PREALLOCATED);
|
|
if(OS_SUCCESS(status)) {
|
|
AdPrint(("Dir pre-alloc truncated (Flush)\n"));
|
|
FileInfo->Dloc->DataLoc.Modified = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// flush FE
|
|
if(!OS_SUCCESS(status = UDFFlushFE(Vcb, FileInfo, PartNum))) {
|
|
UDFPrint(("Error flushing FE\n"));
|
|
BrutePoint();
|
|
if(FlushFlags & UDF_FLUSH_FLAGS_LITE) {
|
|
UDFPrint((" flush pre-alloc\n"));
|
|
FlushFlags &= ~UDF_FLUSH_FLAGS_LITE;
|
|
goto full_flush;
|
|
}
|
|
if(FileInfo->Index >= 2) {
|
|
PDIR_INDEX_ITEM DirNdx;
|
|
DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index);
|
|
if(DirNdx) {
|
|
UDFPrint(("Recovery: mark as deleted & flush FI\n"));
|
|
DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
|
|
DirNdx->FileCharacteristics |= FILE_DELETED;
|
|
FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
|
|
UDFFlushFI(Vcb, FileInfo, PartNum);
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
if(!OS_SUCCESS(status = UDFFlushFI(Vcb, FileInfo, PartNum)))
|
|
return status;
|
|
|
|
ASSERT((FileInfo->Dloc->FileEntry->descVersion == 2) ||
|
|
(FileInfo->Dloc->FileEntry->descVersion == 3));
|
|
|
|
return STATUS_SUCCESS;
|
|
} // end UDFFlushFile__()
|
|
|
|
/*
|
|
This routine compares 2 FileInfo structures
|
|
*/
|
|
BOOLEAN
|
|
UDFCompareFileInfo(
|
|
IN PUDF_FILE_INFO f1,
|
|
IN PUDF_FILE_INFO f2
|
|
)
|
|
{
|
|
uint_di i;
|
|
PDIR_INDEX_HDR hDirIndex1;
|
|
PDIR_INDEX_HDR hDirIndex2;
|
|
PDIR_INDEX_ITEM DirIndex1;
|
|
PDIR_INDEX_ITEM DirIndex2;
|
|
|
|
if(!f1 || !f2) return FALSE;
|
|
if(f1->Dloc->FileEntryLen != f2->Dloc->FileEntryLen) return FALSE;
|
|
// if(f1->FileIdentLen != f2->FileIdentLen) return FALSE;
|
|
/* if(f1->Dloc->DirIndex && !f2->Dloc->DirIndex) return FALSE;
|
|
if(f2->Dloc->DirIndex && !f1->Dloc->DirIndex) return FALSE;
|
|
if((f1->Dloc->DirIndex) &&
|
|
(f1->Dloc->DirIndex->LastFrameCount != f2->Dloc->DirIndex->LastFrameCount)) return FALSE;*/
|
|
if(f1->Index != f2->Index) return FALSE;
|
|
if(!(f1->Dloc->DataLoc.Mapping)) return FALSE;
|
|
if(!(f2->Dloc->DataLoc.Mapping)) return FALSE;
|
|
if(f1->Dloc->DataLoc.Mapping[0].extLocation != f2->Dloc->DataLoc.Mapping[0].extLocation) return FALSE;
|
|
if(f1->Dloc->DataLoc.Mapping[0].extLength != f2->Dloc->DataLoc.Mapping[0].extLength) return FALSE;
|
|
// if(f1-> != f2->) return FALSE;
|
|
// if(f1-> != f2->) return FALSE;
|
|
// if(f1-> != f2->) return FALSE;
|
|
if(!(f1->Dloc->FileEntry)) return FALSE;
|
|
if(!(f2->Dloc->FileEntry)) return FALSE;
|
|
if(RtlCompareMemory(f1->Dloc->FileEntry, f2->Dloc->FileEntry, f2->Dloc->FileEntryLen) != f2->Dloc->FileEntryLen)
|
|
return FALSE;
|
|
if(!(hDirIndex1 = f1->Dloc->DirIndex)) return FALSE;
|
|
if(!(hDirIndex2 = f2->Dloc->DirIndex)) return FALSE;
|
|
|
|
for(i=2; (DirIndex1 = UDFDirIndex(hDirIndex1,i)) &&
|
|
(DirIndex2 = UDFDirIndex(hDirIndex2,i)); i++) {
|
|
if( DirIndex1->FName.Buffer &&
|
|
!DirIndex2->FName.Buffer)
|
|
return FALSE;
|
|
if( DirIndex2->FName.Buffer &&
|
|
!DirIndex1->FName.Buffer)
|
|
return FALSE;
|
|
if(!DirIndex2->FName.Buffer &&
|
|
!DirIndex1->FName.Buffer)
|
|
continue;
|
|
if(RtlCompareUnicodeString(&(DirIndex1->FName),
|
|
&(DirIndex2->FName),FALSE)) {
|
|
return FALSE;
|
|
}
|
|
// if(DirIndex1[i].FileEntry != DirIndex2[i].FileEntry)
|
|
// return FALSE;
|
|
if(RtlCompareMemory(&(DirIndex1->FileEntryLoc),
|
|
&(DirIndex2->FileEntryLoc), sizeof(lb_addr)) != sizeof(lb_addr))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
} // end UDFCompareFileInfo()
|
|
|
|
/*
|
|
This routine computes 32-bit hash based on CRC-32 from SSH
|
|
*/
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4035) // re-enable below
|
|
#endif
|
|
|
|
#if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
|
|
__declspec (naked)
|
|
#endif // _X86_
|
|
uint32
|
|
__fastcall
|
|
crc32(
|
|
IN uint8* s, // ECX
|
|
IN uint32 len // EDX
|
|
)
|
|
{
|
|
#if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
|
|
// uint32 _Size = len;
|
|
|
|
__asm {
|
|
push ebx
|
|
push ecx
|
|
push edx
|
|
push esi
|
|
|
|
xor eax,eax
|
|
mov esi,ecx // ESI <- s
|
|
mov ecx,edx // ECX <- len
|
|
|
|
jecxz EO_CRC
|
|
|
|
lea ebx,[crc32_tab]
|
|
xor edx,edx
|
|
|
|
CRC_loop:
|
|
|
|
mov dl,al
|
|
xor dl,[esi]
|
|
shr eax,8
|
|
xor eax,[dword ptr ebx+edx*4]
|
|
inc esi
|
|
loop CRC_loop
|
|
|
|
EO_CRC:
|
|
|
|
pop esi
|
|
pop edx
|
|
pop ecx
|
|
pop ebx
|
|
|
|
ret
|
|
}
|
|
#else // NO X86 optimization , use generic C/C++
|
|
uint32 i;
|
|
uint32 crc32val = 0;
|
|
|
|
for(i=0; i<len; i++, s++) {
|
|
crc32val =
|
|
crc32_tab[(crc32val ^ (*s)) & 0xff] ^ (crc32val >> 8);
|
|
}
|
|
return crc32val;
|
|
#endif // _X86_
|
|
} // end crc32()
|
|
|
|
/*
|
|
Calculate a 16-bit CRC checksum for unicode strings
|
|
using ITU-T V.41 polynomial.
|
|
|
|
The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
|
|
The polynomial used is: x^16 + x^12 + x^15 + 1
|
|
*/
|
|
|
|
#if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
|
|
__declspec (naked)
|
|
#endif // _X86_
|
|
uint16
|
|
__fastcall
|
|
UDFUnicodeCksum(
|
|
PWCHAR s, // ECX
|
|
uint32 n // EDX
|
|
)
|
|
{
|
|
#if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
|
|
// uint32 _Size = n;
|
|
|
|
__asm {
|
|
push ebx
|
|
push ecx
|
|
push edx
|
|
push esi
|
|
|
|
xor eax,eax
|
|
mov esi,ecx
|
|
mov ecx,edx
|
|
|
|
jecxz EO_uCRC
|
|
|
|
lea ebx,[CrcTable]
|
|
xor edx,edx
|
|
|
|
uCRC_loop:
|
|
|
|
mov dl,ah // dl = (Crc >> 8)
|
|
xor dl,[esi+1] // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff
|
|
mov ah,al
|
|
mov al,dh // ax = (Crc << 8)
|
|
xor ax,[word ptr ebx+edx*2] // ax = ...........
|
|
|
|
mov dl,ah
|
|
xor dl,[esi]
|
|
mov ah,al
|
|
mov al,dh
|
|
xor ax,[word ptr ebx+edx*2]
|
|
|
|
inc esi
|
|
inc esi
|
|
loop uCRC_loop
|
|
|
|
EO_uCRC:
|
|
|
|
pop esi
|
|
pop edx
|
|
pop ecx
|
|
pop ebx
|
|
|
|
ret
|
|
}
|
|
#else // NO X86 optimization , use generic C/C++
|
|
uint16 Crc = 0;
|
|
while (n--) {
|
|
Crc = CrcTable[(Crc >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc << 8);
|
|
Crc = CrcTable[(Crc >> 8 ^ (*s++ & 0xff)) & 0xff] ^ (Crc << 8);
|
|
}
|
|
return Crc;
|
|
|
|
#endif // _X86_
|
|
} // end UDFUnicodeCksum()
|
|
|
|
#if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
|
|
__declspec (naked)
|
|
#endif // _X86_
|
|
uint16
|
|
__fastcall
|
|
UDFUnicodeCksum150(
|
|
PWCHAR s, // ECX
|
|
uint32 n // EDX
|
|
)
|
|
{
|
|
#if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
|
|
// uint32 _Size = n;
|
|
|
|
__asm {
|
|
push ebx
|
|
push ecx
|
|
push edx
|
|
push esi
|
|
push edi
|
|
|
|
xor eax,eax
|
|
mov esi,ecx
|
|
mov ecx,edx
|
|
xor edi,edi
|
|
|
|
jecxz EO_uCRC
|
|
|
|
//lea ebx,[CrcTable]
|
|
xor edx,edx
|
|
xor ebx,ebx
|
|
|
|
uCRC_loop:
|
|
|
|
mov dl,ah // dl = (Crc >> 8)
|
|
or edi,edx // if(*s & 0xff00) Use16 = TRUE;
|
|
xor dl,[esi+1] // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff
|
|
mov ah,al
|
|
mov al,0 // ax = (Crc << 8)
|
|
xor ax,[word ptr CrcTable+edx*2] // ax = ...........
|
|
|
|
mov dl,ah
|
|
xor dl,[esi]
|
|
mov ah,al
|
|
mov al,0
|
|
xor ax,[word ptr CrcTable+edx*2]
|
|
|
|
or edi,edi // if(!Use16) {
|
|
jnz use16_1
|
|
|
|
rol eax,16
|
|
|
|
mov bl,ah // dl = (Crc >> 8)
|
|
xor bl,[esi] // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff
|
|
mov ah,al
|
|
mov al,0 // ax = (Crc << 8)
|
|
xor ax,[word ptr CrcTable+ebx*2] // ax = ...........
|
|
|
|
rol eax,16
|
|
use16_1:
|
|
inc esi
|
|
inc esi
|
|
loop uCRC_loop
|
|
|
|
EO_uCRC:
|
|
|
|
or edi,edi // if(!Use16) {
|
|
jnz use16_2
|
|
|
|
rol eax,16 // }
|
|
use16_2:
|
|
and eax,0xffff
|
|
|
|
pop edi
|
|
pop esi
|
|
pop edx
|
|
pop ecx
|
|
pop ebx
|
|
|
|
ret
|
|
}
|
|
#else // NO X86 optimization , use generic C/C++
|
|
uint16 Crc = 0;
|
|
uint16 Crc2 = 0;
|
|
BOOLEAN Use16 = FALSE;
|
|
while (n--) {
|
|
if(!Use16) {
|
|
if((*s) & 0xff00) {
|
|
Use16 = TRUE;
|
|
} else {
|
|
Crc2 = CrcTable[(Crc2 >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc2 << 8);
|
|
}
|
|
}
|
|
Crc = CrcTable[(Crc >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc << 8);
|
|
Crc = CrcTable[(Crc >> 8 ^ (*s++ & 0xff)) & 0xff] ^ (Crc << 8);
|
|
}
|
|
return Use16 ? Crc : Crc2;
|
|
#endif // _X86_
|
|
} // end UDFUnicodeCksum150()
|
|
|
|
/*
|
|
Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial.
|
|
|
|
The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
|
|
The polynomial used is: x^16 + x^12 + x^15 + 1
|
|
*/
|
|
#if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
|
|
__declspec (naked)
|
|
#endif // _X86_
|
|
uint16
|
|
__fastcall
|
|
UDFCrc(
|
|
IN uint8* Data, // ECX
|
|
IN SIZE_T Size // EDX
|
|
)
|
|
{
|
|
#if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
|
|
// uint32 _Size = Size;
|
|
|
|
__asm {
|
|
push ebx
|
|
push ecx
|
|
push edx
|
|
push esi
|
|
|
|
mov esi,ecx
|
|
mov ecx,edx
|
|
xor eax,eax
|
|
|
|
jecxz EO_CRC
|
|
|
|
lea ebx,[CrcTable]
|
|
xor edx,edx
|
|
|
|
CRC_loop:
|
|
|
|
mov dl,ah
|
|
xor dl,[esi]
|
|
mov ah,al
|
|
mov al,dh
|
|
xor ax,[word ptr ebx+edx*2]
|
|
inc esi
|
|
loop CRC_loop
|
|
|
|
EO_CRC:
|
|
|
|
pop esi
|
|
pop edx
|
|
pop ecx
|
|
pop ebx
|
|
|
|
ret
|
|
}
|
|
#else // NO X86 optimization , use generic C/C++
|
|
uint16 Crc = 0;
|
|
while (Size--)
|
|
Crc = CrcTable[(Crc >> 8 ^ *Data++) & 0xff] ^ (Crc << 8);
|
|
return Crc;
|
|
#endif // _X86_
|
|
|
|
} // end UDFCrc()
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop) // re-enable warning #4035
|
|
#endif
|
|
|
|
/*
|
|
Read the first block of a tagged descriptor & check it.
|
|
*/
|
|
OSSTATUS
|
|
UDFReadTagged(
|
|
PVCB Vcb,
|
|
int8* Buf,
|
|
uint32 Block,
|
|
uint32 Location,
|
|
uint16 *Ident
|
|
)
|
|
{
|
|
OSSTATUS RC;
|
|
tag* PTag = (tag*)Buf;
|
|
// icbtag* Icb = (icbtag*)(Buf+1);
|
|
uint8 checksum;
|
|
unsigned int i;
|
|
SIZE_T ReadBytes;
|
|
int8* tb;
|
|
|
|
// Read the block
|
|
if(Block == 0xFFFFFFFF)
|
|
return NULL;
|
|
|
|
_SEH2_TRY {
|
|
RC = UDFReadSectors(Vcb, FALSE, Block, 1, FALSE, Buf, &ReadBytes);
|
|
if(!OS_SUCCESS(RC)) {
|
|
UDFPrint(("UDF: Block=%x, Location=%x: read failed\n", Block, Location));
|
|
try_return(RC);
|
|
}
|
|
|
|
*Ident = PTag->tagIdent;
|
|
|
|
if(Location != PTag->tagLocation) {
|
|
UDFPrint(("UDF: location mismatch block %x, tag %x != %x\n",
|
|
Block, PTag->tagLocation, Location));
|
|
try_return(RC = STATUS_FILE_CORRUPT_ERROR);
|
|
}
|
|
|
|
/* Verify the tag checksum */
|
|
checksum = 0;
|
|
tb = Buf;
|
|
for (i=0; i<sizeof(tag); i++, tb++)
|
|
checksum += (uint8)((i!=4) ? (*tb) : 0);
|
|
|
|
if(checksum != PTag->tagChecksum) {
|
|
UDFPrint(("UDF: tag checksum failed block %x\n", Block));
|
|
try_return(RC = STATUS_CRC_ERROR);
|
|
}
|
|
|
|
// Verify the tag version
|
|
if((PTag->descVersion != 2) &&
|
|
(PTag->descVersion != 3)) {
|
|
UDFPrint(("UDF: Tag version 0x%04x != 0x0002 || 0x0003 block %x\n",
|
|
(PTag->descVersion), Block));
|
|
try_return(RC = STATUS_FILE_CORRUPT_ERROR);
|
|
}
|
|
|
|
// Verify the descriptor CRC
|
|
if(((PTag->descCRCLength) + sizeof(tag) > Vcb->BlockSize) ||
|
|
((PTag->descCRC) == UDFCrc((uint8*)Buf + sizeof(tag), PTag->descCRCLength)) ||
|
|
!(PTag->descCRC) ) {
|
|
/* UDFPrint(("Tag ID: %x, ver %x\t", PTag->tagIdent, PTag->descVersion ));
|
|
if((i == TID_FILE_ENTRY) ||
|
|
(i == TID_EXTENDED_FILE_ENTRY)) {
|
|
UDFPrint(("StrategType: %x, ", Icb->strategyType ));
|
|
UDFPrint(("FileType: %x\t", Icb->fileType ));
|
|
}
|
|
UDFPrint(("\n"));*/
|
|
try_return(RC = STATUS_SUCCESS);
|
|
}
|
|
UDFPrint(("UDF: Crc failure block %x: crc = %x, crclen = %x\n",
|
|
Block, PTag->descCRC, PTag->descCRCLength));
|
|
RC = STATUS_CRC_ERROR;
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} _SEH2_FINALLY {
|
|
;
|
|
} _SEH2_END
|
|
|
|
return RC;
|
|
} // end UDFReadTagged()
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
/*
|
|
This routine creates hard link for the file from DirInfo1
|
|
to DirInfo2 & names it as fn
|
|
*/
|
|
OSSTATUS
|
|
UDFHardLinkFile__(
|
|
IN PVCB Vcb,
|
|
IN BOOLEAN IgnoreCase,
|
|
IN OUT BOOLEAN* Replace, // replace if destination file exists
|
|
IN PUNICODE_STRING fn, // destination
|
|
IN OUT PUDF_FILE_INFO DirInfo1,
|
|
IN OUT PUDF_FILE_INFO DirInfo2,
|
|
IN OUT PUDF_FILE_INFO FileInfo // source (opened)
|
|
)
|
|
{
|
|
PUDF_FILE_INFO FileInfo2;
|
|
OSSTATUS status;
|
|
PDIR_INDEX_ITEM DirNdx1;
|
|
PDIR_INDEX_ITEM DirNdx2;
|
|
uint_di i;
|
|
BOOLEAN Recovery = FALSE;
|
|
BOOLEAN SameFE = FALSE;
|
|
uint32 NTAttr = 0;
|
|
|
|
// validate FileInfo
|
|
ValidateFileInfo(DirInfo1);
|
|
ValidateFileInfo(DirInfo2);
|
|
ValidateFileInfo(FileInfo);
|
|
|
|
if(UDFGetFileLinkCount(FileInfo) >= UDF_MAX_LINK_COUNT) {
|
|
// too many links to file...
|
|
return STATUS_TOO_MANY_LINKS;
|
|
}
|
|
|
|
i = 0;
|
|
if(DirInfo1 == DirInfo2) {
|
|
if(OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &i)) &&
|
|
(i==FileInfo->Index) ) {
|
|
// case-only difference
|
|
return STATUS_OBJECT_NAME_COLLISION;
|
|
}
|
|
}
|
|
|
|
// PHASE 0
|
|
// try to create new FileIdent & FileEntry in Dir2
|
|
|
|
HLinkRetry:
|
|
if(!OS_SUCCESS(status = UDFCreateFile__(Vcb, IgnoreCase, fn, UDFGetFileEALength(FileInfo),
|
|
0, (FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY),
|
|
TRUE, DirInfo2, &FileInfo2))) {
|
|
if(UDFCleanUpFile__(Vcb, FileInfo2) && FileInfo2)
|
|
MyFreePool__(FileInfo2);
|
|
if(status == STATUS_ACCESS_DENIED) {
|
|
// try to recover >;->
|
|
if((*Replace) && !Recovery) {
|
|
Recovery = TRUE;
|
|
status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL);
|
|
if(OS_SUCCESS(status)) {
|
|
status = UDFDoesOSAllowFileToBeTargetForHLink__(FileInfo2);
|
|
if(!OS_SUCCESS(status)) {
|
|
UDFCloseFile__(Vcb, FileInfo2);
|
|
goto cleanup_and_abort_hlink;
|
|
}
|
|
if((FileInfo->Dloc == FileInfo2->Dloc) &&
|
|
(FileInfo != FileInfo2)) {
|
|
SameFE = TRUE;
|
|
// 'status' is already STATUS_SUCCESS here
|
|
} else {
|
|
status = UDFUnlinkFile__(Vcb, FileInfo2, TRUE);
|
|
}
|
|
UDFCloseFile__(Vcb, FileInfo2);
|
|
if(UDFCleanUpFile__(Vcb, FileInfo2)) {
|
|
MyFreePool__(FileInfo2);
|
|
FileInfo2 = NULL;
|
|
if(SameFE)
|
|
return STATUS_SUCCESS;
|
|
} else {
|
|
// we get here if the FileInfo has associated
|
|
// system-specific Fcb
|
|
// Such fact means that not all system references
|
|
// has already gone (except Linked file case)
|
|
if(SameFE)
|
|
return STATUS_SUCCESS;
|
|
if(!OS_SUCCESS(status) ||
|
|
(UDFGetFileLinkCount(FileInfo) < 1))
|
|
status = STATUS_ACCESS_DENIED;
|
|
}
|
|
if(OS_SUCCESS(status)) goto HLinkRetry;
|
|
}
|
|
cleanup_and_abort_hlink:
|
|
if(FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) {
|
|
MyFreePool__(FileInfo2);
|
|
FileInfo2 = NULL;
|
|
}
|
|
} else {
|
|
status = STATUS_OBJECT_NAME_COLLISION;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
// update pointers
|
|
DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex, FileInfo->Index);
|
|
DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex, FileInfo2->Index);
|
|
|
|
// copy file attributes to newly created FileIdent
|
|
NTAttr = UDFAttributesToNT(DirNdx1, FileInfo->Dloc->FileEntry);
|
|
FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
|
|
|
|
// PHASE 1
|
|
// copy all necessary info from FileInfo to FileInfo2
|
|
|
|
FileInfo2->FileIdent->icb = FileInfo->FileIdent->icb;
|
|
FileInfo2->FileIdent->fileCharacteristics = FileInfo->FileIdent->fileCharacteristics;
|
|
FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
|
|
|
|
DirNdx2->FileCharacteristics = DirNdx1->FileCharacteristics & ~FILE_DELETED;
|
|
DirNdx2->FileEntryLoc = DirNdx1->FileEntryLoc;
|
|
DirNdx2->FI_Flags = (DirNdx1->FI_Flags & ~UDF_FI_FLAG_SYS_ATTR) | UDF_FI_FLAG_FI_MODIFIED | UDF_FI_FLAG_LINKED;
|
|
|
|
UDFAttributesToUDF(DirNdx2, FileInfo2->Dloc->FileEntry, NTAttr);
|
|
|
|
// PHASE 2
|
|
// update FileInfo
|
|
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
DirNdx1->FI_Flags = DirNdx2->FI_Flags;
|
|
UDFIncFileLinkCount(FileInfo); // increase to 1
|
|
// UDFUpdateModifyTime(Vcb, FileInfo);
|
|
FileInfo->Dloc->LinkRefCount += FileInfo2->Dloc->LinkRefCount;
|
|
if(FileInfo2->FileIdent)
|
|
((FidADImpUse*)&(FileInfo2->FileIdent->icb.impUse))->uniqueID = (uint32)UDFAssingNewFUID(Vcb);
|
|
|
|
// PHASE 3
|
|
// drop all unnecessary info from FileInfo2
|
|
|
|
UDFFreeFESpace(Vcb, DirInfo2, &(FileInfo2->Dloc->FELoc));
|
|
UDFRemoveDloc(Vcb, FileInfo2->Dloc);
|
|
|
|
// PHASE 4
|
|
// perform in-memory linkage (update driver's tree structures) and flush
|
|
|
|
FileInfo2->Dloc = FileInfo->Dloc;
|
|
UDFInsertLinkedFile(FileInfo2, FileInfo);
|
|
|
|
UDFCloseFile__(Vcb, FileInfo2);
|
|
if(UDFCleanUpFile__(Vcb, FileInfo2)) {
|
|
MyFreePool__(FileInfo2);
|
|
}
|
|
// return 'delete target' status
|
|
(*Replace) = Recovery;
|
|
|
|
return STATUS_SUCCESS;
|
|
} // end UDFHardLinkFile__()
|
|
|
|
/*
|
|
This routine allocates FileEntry with in-ICB zero-sized data
|
|
If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
|
|
for returned pointer *WITHOUT* using UDFCloseFile__
|
|
*/
|
|
OSSTATUS
|
|
UDFCreateRootFile__(
|
|
IN PVCB Vcb,
|
|
// IN uint16 AllocMode, // short/long/ext/in-icb // always in-ICB
|
|
IN uint32 PartNum,
|
|
IN uint32 ExtAttrSz,
|
|
IN uint32 ImpUseLen,
|
|
IN BOOLEAN Extended,
|
|
OUT PUDF_FILE_INFO* _FileInfo
|
|
)
|
|
{
|
|
OSSTATUS status;
|
|
LONG_AD FEicb;
|
|
PUDF_FILE_INFO FileInfo;
|
|
*_FileInfo = NULL;
|
|
SIZE_T ReadBytes;
|
|
|
|
FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG);
|
|
*_FileInfo = FileInfo;
|
|
if(!FileInfo)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
ImpUseLen = (ImpUseLen + 3) & ~((uint16)3);
|
|
|
|
RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
|
|
// init horizontal links
|
|
FileInfo->NextLinkedFile =
|
|
FileInfo->PrevLinkedFile = FileInfo;
|
|
// allocate space for FileEntry
|
|
if(!OS_SUCCESS(status =
|
|
UDFBuildFileEntry(Vcb, NULL, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) ))
|
|
return status;
|
|
FEicb.extLength = Vcb->LBlockSize;
|
|
FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
FEicb.extLocation.partitionReferenceNum = (uint16)PartNum;
|
|
RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse));
|
|
|
|
FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0]));
|
|
if(!(FileInfo->Dloc->DataLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
|
|
FileInfo->Dloc->DataLoc.Length = 0;
|
|
FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
|
|
// init FileEntry
|
|
UDFSetFileUID(Vcb, FileInfo);
|
|
UDFSetFileSize(FileInfo, 0);
|
|
UDFIncFileLinkCount(FileInfo); // increase to 1
|
|
UDFUpdateCreateTime(Vcb, FileInfo);
|
|
// zero sector for FileEntry
|
|
FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
|
|
FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
|
|
status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, Vcb->LBlockSize, FALSE, Vcb->ZBuffer, &ReadBytes);
|
|
if(!OS_SUCCESS(status))
|
|
return status;
|
|
|
|
UDFReferenceFile__(FileInfo);
|
|
UDFReleaseDloc(Vcb, FileInfo->Dloc);
|
|
return STATUS_SUCCESS;
|
|
} // end UDFCreateRootFile__()
|
|
|
|
/*
|
|
This routine tries to create StreamDirectory associated with given file
|
|
Caller should use UDFCleanUpFile__ if returned status != STATUS_SUCCESS
|
|
*/
|
|
OSSTATUS
|
|
UDFCreateStreamDir__(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo, // file containing stream-dir
|
|
OUT PUDF_FILE_INFO* _SDirInfo // this is to be filled & doesn't contain
|
|
// any pointers
|
|
)
|
|
{
|
|
OSSTATUS status;
|
|
PUDF_FILE_INFO SDirInfo;
|
|
uint16 Ident;
|
|
|
|
*_SDirInfo = NULL;
|
|
ValidateFileInfo(FileInfo);
|
|
// check currently recorded UDF revision
|
|
if(!UDFStreamsSupported(Vcb))
|
|
return STATUS_INVALID_PARAMETER;
|
|
// check if we are allowed to associate Stream Dir with this file
|
|
if((FileInfo->ParentFile && UDFIsAStreamDir(FileInfo->ParentFile)) ||
|
|
UDFHasAStreamDir(FileInfo))
|
|
return STATUS_FILE_DELETED;
|
|
// check if we have Deleted SDir
|
|
if(FileInfo->Dloc->SDirInfo &&
|
|
UDFIsSDirDeleted(FileInfo->Dloc->SDirInfo))
|
|
return STATUS_ACCESS_DENIED;
|
|
// check if this file has ExtendedFileEntry
|
|
if((Ident = FileInfo->Dloc->FileEntry->tagIdent) != TID_EXTENDED_FILE_ENTRY) {
|
|
if(!OS_SUCCESS(status = UDFConvertFEToExtended(Vcb, FileInfo)))
|
|
return status;
|
|
}
|
|
|
|
uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
// create stream directory file
|
|
if(!OS_SUCCESS(status = UDFCreateRootFile__(Vcb, PartNum, 0,0,FALSE, &SDirInfo)))
|
|
return status;
|
|
// link objects
|
|
SDirInfo->ParentFile = FileInfo;
|
|
// record directory structure
|
|
SDirInfo->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | UDF_FE_FLAG_IS_SDIR);
|
|
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR;
|
|
UDFIncFileLinkCount(FileInfo);
|
|
FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR;
|
|
|
|
status = UDFRecordDirectory__(Vcb, SDirInfo);
|
|
UDFDecDirCounter(Vcb);
|
|
|
|
UDFInterlockedIncrement((PLONG)&(FileInfo->OpenCount));
|
|
if(!OS_SUCCESS(status)) {
|
|
UDFUnlinkFile__(Vcb, SDirInfo, TRUE);
|
|
UDFCloseFile__(Vcb, SDirInfo);
|
|
UDFCleanUpFile__(Vcb, SDirInfo);
|
|
MyFreePool__(SDirInfo);
|
|
((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength = 0;
|
|
((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.partitionReferenceNum = 0;
|
|
((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.logicalBlockNum = 0;
|
|
return status;
|
|
}
|
|
*_SDirInfo = SDirInfo;
|
|
// do some init
|
|
((PEXTENDED_FILE_ENTRY)(SDirInfo->Dloc->FileEntry))->icbTag.fileType = UDF_FILE_TYPE_STREAMDIR;
|
|
((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength = Vcb->LBlockSize;
|
|
((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.partitionReferenceNum = (uint16)PartNum;
|
|
((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.logicalBlockNum =
|
|
UDFPhysLbaToPart(Vcb, PartNum, SDirInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
((PEXTENDED_FILE_ENTRY)(SDirInfo->Dloc->FileEntry))->uniqueID =
|
|
((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->uniqueID;
|
|
FileInfo->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | UDF_FE_FLAG_HAS_SDIR);
|
|
// open & finalize linkage
|
|
FileInfo->Dloc->SDirInfo = SDirInfo;
|
|
return STATUS_SUCCESS;
|
|
} // end UDFCreateStreamDir__()
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
/*
|
|
This routine opens Stream Directory associated with file specified
|
|
*/
|
|
OSSTATUS
|
|
UDFOpenStreamDir__(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo, // file containing stream-dir
|
|
OUT PUDF_FILE_INFO* _SDirInfo // this is to be filled & doesn't contain
|
|
// any pointers
|
|
)
|
|
{
|
|
OSSTATUS status;
|
|
PUDF_FILE_INFO SDirInfo;
|
|
PUDF_FILE_INFO ParSDirInfo;
|
|
uint16 Ident;
|
|
|
|
*_SDirInfo = NULL;
|
|
ValidateFileInfo(FileInfo);
|
|
// check if this file has ExtendedFileEntry
|
|
if((Ident = FileInfo->Dloc->FileEntry->tagIdent) != TID_EXTENDED_FILE_ENTRY) {
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
if((SDirInfo = FileInfo->Dloc->SDirInfo)) {
|
|
// it is already opened. Good...
|
|
|
|
// check if we have Deleted SDir
|
|
if(FileInfo->Dloc->SDirInfo &&
|
|
UDFIsSDirDeleted(FileInfo->Dloc->SDirInfo))
|
|
return STATUS_FILE_DELETED;
|
|
// All right. Look for parallel SDir (if any)
|
|
if(SDirInfo->ParentFile != FileInfo) {
|
|
ParSDirInfo = UDFLocateParallelFI(FileInfo, 0, SDirInfo);
|
|
BrutePoint();
|
|
if(ParSDirInfo->ParentFile != FileInfo) {
|
|
SDirInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_SDFINF_TAG);
|
|
*_SDirInfo = SDirInfo;
|
|
if(!SDirInfo) return STATUS_INSUFFICIENT_RESOURCES;
|
|
RtlCopyMemory(SDirInfo, FileInfo->Dloc->SDirInfo, sizeof(UDF_FILE_INFO));
|
|
// SDirInfo->NextLinkedFile = FileInfo->Dloc->SDirInfo->NextLinkedFile; // is already done
|
|
UDFInsertLinkedFile(SDirInfo, FileInfo->Dloc->SDirInfo);
|
|
SDirInfo->RefCount = 0;
|
|
SDirInfo->ParentFile = FileInfo;
|
|
SDirInfo->Fcb = NULL;
|
|
} else {
|
|
SDirInfo = ParSDirInfo;
|
|
}
|
|
}
|
|
UDFReferenceFile__(SDirInfo);
|
|
*_SDirInfo = SDirInfo;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
// normal open
|
|
if(!((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength)
|
|
return STATUS_NOT_FOUND;
|
|
SDirInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_SDFINF_TAG);
|
|
if(!SDirInfo) return STATUS_INSUFFICIENT_RESOURCES;
|
|
*_SDirInfo = SDirInfo;
|
|
status = UDFOpenRootFile__(Vcb, &(((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation) ,SDirInfo);
|
|
if(!OS_SUCCESS(status)) return status;
|
|
// open & finalize linkage
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR;
|
|
SDirInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_SDIR;
|
|
FileInfo->Dloc->SDirInfo = SDirInfo;
|
|
SDirInfo->ParentFile = FileInfo;
|
|
|
|
UDFInterlockedIncrement((PLONG)&(FileInfo->OpenCount));
|
|
|
|
return STATUS_SUCCESS;
|
|
} // end UDFOpenStreamDir__()
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
/*
|
|
This routine records VAT & VAT Icb at the end of session
|
|
*/
|
|
OSSTATUS
|
|
UDFRecordVAT(
|
|
IN PVCB Vcb
|
|
)
|
|
{
|
|
uint32 Offset;
|
|
uint32 to_read;
|
|
uint32 hdrOffset, hdrOffsetNew;
|
|
uint32 hdrLen;
|
|
OSSTATUS status;
|
|
SIZE_T ReadBytes;
|
|
uint32 len;
|
|
uint16 PartNdx = (uint16)Vcb->VatPartNdx;
|
|
uint16 PartNum = UDFGetPartNumByPartNdx(Vcb, PartNdx);
|
|
uint32 root = UDFPartStart(Vcb, PartNum);
|
|
PUDF_FILE_INFO VatFileInfo = Vcb->VatFileInfo;
|
|
uint32 i;
|
|
PEXTENT_MAP Mapping;
|
|
uint32 off, BS, NWA;
|
|
int8* Old;
|
|
int8* New;
|
|
uint32* Vat;
|
|
uint8 AllocMode;
|
|
uint32 VatLen;
|
|
uint32 PacketOffset;
|
|
uint32 BSh = Vcb->BlockSizeBits;
|
|
uint32 MaxPacket = Vcb->WriteBlockSize >> BSh;
|
|
uint32 OldLen;
|
|
EntityID* eID;
|
|
|
|
if(!(Vat = Vcb->Vat) || !VatFileInfo) return STATUS_INVALID_PARAMETER;
|
|
// Disable VAT-based translation
|
|
Vcb->Vat = NULL;
|
|
// sync VAT and FSBM
|
|
len = min(UDFPartLen(Vcb, PartNum), Vcb->FSBM_BitCount - root);
|
|
len = min(Vcb->VatCount, len);
|
|
for(i=0; i<len; i++) {
|
|
if(UDFGetFreeBit(Vcb->FSBM_Bitmap, root+i))
|
|
Vat[i] = UDF_VAT_FREE_ENTRY;
|
|
}
|
|
// Ok, now we shall construct new VAT image...
|
|
// !!! NOTE !!!
|
|
// Both VAT copies - in-memory & on-disc
|
|
// contain _relative_ addresses
|
|
OldLen = len = (uint32)UDFGetFileSize(Vcb->VatFileInfo);
|
|
VatLen = (Vcb->LastLBA - root + 1) * sizeof(uint32);
|
|
Old = (int8*)DbgAllocatePool(PagedPool, OldLen);
|
|
if(!Old) {
|
|
DbgFreePool(Vat);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
// read old one
|
|
status = UDFReadFile__(Vcb, VatFileInfo, 0, OldLen, FALSE, Old, &ReadBytes);
|
|
if(!OS_SUCCESS(status)) {
|
|
DbgFreePool(Vat);
|
|
DbgFreePool(Old);
|
|
return status;
|
|
}
|
|
// prepare some pointers
|
|
// and fill headers
|
|
if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP15) {
|
|
Offset = 0;
|
|
to_read =
|
|
hdrOffset = len - sizeof(VirtualAllocationTable15);
|
|
hdrLen = sizeof(VirtualAllocationTable15);
|
|
hdrOffsetNew = VatLen;
|
|
New = (int8*)DbgAllocatePool(PagedPool, VatLen + hdrLen);
|
|
if(!New) {
|
|
DbgFreePool(Vat);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlCopyMemory(New+hdrOffsetNew, Old+hdrOffset, hdrLen);
|
|
((VirtualAllocationTable15*)(New + hdrOffset))->previousVATICB =
|
|
VatFileInfo->Dloc->FELoc.Mapping[0].extLocation - root;
|
|
eID = &(((VirtualAllocationTable15*)(New + hdrOffset))->ident);
|
|
|
|
UDFSetEntityID_imp(eID, UDF_ID_ALLOC);
|
|
|
|
/* RtlCopyMemory((int8*)&(eID->ident), UDF_ID_ALLOC, sizeof(UDF_ID_ALLOC) );
|
|
iis = (impIdentSuffix*)&(eID->identSuffix);
|
|
iis->OSClass = UDF_OS_CLASS_WINNT;
|
|
iis->OSIdent = UDF_OS_ID_WINNT;*/
|
|
} else {
|
|
VirtualAllocationTable20* Buf;
|
|
|
|
Offset = ((VirtualAllocationTable20*)Old)->lengthHeader;
|
|
to_read = len - Offset;
|
|
hdrOffset = 0;
|
|
hdrLen = sizeof(VirtualAllocationTable20);
|
|
hdrOffsetNew = 0;
|
|
New = (int8*)DbgAllocatePool(PagedPool, VatLen + hdrLen);
|
|
if(!New) {
|
|
DbgFreePool(Vat);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlCopyMemory(New+hdrOffsetNew, Old+hdrOffset, hdrLen);
|
|
((VirtualAllocationTable20*)New)->previousVatICBLoc =
|
|
VatFileInfo->Dloc->FELoc.Mapping[0].extLocation - root;
|
|
|
|
Buf = (VirtualAllocationTable20*)New;
|
|
|
|
Buf->minReadRevision = Vcb->minUDFReadRev;
|
|
Buf->minWriteRevision = Vcb->minUDFWriteRev;
|
|
Buf->maxWriteRevision = Vcb->maxUDFWriteRev;
|
|
|
|
Buf->numFIDSFiles = Vcb->numFiles;
|
|
Buf->numFIDSDirectories = Vcb->numDirs;
|
|
}
|
|
|
|
RtlCopyMemory(New+Offset, Vat, VatLen);
|
|
//
|
|
if(VatFileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) {
|
|
eID = &(((PEXTENDED_FILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->impIdent);
|
|
} else {
|
|
eID = &(((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->impIdent);
|
|
}
|
|
|
|
#if 0
|
|
UDFSetEntityID_imp(eID, UDF_ID_DEVELOPER);
|
|
#endif
|
|
|
|
/* RtlCopyMemory((int8*)&(eID->ident), UDF_ID_DEVELOPER, sizeof(UDF_ID_DEVELOPER) );
|
|
iis = (impIdentSuffix*)&(eID->identSuffix);
|
|
iis->OSClass = UDF_OS_CLASS_WINNT;
|
|
iis->OSIdent = UDF_OS_ID_WINNT;*/
|
|
|
|
VatFileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
// drop VAT
|
|
DbgFreePool(Vat);
|
|
len = VatLen;
|
|
// the operation of resize can modifiy WriteCount in WCache due to movement
|
|
// of the data from FE. That's why we should remember PacketOffset now
|
|
if(to_read < VatLen) {
|
|
status = UDFResizeFile__(Vcb, VatFileInfo, len = hdrLen + VatLen);
|
|
if(!OS_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
UDFMarkSpaceAsXXX(Vcb, VatFileInfo->Dloc, VatFileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); //free
|
|
}
|
|
PacketOffset = WCacheGetWriteBlockCount__(&(Vcb->FastCache));
|
|
if( ((((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) ) {
|
|
// now we'll place FE & built-in data to the last sector of
|
|
// the last packet will be recorded
|
|
if(!PacketOffset) {
|
|
// add padding
|
|
UDFWriteData(Vcb, TRUE, ((uint64)Vcb->NWA) << Vcb->BlockSizeBits, 1, FALSE, Old, &ReadBytes);
|
|
PacketOffset++;
|
|
} else {
|
|
Vcb->Vat = (uint32*)(New+Offset);
|
|
WCacheSyncReloc__(&(Vcb->FastCache), Vcb);
|
|
Vcb->Vat = NULL;
|
|
}
|
|
VatFileInfo->Dloc->FELoc.Mapping[0].extLocation =
|
|
VatFileInfo->Dloc->DataLoc.Mapping[0].extLocation =
|
|
Vcb->NWA+PacketOffset;
|
|
VatFileInfo->Dloc->FELoc.Modified = TRUE;
|
|
// setup descTag
|
|
((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->descTag.tagLocation =
|
|
UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->DataLoc.Mapping[0].extLocation);
|
|
// record data
|
|
if(OS_SUCCESS(status = UDFWriteFile__(Vcb, VatFileInfo, 0, VatLen + hdrLen, FALSE, New, &ReadBytes))) {
|
|
status = UDFFlushFile__(Vcb, VatFileInfo);
|
|
}
|
|
return status;
|
|
}
|
|
// We can't fit the whole VAT in FE tail
|
|
// Now lets 'unpack' VAT's mapping to make updating easier
|
|
status = UDFUnPackMapping(Vcb, &(VatFileInfo->Dloc->DataLoc));
|
|
if(!OS_SUCCESS(status)) return status;
|
|
// update VAT with locations of not flushed blocks
|
|
if(PacketOffset) {
|
|
Vcb->Vat = (uint32*)(New+Offset);
|
|
WCacheSyncReloc__(&(Vcb->FastCache), Vcb);
|
|
Vcb->Vat = NULL;
|
|
}
|
|
|
|
Mapping = VatFileInfo->Dloc->DataLoc.Mapping;
|
|
off=0;
|
|
BS = Vcb->BlockSize;
|
|
NWA = Vcb->NWA;
|
|
VatLen += hdrLen;
|
|
// record modified parts of VAT & update mapping
|
|
for(i=0; Mapping[i].extLength; i++) {
|
|
to_read = (VatLen>=BS) ? BS : VatLen;
|
|
if((OldLen < off) || (RtlCompareMemory(Old+off, New+off, to_read) != to_read)) {
|
|
// relocate frag
|
|
Mapping[i].extLocation = NWA+PacketOffset;
|
|
Mapping[i].extLength &= UDF_EXTENT_LENGTH_MASK;
|
|
PacketOffset++;
|
|
if(PacketOffset >= MaxPacket) {
|
|
NWA += (MaxPacket + 7);
|
|
PacketOffset = 0;
|
|
}
|
|
status = UDFWriteFile__(Vcb, VatFileInfo, off, to_read, FALSE, New+off, &ReadBytes);
|
|
if(!OS_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
}
|
|
VatLen-=BS;
|
|
off+=BS;
|
|
}
|
|
// pack mapping
|
|
UDFPackMapping(Vcb, &(VatFileInfo->Dloc->DataLoc));
|
|
len = UDFGetMappingLength(VatFileInfo->Dloc->DataLoc.Mapping)/sizeof(EXTENT_MAP) - 1;
|
|
// obtain AllocMode
|
|
AllocMode = ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
|
|
switch(AllocMode) {
|
|
case ICB_FLAG_AD_SHORT: {
|
|
AllocMode = sizeof(SHORT_AD);
|
|
break;
|
|
}
|
|
case ICB_FLAG_AD_LONG: {
|
|
AllocMode = sizeof(LONG_AD);
|
|
break;
|
|
}
|
|
case ICB_FLAG_AD_EXTENDED: {
|
|
// break;
|
|
}
|
|
default: {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
// calculate actual AllocSequence length (in blocks)
|
|
len = (len*AllocMode+BS-1+VatFileInfo->Dloc->AllocLoc.Offset) /
|
|
// (((BS - sizeof(ALLOC_EXT_DESC))/sizeof(SHORT_AD))*sizeof(SHORT_AD));
|
|
((BS - sizeof(ALLOC_EXT_DESC) + AllocMode - 1) & ~(AllocMode-1));
|
|
// Re-init AllocLoc
|
|
if(VatFileInfo->Dloc->AllocLoc.Mapping) MyFreePool__(VatFileInfo->Dloc->AllocLoc.Mapping);
|
|
VatFileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (len+1)*sizeof(EXTENT_MAP),
|
|
MEM_EXTMAP_TAG);
|
|
if(!(VatFileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
VatFileInfo->Dloc->AllocLoc.Offset = (uint32)(VatFileInfo->Dloc->FELoc.Length);
|
|
VatFileInfo->Dloc->AllocLoc.Length = 0;
|
|
Mapping = VatFileInfo->Dloc->AllocLoc.Mapping;
|
|
Mapping[0].extLength = BS-VatFileInfo->Dloc->AllocLoc.Offset;
|
|
// Mapping[0].extLocation = ???;
|
|
for(i=1; i<len; i++) {
|
|
// relocate frag
|
|
Mapping[i].extLocation = NWA+PacketOffset;
|
|
Mapping[i].extLength = BS;
|
|
PacketOffset++;
|
|
if(PacketOffset >= MaxPacket) {
|
|
NWA += (MaxPacket + 7);
|
|
PacketOffset = 0;
|
|
}
|
|
}
|
|
// Terminator
|
|
Mapping[i].extLocation =
|
|
Mapping[i].extLength = 0;
|
|
|
|
if( !PacketOffset &&
|
|
(VatFileInfo->Dloc->AllocLoc.Length <= (Vcb->BlockSize - (uint32)(VatFileInfo->Dloc->AllocLoc.Offset)) ) ) {
|
|
// add padding
|
|
UDFWriteData(Vcb, TRUE, ((uint64)NWA) << Vcb->BlockSizeBits, 1, FALSE, Old, &ReadBytes);
|
|
PacketOffset++;
|
|
}
|
|
// now we'll place FE & built-in data to the last sector of
|
|
// the last packet will be recorded
|
|
VatFileInfo->Dloc->FELoc.Mapping[0].extLocation =
|
|
VatFileInfo->Dloc->AllocLoc.Mapping[0].extLocation =
|
|
NWA+PacketOffset;
|
|
VatFileInfo->Dloc->FELoc.Modified = TRUE;
|
|
// setup descTag
|
|
((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->descTag.tagLocation =
|
|
UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->FELoc.Mapping[0].extLocation);
|
|
VatFileInfo->Dloc->DataLoc.Modified = TRUE;
|
|
|
|
status = UDFFlushFile__(Vcb, VatFileInfo);
|
|
if(!OS_SUCCESS(status))
|
|
return status;
|
|
WCacheFlushAll__(&(Vcb->FastCache), Vcb);
|
|
return STATUS_SUCCESS;
|
|
} // end UDFRecordVAT()
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
/*
|
|
This routine updates VAT according to RequestedLbaTable (RelocTab) &
|
|
actual physical address where this data will be stored
|
|
*/
|
|
OSSTATUS
|
|
UDFUpdateVAT(
|
|
IN void* _Vcb,
|
|
IN uint32 Lba,
|
|
IN uint32* RelocTab, // can be NULL
|
|
IN uint32 BCount
|
|
)
|
|
{
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
PVCB Vcb = (PVCB)_Vcb;
|
|
uint16 PartNdx = (uint16)(Vcb->VatPartNdx);
|
|
uint16 PartNum = (uint16)(Lba ? UDFGetPartNumByPhysLba(Vcb, Lba) : UDFGetPartNumByPartNdx(Vcb, PartNdx));
|
|
if(PartNum != UDFGetPartNumByPartNdx(Vcb, PartNdx)) {
|
|
UDFPrint(("UDFUpdateVAT: Write to Write-Protected partition\n"));
|
|
return STATUS_MEDIA_WRITE_PROTECTED;
|
|
}
|
|
// !!! NOTE !!!
|
|
// Both VAT copies - in-memory & on-disc
|
|
// contain _relative_ addresses
|
|
uint32 root = Vcb->Partitions[PartNdx].PartitionRoot;
|
|
uint32 NWA = Vcb->NWA-root;
|
|
uint32 i;
|
|
uint32 CurLba;
|
|
|
|
if(!Vcb->Vat) return STATUS_SUCCESS;
|
|
|
|
for(i=0; i<BCount; i++, NWA++) {
|
|
if((CurLba = (RelocTab ? RelocTab[i] : (Lba+i)) - root) >= Vcb->VatCount)
|
|
Vcb->VatCount = CurLba+1;
|
|
Vcb->Vat[CurLba] = NWA;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
#else //UDF_READ_ONLY_BUILD
|
|
return STATUS_MEDIA_WRITE_PROTECTED;
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
} // end UDFUpdateVAT()
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
/*
|
|
This routine rebuilds file's FE in order to move data from
|
|
ICB to separate Block.
|
|
*/
|
|
OSSTATUS
|
|
UDFConvertFEToNonInICB(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo,
|
|
IN uint8 NewAllocMode
|
|
)
|
|
{
|
|
OSSTATUS status;
|
|
int8* OldInIcb = NULL;
|
|
uint32 OldLen;
|
|
ValidateFileInfo(FileInfo);
|
|
SIZE_T ReadBytes;
|
|
SIZE_T _WrittenBytes;
|
|
PUDF_DATALOC_INFO Dloc;
|
|
|
|
// ASSERT(FileInfo->RefCount >= 1);
|
|
|
|
Dloc = FileInfo->Dloc;
|
|
ASSERT(Dloc->FELoc.Mapping[0].extLocation);
|
|
uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Dloc->FELoc.Mapping[0].extLocation);
|
|
|
|
if(NewAllocMode == ICB_FLAG_AD_DEFAULT_ALLOC_MODE) {
|
|
NewAllocMode = (uint8)(Vcb->DefaultAllocMode);
|
|
}
|
|
// we do not support recording of extended AD now
|
|
if(NewAllocMode != ICB_FLAG_AD_SHORT &&
|
|
NewAllocMode != ICB_FLAG_AD_LONG)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if(!Dloc->DataLoc.Offset || !Dloc->DataLoc.Length)
|
|
return STATUS_SUCCESS;
|
|
ASSERT(!Dloc->AllocLoc.Mapping);
|
|
// read in-icb data. it'll be replaced after resize
|
|
OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length));
|
|
if(!OldInIcb)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
OldLen = (uint32)(Dloc->DataLoc.Length);
|
|
status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, OldLen, FALSE, OldInIcb, &ReadBytes);
|
|
if(!OS_SUCCESS(status)) {
|
|
MyFreePool__(OldInIcb);
|
|
return status;
|
|
}
|
|
/* if(!Dloc->AllocLoc.Mapping) {
|
|
Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, sizeof(EXTENT_MAP)*2);
|
|
if(!Dloc->AllocLoc.Mapping) {
|
|
MyFreePool__(OldInIcb);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
// init Alloc mode
|
|
if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
|
|
((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
|
|
((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode;
|
|
} else {
|
|
BrutePoint();
|
|
}
|
|
RtlZeroMemory(Dloc->AllocLoc.Mapping, sizeof(EXTENT_MAP)*2);
|
|
// Dloc->AllocLoc.Mapping[0].extLocation = 0;
|
|
Dloc->AllocLoc.Mapping[0].extLength = Vcb->LBlockSize | EXTENT_NOT_RECORDED_NOT_ALLOCATED;
|
|
// Dloc->AllocLoc.Mapping[1].extLocation = 0;
|
|
// Dloc->AllocLoc.Mapping[1].extLength = 0;
|
|
*/
|
|
|
|
// grow extent in order to force space allocation
|
|
status = UDFResizeExtent(Vcb, PartNum, Vcb->LBlockSize, FALSE, &Dloc->DataLoc);
|
|
if(!OS_SUCCESS(status)) {
|
|
MyFreePool__(OldInIcb);
|
|
return status;
|
|
}
|
|
|
|
// set Alloc mode
|
|
if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
|
|
((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
|
|
((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= NewAllocMode;
|
|
} else {
|
|
BrutePoint();
|
|
}
|
|
|
|
// revert to initial extent size. This will not cause NonInICB->InICB transform
|
|
status = UDFResizeExtent(Vcb, PartNum, OldLen, FALSE, &Dloc->DataLoc);
|
|
if(!OS_SUCCESS(status)) {
|
|
MyFreePool__(OldInIcb);
|
|
return status;
|
|
}
|
|
|
|
// replace data from ICB (if any) & free buffer
|
|
status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, OldLen, FALSE, OldInIcb, &_WrittenBytes);
|
|
MyFreePool__(OldInIcb);
|
|
if(!OS_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
// inform UdfInfo, that AllocDesc's must be rebuilt on flush/close
|
|
Dloc->AllocLoc.Modified = TRUE;
|
|
Dloc->DataLoc.Modified = TRUE;
|
|
return STATUS_SUCCESS;
|
|
} // end UDFConvertFEToNonInICB()
|
|
|
|
/*
|
|
This routine converts file's FE to extended form.
|
|
It is needed for stream creation.
|
|
*/
|
|
OSSTATUS
|
|
UDFConvertFEToExtended(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
PEXTENDED_FILE_ENTRY ExFileEntry;
|
|
PFILE_ENTRY FileEntry;
|
|
uint32 Length, NewLength, l;
|
|
OSSTATUS status;
|
|
SIZE_T ReadBytes;
|
|
|
|
if(!FileInfo) return STATUS_INVALID_PARAMETER;
|
|
ValidateFileInfo(FileInfo);
|
|
if(FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) return STATUS_SUCCESS;
|
|
if(FileInfo->Dloc->FileEntry->tagIdent != TID_FILE_ENTRY) return STATUS_INVALID_PARAMETER;
|
|
|
|
/* if(!OS_SUCCESS(status = UDFFlushFile__(Vcb, FileInfo)))
|
|
return status;*/
|
|
|
|
Length = FileInfo->Dloc->FileEntryLen;
|
|
NewLength = Length - sizeof(FILE_ENTRY) + sizeof(EXTENDED_FILE_ENTRY);
|
|
ExFileEntry = (PEXTENDED_FILE_ENTRY)MyAllocatePoolTag__(NonPagedPool, NewLength, MEM_XFE_TAG);
|
|
if(!ExFileEntry) return STATUS_INSUFFICIENT_RESOURCES;
|
|
FileEntry = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
|
|
RtlZeroMemory(ExFileEntry, NewLength);
|
|
|
|
ExFileEntry->descTag.tagIdent = TID_EXTENDED_FILE_ENTRY;
|
|
ExFileEntry->icbTag = FileEntry->icbTag;
|
|
ExFileEntry->uid = FileEntry->uid;
|
|
ExFileEntry->gid = FileEntry->gid;
|
|
ExFileEntry->permissions = FileEntry->permissions;
|
|
ExFileEntry->fileLinkCount = FileEntry->fileLinkCount;
|
|
ExFileEntry->recordFormat = FileEntry->recordFormat;
|
|
ExFileEntry->recordDisplayAttr = FileEntry->recordDisplayAttr;
|
|
ExFileEntry->recordLength = FileEntry->recordLength;
|
|
ExFileEntry->informationLength = FileEntry->informationLength;
|
|
ExFileEntry->logicalBlocksRecorded = FileEntry->logicalBlocksRecorded;
|
|
ExFileEntry->accessTime = FileEntry->accessTime;
|
|
ExFileEntry->modificationTime = FileEntry->modificationTime;
|
|
ExFileEntry->attrTime = FileEntry->attrTime;
|
|
ExFileEntry->checkpoint = FileEntry->checkpoint;
|
|
ExFileEntry->extendedAttrICB = FileEntry->extendedAttrICB;
|
|
ExFileEntry->impIdent = FileEntry->impIdent;
|
|
ExFileEntry->uniqueID = FileEntry->uniqueID;
|
|
ExFileEntry->lengthExtendedAttr = FileEntry->lengthExtendedAttr;
|
|
ExFileEntry->lengthAllocDescs = FileEntry->lengthAllocDescs;
|
|
RtlCopyMemory(ExFileEntry+1, FileEntry+1, FileEntry->lengthExtendedAttr);
|
|
RtlCopyMemory((int8*)(ExFileEntry+1)+FileEntry->lengthExtendedAttr, (int8*)(ExFileEntry+1)+FileEntry->lengthExtendedAttr, FileEntry->lengthAllocDescs);
|
|
|
|
if((((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
|
|
|
|
if((l = (uint32)(FileInfo->Dloc->DataLoc.Length))) {
|
|
|
|
int8* tmp_buff = (int8*)MyAllocatePool__(NonPagedPool, l);
|
|
if(!tmp_buff) {
|
|
MyFreePool__(ExFileEntry);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
if(!OS_SUCCESS(status = UDFReadFile__(Vcb, FileInfo, 0, l, FALSE, tmp_buff, &ReadBytes)) ||
|
|
!OS_SUCCESS(status = UDFResizeFile__(Vcb, FileInfo, 0)) ) {
|
|
MyFreePool__(ExFileEntry);
|
|
MyFreePool__(tmp_buff);
|
|
return status;
|
|
}
|
|
FileInfo->Dloc->FELoc.Length =
|
|
FileInfo->Dloc->DataLoc.Offset = NewLength;
|
|
FileInfo->Dloc->FELoc.Modified =
|
|
FileInfo->Dloc->DataLoc.Modified = TRUE;
|
|
MyFreePool__(FileInfo->Dloc->FileEntry);
|
|
FileInfo->Dloc->FileEntry = (tag*)ExFileEntry;
|
|
if(!OS_SUCCESS(status = UDFResizeFile__(Vcb, FileInfo, l)) ||
|
|
!OS_SUCCESS(status = UDFWriteFile__(Vcb, FileInfo, 0, l, FALSE, tmp_buff, &ReadBytes)) ) {
|
|
MyFreePool__(ExFileEntry);
|
|
MyFreePool__(tmp_buff);
|
|
return status;
|
|
}
|
|
MyFreePool__(tmp_buff);
|
|
} else {
|
|
FileInfo->Dloc->FELoc.Length =
|
|
FileInfo->Dloc->DataLoc.Offset = NewLength;
|
|
FileInfo->Dloc->FELoc.Modified =
|
|
FileInfo->Dloc->DataLoc.Modified = TRUE;
|
|
MyFreePool__(FileInfo->Dloc->FileEntry);
|
|
FileInfo->Dloc->FileEntry = (tag*)ExFileEntry;
|
|
}
|
|
} else {
|
|
FileInfo->Dloc->FELoc.Length =
|
|
FileInfo->Dloc->AllocLoc.Offset = NewLength;
|
|
FileInfo->Dloc->FELoc.Modified =
|
|
FileInfo->Dloc->AllocLoc.Modified = TRUE;
|
|
MyFreePool__(FileInfo->Dloc->FileEntry);
|
|
FileInfo->Dloc->FileEntry = (tag*)ExFileEntry;
|
|
}
|
|
FileInfo->Dloc->FileEntryLen = NewLength;
|
|
FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
|
|
if(Vcb->minUDFReadRev < 0x0200)
|
|
Vcb->minUDFReadRev = 0x0200;
|
|
return STATUS_SUCCESS;
|
|
} // end UDFConvertFEToExtended()
|
|
|
|
/*
|
|
This routine makes file almost unavailable for external callers.
|
|
The only way to access Hidden with this routine file is OpenByIndex.
|
|
It is usefull calling this routine to pretend file to be deleted,
|
|
for ex. when we have UDFCleanUp__() or smth. like this in progress,
|
|
but we want to create file with the same name.
|
|
*/
|
|
OSSTATUS
|
|
UDFPretendFileDeleted__(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FileInfo
|
|
)
|
|
{
|
|
AdPrint(("UDFPretendFileDeleted__:\n"));
|
|
|
|
NTSTATUS RC;
|
|
PDIR_INDEX_HDR hDirNdx = UDFGetDirIndexByFileInfo(FileInfo);
|
|
if(!hDirNdx) return STATUS_CANNOT_DELETE;
|
|
PDIR_INDEX_ITEM DirNdx = UDFDirIndex(hDirNdx, FileInfo->Index);
|
|
if(!DirNdx) return STATUS_CANNOT_DELETE;
|
|
|
|
|
|
// we can't hide file that is not marked as deleted
|
|
RC = UDFDoesOSAllowFilePretendDeleted__(FileInfo);
|
|
if(!NT_SUCCESS(RC))
|
|
return RC;
|
|
|
|
AdPrint(("UDFPretendFileDeleted__: set UDF_FI_FLAG_FI_INTERNAL\n"));
|
|
|
|
DirNdx->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
|
|
if(DirNdx->FName.Buffer) {
|
|
MyFreePool__(DirNdx->FName.Buffer);
|
|
DirNdx->FName.Buffer = NULL;
|
|
DirNdx->FName.Length =
|
|
DirNdx->FName.MaximumLength = 0;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
} // end UDFPretendFileDeleted__()
|
|
#endif //UDF_READ_ONLY_BUILD
|