udf.cpp

00001 /*************************************************************************
00002   vStrip by [maven] ([email protected])
00003         udf.c:  routines for udf-parsing (because windows just doesn't cut it),
00004                                         refs: udf102.pdf, udf200.pdf, ecma 167
00005                                         (tabsize 2)
00006 *************************************************************************/
00007 
00008 #include "stdafx.h"
00009 #include "udf.h"
00010 
00011 static bool aspi_GetSectorInfo(const HANDLE hDrive, DWORD* sec_size, DWORD* max_sec)
00012 {
00013         LARGE_INTEGER size;
00014         size.LowPart = GetFileSize(hDrive, (DWORD*)&size.HighPart);
00015 
00016         *sec_size = 2048;
00017         *max_sec = size.QuadPart / *sec_size;
00018 
00019         return true;
00020 }
00021 
00022 static bool aspi_ReadSectors(const HANDLE hDrive, int lba, int nSectors, DWORD sec_size, BYTE* sector)
00023 {
00024         DWORD nbr = 0;
00025         return lba*sec_size == SetFilePointer(hDrive, lba*sec_size, NULL, FILE_BEGIN)
00026                 && ReadFile(hDrive, sector, nSectors*sec_size, &nbr, NULL);
00027 }
00028 
00029 static bool udf_GetLBA(const tp_udf_FileEntry fe, const DWORD sec_size, DWORD *start, DWORD *end)
00030 {
00031         if (fe->LengthofAllocationDescriptors == 0)
00032                 return false;
00033         switch (fe->ICBTag.Flags & udf_icbf_Mask)
00034         {
00035                 case udf_icbf_ShortAd:
00036                 {
00037                         tp_udf_short_ad ad = (tp_udf_short_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes);
00038 
00039                         *start = ad->Location;
00040                         *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size;
00041                         return true;
00042                 }
00043                 break;
00044                 case udf_icbf_LongAd:
00045                 {
00046                         tp_udf_long_ad ad = (tp_udf_long_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes);
00047 
00048                         *start = ad->Location.Location; // ignore partition number
00049                         *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size;
00050                         return true;
00051                 }
00052                 break;
00053                 case udf_icbf_ExtAd:
00054                 {
00055                         tp_udf_ext_ad ad = (tp_udf_ext_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes);
00056 
00057                         *start = ad->Location.Location; // ignore partition number
00058                         *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size;
00059                         return true;
00060                 }
00061                 break;
00062         }
00063         return false;
00064 }
00065 
00066 tp_udf_file udf_get_root(const HANDLE hDrive, const WORD partition_number)
00067 {
00068         BYTE sector[fio_SECTOR_SIZE];
00069         tp_udf_tag tag = (tp_udf_tag)sector;
00070         DWORD sec_size, max_sec, i, j;
00071         DWORD MVDS_lba, MVDS_lba_end, MVDS_back_lba, MVDS_back_lba_end;
00072         DWORD   FileDescriptorSequence_lba, FileDescriptorSequence_lba_end;
00073         DWORD partition_lba, parent_icb;
00074         tp_udf_AnchorVolumeDescriptorPointer avd;
00075         bool res, part_valid, vol_valid;
00076 
00077         if (!aspi_GetSectorInfo(hDrive, &sec_size, &max_sec))
00078                 return NULL;
00079 
00080         if (sec_size != fio_SECTOR_SIZE || max_sec < 256)
00081                 return NULL;
00082         
00083         // read AnchorVolumeDescriptorPointer at 256 (or MaxSec) (Tag == 2)
00084         res = aspi_ReadSectors(hDrive, 256, 1, sec_size, sector);
00085         if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor)
00086         {
00087                 res = aspi_ReadSectors(hDrive, max_sec, 1, sec_size, sector);
00088                 if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor)
00089                         return NULL;
00090         }
00091         
00092         // check Static Structures
00093         
00094         // get MainVolumeDescriptorSequence Location & Length
00095         avd = (tp_udf_AnchorVolumeDescriptorPointer)sector;
00096         MVDS_lba = avd->MainVolumeDescriptorSequenceExtent.Location;
00097         MVDS_lba_end = MVDS_lba + (avd->MainVolumeDescriptorSequenceExtent.Length - 1) / sec_size;
00098         MVDS_back_lba = avd->ReserveVolumeDescriptorSequenceExtent.Location;
00099         MVDS_back_lba_end = MVDS_back_lba + (avd->ReserveVolumeDescriptorSequenceExtent.Length - 1) / sec_size;
00100 
00101         // read MVDS_Location..MVDS_Location + (MVDS_Length - 1) / SectorSize sectors
00102 
00103         part_valid = vol_valid = false;
00104         i = 1;
00105         do
00106         { // try twice (if we need to) for ReserveAnchor
00107                 j = MVDS_lba;
00108                 do
00109                 {
00110                         res = aspi_ReadSectors(hDrive, j++, 1, sec_size, sector);
00111                         if (res)
00112                         {
00113                                 if (tag->TagIdentifier == udf_TAG_PartitionDescriptor && !part_valid)
00114                                 {       // get stuff out of partition
00115                                         tp_udf_PartitionDescriptor par = (tp_udf_PartitionDescriptor )sector;
00116 
00117                                         part_valid = par->PartitionNumber == partition_number;
00118                                         if (part_valid)
00119                                         { // extract par->PartitionStartingLocation, par->PartitionLength
00120                                                 partition_lba = par->PartitionStartingLocation;
00121                                         }
00122                                 }
00123                                 else if (tag->TagIdentifier == udf_TAG_LogicalVolumeDescriptor && !vol_valid)
00124                                 { // get stuff out of volume
00125                                         tp_udf_LogicalVolumeDescriptor vol = (tp_udf_LogicalVolumeDescriptor)sector;
00126 
00127                                         // check_volume sector size
00128                                         vol_valid = (vol->LogicalBlockSize == sec_size) && (partition_number == vol->FileSetDescriptorSequence.Location.PartitionNumber);
00129                                         if (vol_valid)
00130                                         { // extract vol->FileSetDescriptorSequence
00131                                                 FileDescriptorSequence_lba = vol->FileSetDescriptorSequence.Location.Location;
00132                                                 FileDescriptorSequence_lba_end = FileDescriptorSequence_lba + ((vol->FileSetDescriptorSequence.Length & udf_LengthMask) - 1) / sec_size;
00133                                         }
00134                                 }
00135                         }
00136                         else
00137                                 tag->TagIdentifier = 0;
00138                 } while (j <= MVDS_lba_end && tag->TagIdentifier != udf_TAG_TerminatingDescriptor && ((!part_valid) || (!vol_valid)));
00139 
00140                 if ((!part_valid) || (!vol_valid)) 
00141                 { // try backup
00142                         MVDS_lba = MVDS_back_lba;
00143                         MVDS_lba_end = MVDS_back_lba_end;
00144                 }
00145         } while (i-- && ((!part_valid) || (!vol_valid)));
00146 
00147         if (part_valid && vol_valid)
00148         { // read FileSetDescriptor, get RootDir Location & Length, RootDir Length != 0
00149                 res = aspi_ReadSectors(hDrive, FileDescriptorSequence_lba + partition_lba, 1, sec_size, sector);
00150                 if (res && tag->TagIdentifier == udf_TAG_FileSetDescriptor)
00151                 {
00152                         tp_udf_FileSetDescriptor fsd = (tp_udf_FileSetDescriptor)sector;
00153 
00154                         if (partition_number == fsd->RootDirectoryICB.Location.PartitionNumber)
00155                         {
00156                                 parent_icb = fsd->RootDirectoryICB.Location.Location;
00157                                 res = aspi_ReadSectors(hDrive, partition_lba + parent_icb, 1, sec_size, sector);
00158                                 if (res && tag->TagIdentifier == udf_TAG_FileEntry)
00159                                 {
00160                                         tp_udf_FileEntry fe = (tp_udf_FileEntry)sector;
00161 
00162                                         if (fe->ICBTag.FileType == udf_FT_Directory)
00163                                         {
00164                                                 tp_udf_file root = (tp_udf_file)malloc(sizeof *root);
00165 
00166                                                 root->partition_lba = partition_lba;
00167                                                 udf_GetLBA(fe, sec_size, &root->dir_lba, &root->dir_end_lba);
00168                                                 root->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb
00169                                                 root->sector = NULL;
00170                                                 root->fid = NULL;
00171                                                 root->sec_size = sec_size;
00172                                                 strcpy(root->name, "/");
00173                                                 root->is_dir = true;
00174                                                 root->is_parent = false;
00175                                                 return root;
00176                                         }
00177                                 }
00178                         }
00179                 }
00180         }
00181         
00182         return NULL;
00183 }
00184 
00185 static void udf_GetName(const BYTE *data, const DWORD len, char *target)
00186 {
00187         DWORD p = 1, i = 0;
00188 
00189         if (len == 0 || !(data[0] & 0x18))
00190                 target[0] = '\0';
00191 
00192         if (data[0] & 0x10)
00193         {       // ignore MSB of unicode16
00194                 p++;
00195 
00196                 while (p < len)
00197                         target[i++] = data[p += 2];
00198         }
00199         else
00200         {
00201                 while (p < len)
00202                         target[i++] = data[p++];
00203         }
00204 
00205         target[i]='\0';
00206 }
00207 
00208 tp_udf_file udf_get_sub(const HANDLE hDrive, tp_udf_file f)
00209 {
00210         if (f->is_dir && !f->is_parent && f->fid)
00211         {
00212                 BYTE sector[fio_SECTOR_SIZE];
00213                 tp_udf_tag tag = (tp_udf_tag)sector;
00214                 bool res;
00215 
00216                 res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector);
00217                 if (res && tag->TagIdentifier == udf_TAG_FileEntry)
00218                 {
00219                         tp_udf_FileEntry fe = (tp_udf_FileEntry)sector;
00220 
00221                         if (fe->ICBTag.FileType == udf_FT_Directory)
00222                         {
00223                                 tp_udf_file newf = (tp_udf_file)malloc(sizeof *newf);
00224 
00225                                 strcpy(newf->name, f->name); // maybe just ""?
00226                                 newf->sec_size = f->sec_size;
00227                                 newf->partition_lba = f->partition_lba;
00228                                 udf_GetLBA(fe, f->sec_size, &newf->dir_lba, &newf->dir_end_lba);
00229                                 newf->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb
00230                                 newf->sector = NULL;
00231                                 newf->fid = NULL;
00232                                 newf->is_dir = true;
00233                                 newf->is_parent = false;
00234                                 return newf;
00235                         }
00236                 }
00237         }
00238         return NULL;
00239 }
00240 
00241 tp_udf_file udf_get_next(const HANDLE hDrive, tp_udf_file f)
00242 {
00243         bool res = true;
00244 
00245         if (f->dir_left <= 0)
00246         {
00247                 f->fid = NULL;
00248                 return NULL;
00249         }
00250         
00251         if (f->fid)
00252         { // advance to next FileIdentifierDescriptor
00253                 DWORD ofs = 4 * ((sizeof *(f->fid) + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4);
00254 
00255                 f->fid = (tp_udf_FileIdentifierDescriptor)((BYTE *)f->fid + ofs);
00256         }
00257         
00258         if (f->fid == NULL)
00259         {
00260                 DWORD size = f->sec_size * (f->dir_end_lba - f->dir_lba + 1);
00261 
00262                 if (!f->sector)
00263                         f->sector = (BYTE*)malloc(size);
00264                 res = aspi_ReadSectors(hDrive, f->partition_lba + f->dir_lba, (WORD)(f->dir_end_lba - f->dir_lba + 1), f->sec_size, f->sector);
00265                 if (res)
00266                         f->fid = (tp_udf_FileIdentifierDescriptor)f->sector;
00267                 else
00268                         f->fid = NULL;
00269         }
00270         
00271         if (f->fid && f->fid->DescriptorTag.TagIdentifier == udf_TAG_FileIdentifierDescriptor)
00272         {
00273                 DWORD ofs = 4 * ((sizeof *f->fid + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4);
00274 
00275                 f->dir_left -= ofs;
00276                 f->is_dir = (f->fid->FileCharacteristics & udf_FID_Directory) != 0;
00277                 f->is_parent = (f->fid->FileCharacteristics & udf_FID_Parent) != 0;
00278                 udf_GetName(f->fid->ImplementationUse + f->fid->LengthofImplementationUse, f->fid->LengthofFileIdentifier, f->name);
00279                 return f;
00280         }
00281         return NULL;
00282 }
00283 
00284 void udf_free(tp_udf_file f)
00285 {
00286         if (f)
00287         {
00288                 if (f->sector)
00289                         free(f->sector);
00290                 free(f);
00291         }
00292 }
00293 
00294 #define udf_PATH_DELIMITERS "/\\"
00295 
00296 static tp_udf_file udf_ff_traverse(const HANDLE hDrive, tp_udf_file f, char *token)
00297 {
00298         while (udf_get_next(hDrive, f))
00299         {
00300                 if (stricmp(token, f->name) == 0)
00301                 {
00302                         char *next_tok = strtok(NULL, udf_PATH_DELIMITERS);
00303 
00304                         if (!next_tok)
00305                                 return f; // found
00306                         else if (f->is_dir)
00307                         {
00308                                 tp_udf_file f2 = udf_get_sub(hDrive, f);
00309 
00310                                 if (f2)
00311                                 {
00312                                         tp_udf_file f3 = udf_ff_traverse(hDrive, f2, next_tok);
00313 
00314                                         if (!f3)
00315                                                 udf_free(f2);
00316                                         return f3;
00317                                 }
00318                         }
00319                 }
00320         }
00321         return NULL;
00322 }
00323 
00324 tp_udf_file udf_find_file(const HANDLE hDrive, const WORD partition, const char *name)
00325 {
00326         tp_udf_file f = udf_get_root(hDrive, partition), f2 = NULL;
00327 
00328         if (f)
00329         {
00330                 char tokenline[udf_MAX_PATHLEN];
00331                 char *token;
00332 
00333                 strcpy(tokenline, name);
00334                 token = strtok(tokenline, udf_PATH_DELIMITERS);
00335                 if (token)
00336                         f2 = udf_ff_traverse(hDrive, f, token);
00337                 udf_free(f);
00338         }
00339         return f2;
00340 }
00341 
00342 bool udf_get_lba(const HANDLE hDrive, const tp_udf_file f, DWORD *start_lba, DWORD *end_lba)
00343 {
00344         if (f->fid)
00345         {
00346                 BYTE sector[2048];
00347                 tp_udf_FileEntry fe = (tp_udf_FileEntry)sector;
00348                 bool res;
00349 
00350                 res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector);
00351                 if (res && fe->DescriptorTag.TagIdentifier == udf_TAG_FileEntry)
00352                         return udf_GetLBA(fe, f->sec_size, start_lba, end_lba);
00353         }
00354         return false;
00355 }

Generated on Tue Dec 13 14:47:06 2005 for guliverkli by  doxygen 1.4.5