1 /*************************************************************************
2 vStrip by [maven] (maven@maven.de)
3 udf.c: routines for udf-parsing (because windows just doesn't cut it),
4 refs: udf102.pdf, udf200.pdf, ecma 167
6 *************************************************************************/
11 static bool aspi_GetSectorInfo(const HANDLE hDrive
, DWORD
* sec_size
, DWORD
* max_sec
)
14 size
.LowPart
= GetFileSize(hDrive
, (DWORD
*)&size
.HighPart
);
17 *max_sec
= size
.QuadPart
/ *sec_size
;
22 static bool aspi_ReadSectors(const HANDLE hDrive
, int lba
, int nSectors
, DWORD sec_size
, BYTE
* sector
)
25 return lba
*sec_size
== SetFilePointer(hDrive
, lba
*sec_size
, NULL
, FILE_BEGIN
)
26 && ReadFile(hDrive
, sector
, nSectors
*sec_size
, &nbr
, NULL
);
29 static bool udf_GetLBA(const tp_udf_FileEntry fe
, const DWORD sec_size
, DWORD
*start
, DWORD
*end
)
31 if (fe
->LengthofAllocationDescriptors
== 0)
33 switch (fe
->ICBTag
.Flags
& udf_icbf_Mask
)
35 case udf_icbf_ShortAd
:
37 tp_udf_short_ad ad
= (tp_udf_short_ad
)(fe
->ExtendedAttributes
+ fe
->LengthofExtendedAttributes
);
39 *start
= ad
->Location
;
40 *end
= *start
+ ((ad
->Length
& udf_LengthMask
) - 1) / sec_size
;
46 tp_udf_long_ad ad
= (tp_udf_long_ad
)(fe
->ExtendedAttributes
+ fe
->LengthofExtendedAttributes
);
48 *start
= ad
->Location
.Location
; // ignore partition number
49 *end
= *start
+ ((ad
->Length
& udf_LengthMask
) - 1) / sec_size
;
55 tp_udf_ext_ad ad
= (tp_udf_ext_ad
)(fe
->ExtendedAttributes
+ fe
->LengthofExtendedAttributes
);
57 *start
= ad
->Location
.Location
; // ignore partition number
58 *end
= *start
+ ((ad
->Length
& udf_LengthMask
) - 1) / sec_size
;
66 tp_udf_file
udf_get_root(const HANDLE hDrive
, const WORD partition_number
)
68 BYTE sector
[fio_SECTOR_SIZE
];
69 tp_udf_tag tag
= (tp_udf_tag
)sector
;
70 DWORD sec_size
, max_sec
, i
, j
;
71 DWORD MVDS_lba
, MVDS_lba_end
, MVDS_back_lba
, MVDS_back_lba_end
;
72 DWORD FileDescriptorSequence_lba
, FileDescriptorSequence_lba_end
;
73 DWORD partition_lba
, parent_icb
;
74 tp_udf_AnchorVolumeDescriptorPointer avd
;
75 bool res
, part_valid
, vol_valid
;
77 if (!aspi_GetSectorInfo(hDrive
, &sec_size
, &max_sec
))
80 if (sec_size
!= fio_SECTOR_SIZE
|| max_sec
< 256)
83 // read AnchorVolumeDescriptorPointer at 256 (or MaxSec) (Tag == 2)
84 res
= aspi_ReadSectors(hDrive
, 256, 1, sec_size
, sector
);
85 if (!res
|| tag
->TagIdentifier
!= udf_TAG_AnchorVolumeDescriptor
)
87 res
= aspi_ReadSectors(hDrive
, max_sec
, 1, sec_size
, sector
);
88 if (!res
|| tag
->TagIdentifier
!= udf_TAG_AnchorVolumeDescriptor
)
92 // check Static Structures
94 // get MainVolumeDescriptorSequence Location & Length
95 avd
= (tp_udf_AnchorVolumeDescriptorPointer
)sector
;
96 MVDS_lba
= avd
->MainVolumeDescriptorSequenceExtent
.Location
;
97 MVDS_lba_end
= MVDS_lba
+ (avd
->MainVolumeDescriptorSequenceExtent
.Length
- 1) / sec_size
;
98 MVDS_back_lba
= avd
->ReserveVolumeDescriptorSequenceExtent
.Location
;
99 MVDS_back_lba_end
= MVDS_back_lba
+ (avd
->ReserveVolumeDescriptorSequenceExtent
.Length
- 1) / sec_size
;
101 // read MVDS_Location..MVDS_Location + (MVDS_Length - 1) / SectorSize sectors
103 part_valid
= vol_valid
= false;
106 { // try twice (if we need to) for ReserveAnchor
110 res
= aspi_ReadSectors(hDrive
, j
++, 1, sec_size
, sector
);
113 if (tag
->TagIdentifier
== udf_TAG_PartitionDescriptor
&& !part_valid
)
114 { // get stuff out of partition
115 tp_udf_PartitionDescriptor par
= (tp_udf_PartitionDescriptor
)sector
;
117 part_valid
= par
->PartitionNumber
== partition_number
;
119 { // extract par->PartitionStartingLocation, par->PartitionLength
120 partition_lba
= par
->PartitionStartingLocation
;
123 else if (tag
->TagIdentifier
== udf_TAG_LogicalVolumeDescriptor
&& !vol_valid
)
124 { // get stuff out of volume
125 tp_udf_LogicalVolumeDescriptor vol
= (tp_udf_LogicalVolumeDescriptor
)sector
;
127 // check_volume sector size
128 vol_valid
= (vol
->LogicalBlockSize
== sec_size
) && (partition_number
== vol
->FileSetDescriptorSequence
.Location
.PartitionNumber
);
130 { // extract vol->FileSetDescriptorSequence
131 FileDescriptorSequence_lba
= vol
->FileSetDescriptorSequence
.Location
.Location
;
132 FileDescriptorSequence_lba_end
= FileDescriptorSequence_lba
+ ((vol
->FileSetDescriptorSequence
.Length
& udf_LengthMask
) - 1) / sec_size
;
137 tag
->TagIdentifier
= 0;
138 } while (j
<= MVDS_lba_end
&& tag
->TagIdentifier
!= udf_TAG_TerminatingDescriptor
&& ((!part_valid
) || (!vol_valid
)));
140 if ((!part_valid
) || (!vol_valid
))
142 MVDS_lba
= MVDS_back_lba
;
143 MVDS_lba_end
= MVDS_back_lba_end
;
145 } while (i
-- && ((!part_valid
) || (!vol_valid
)));
147 if (part_valid
&& vol_valid
)
148 { // read FileSetDescriptor, get RootDir Location & Length, RootDir Length != 0
149 res
= aspi_ReadSectors(hDrive
, FileDescriptorSequence_lba
+ partition_lba
, 1, sec_size
, sector
);
150 if (res
&& tag
->TagIdentifier
== udf_TAG_FileSetDescriptor
)
152 tp_udf_FileSetDescriptor fsd
= (tp_udf_FileSetDescriptor
)sector
;
154 if (partition_number
== fsd
->RootDirectoryICB
.Location
.PartitionNumber
)
156 parent_icb
= fsd
->RootDirectoryICB
.Location
.Location
;
157 res
= aspi_ReadSectors(hDrive
, partition_lba
+ parent_icb
, 1, sec_size
, sector
);
158 if (res
&& tag
->TagIdentifier
== udf_TAG_FileEntry
)
160 tp_udf_FileEntry fe
= (tp_udf_FileEntry
)sector
;
162 if (fe
->ICBTag
.FileType
== udf_FT_Directory
)
164 tp_udf_file root
= (tp_udf_file
)malloc(sizeof *root
);
166 root
->partition_lba
= partition_lba
;
167 udf_GetLBA(fe
, sec_size
, &root
->dir_lba
, &root
->dir_end_lba
);
168 root
->dir_left
= (DWORD
)fe
->InformationLength
; // don't want directories of more than 4gb
171 root
->sec_size
= sec_size
;
172 strcpy(root
->name
, "/");
174 root
->is_parent
= false;
185 static void udf_GetName(const BYTE
*data
, const DWORD len
, char *target
)
189 if (len
== 0 || !(data
[0] & 0x18))
193 { // ignore MSB of unicode16
197 target
[i
++] = data
[p
+= 2];
202 target
[i
++] = data
[p
++];
208 tp_udf_file
udf_get_sub(const HANDLE hDrive
, tp_udf_file f
)
210 if (f
->is_dir
&& !f
->is_parent
&& f
->fid
)
212 BYTE sector
[fio_SECTOR_SIZE
];
213 tp_udf_tag tag
= (tp_udf_tag
)sector
;
216 res
= aspi_ReadSectors(hDrive
, f
->partition_lba
+ f
->fid
->ICB
.Location
.Location
, 1, f
->sec_size
, sector
);
217 if (res
&& tag
->TagIdentifier
== udf_TAG_FileEntry
)
219 tp_udf_FileEntry fe
= (tp_udf_FileEntry
)sector
;
221 if (fe
->ICBTag
.FileType
== udf_FT_Directory
)
223 tp_udf_file newf
= (tp_udf_file
)malloc(sizeof *newf
);
225 strcpy(newf
->name
, f
->name
); // maybe just ""?
226 newf
->sec_size
= f
->sec_size
;
227 newf
->partition_lba
= f
->partition_lba
;
228 udf_GetLBA(fe
, f
->sec_size
, &newf
->dir_lba
, &newf
->dir_end_lba
);
229 newf
->dir_left
= (DWORD
)fe
->InformationLength
; // don't want directories of more than 4gb
233 newf
->is_parent
= false;
241 tp_udf_file
udf_get_next(const HANDLE hDrive
, tp_udf_file f
)
245 if (f
->dir_left
<= 0)
252 { // advance to next FileIdentifierDescriptor
253 DWORD ofs
= 4 * ((sizeof *(f
->fid
) + f
->fid
->LengthofImplementationUse
+ f
->fid
->LengthofFileIdentifier
+ 3) / 4);
255 f
->fid
= (tp_udf_FileIdentifierDescriptor
)((BYTE
*)f
->fid
+ ofs
);
260 DWORD size
= f
->sec_size
* (f
->dir_end_lba
- f
->dir_lba
+ 1);
263 f
->sector
= (BYTE
*)malloc(size
);
264 res
= aspi_ReadSectors(hDrive
, f
->partition_lba
+ f
->dir_lba
, (WORD
)(f
->dir_end_lba
- f
->dir_lba
+ 1), f
->sec_size
, f
->sector
);
266 f
->fid
= (tp_udf_FileIdentifierDescriptor
)f
->sector
;
271 if (f
->fid
&& f
->fid
->DescriptorTag
.TagIdentifier
== udf_TAG_FileIdentifierDescriptor
)
273 DWORD ofs
= 4 * ((sizeof *f
->fid
+ f
->fid
->LengthofImplementationUse
+ f
->fid
->LengthofFileIdentifier
+ 3) / 4);
276 f
->is_dir
= (f
->fid
->FileCharacteristics
& udf_FID_Directory
) != 0;
277 f
->is_parent
= (f
->fid
->FileCharacteristics
& udf_FID_Parent
) != 0;
278 udf_GetName(f
->fid
->ImplementationUse
+ f
->fid
->LengthofImplementationUse
, f
->fid
->LengthofFileIdentifier
, f
->name
);
284 void udf_free(tp_udf_file f
)
294 #define udf_PATH_DELIMITERS "/\\"
296 static tp_udf_file
udf_ff_traverse(const HANDLE hDrive
, tp_udf_file f
, char *token
)
298 while (udf_get_next(hDrive
, f
))
300 if (stricmp(token
, f
->name
) == 0)
302 char *next_tok
= strtok(NULL
, udf_PATH_DELIMITERS
);
308 tp_udf_file f2
= udf_get_sub(hDrive
, f
);
312 tp_udf_file f3
= udf_ff_traverse(hDrive
, f2
, next_tok
);
324 tp_udf_file
udf_find_file(const HANDLE hDrive
, const WORD partition
, const char *name
)
326 tp_udf_file f
= udf_get_root(hDrive
, partition
), f2
= NULL
;
330 char tokenline
[udf_MAX_PATHLEN
];
333 strcpy(tokenline
, name
);
334 token
= strtok(tokenline
, udf_PATH_DELIMITERS
);
336 f2
= udf_ff_traverse(hDrive
, f
, token
);
342 bool udf_get_lba(const HANDLE hDrive
, const tp_udf_file f
, DWORD
*start_lba
, DWORD
*end_lba
)
347 tp_udf_FileEntry fe
= (tp_udf_FileEntry
)sector
;
350 res
= aspi_ReadSectors(hDrive
, f
->partition_lba
+ f
->fid
->ICB
.Location
.Location
, 1, f
->sec_size
, sector
);
351 if (res
&& fe
->DescriptorTag
.TagIdentifier
== udf_TAG_FileEntry
)
352 return udf_GetLBA(fe
, f
->sec_size
, start_lba
, end_lba
);