00001
00002
00003
00004
00005
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;
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;
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
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
00093
00094
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
00102
00103 part_valid = vol_valid = false;
00104 i = 1;
00105 do
00106 {
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 {
00115 tp_udf_PartitionDescriptor par = (tp_udf_PartitionDescriptor )sector;
00116
00117 part_valid = par->PartitionNumber == partition_number;
00118 if (part_valid)
00119 {
00120 partition_lba = par->PartitionStartingLocation;
00121 }
00122 }
00123 else if (tag->TagIdentifier == udf_TAG_LogicalVolumeDescriptor && !vol_valid)
00124 {
00125 tp_udf_LogicalVolumeDescriptor vol = (tp_udf_LogicalVolumeDescriptor)sector;
00126
00127
00128 vol_valid = (vol->LogicalBlockSize == sec_size) && (partition_number == vol->FileSetDescriptorSequence.Location.PartitionNumber);
00129 if (vol_valid)
00130 {
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 {
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 {
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;
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 {
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);
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;
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 {
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;
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 }