1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
23 #include "biso_list.h"
24 #include "biso_util.h"
25 #include "biso_9660.h"
26 #include "biso_dump.h"
27 #include "biso_rockridge.h"
29 /* Rock Ridge扩展处理函数数组, NULL表示暂时不处理这类表项 */
30 STATIC BISO_RRIP_PARSE_ENTRY_CB_S g_astBISO_RRIP_ParseFunc
[] =
39 { "PX", BISO_RRIP_GetPXInfo
},
40 { "PN", BISO_RRIP_GetPNInfo
},
41 { "SL", BISO_RRIP_GetSLInfo
},
42 { "NM", BISO_RRIP_GetNMInfo
},
46 { "TF", BISO_RRIP_GetTFInfo
},
50 STATIC VOID BISO_RRIP_AddLinkBuf
54 INOUT BISO_POSIX_INFO_S
*pstPosixInfo
57 CHAR
*pcNewBuf
= NULL
;
59 DBGASSERT(NULL
!= pstPosixInfo
);
60 DBGASSERT(NULL
!= pcBuf
);
63 * 这里采用的是最简单的每次重新申请大内存保存老数据和新数据的方式
64 * 实际上效率是比较低的,但是由于普通ISO文件中link类型本身就不多
65 * 而有连续多条SL表项的就更少了,所以这里只是简单实现功能,没有特别考虑效率
68 /* 申请一个新Buf用于保存原有的数据和这次的新数据 */
69 pcNewBuf
= (CHAR
*)BISO_ZALLOC(uiBufLen
+ pstPosixInfo
->uiLinkLen
);
75 if (NULL
== pstPosixInfo
->pcLinkSrc
)
77 memcpy(pcNewBuf
, pcBuf
, uiBufLen
);
81 /* 分别保存新老数据,同时把老的Buf释放掉 */
82 memcpy(pcNewBuf
, pstPosixInfo
->pcLinkSrc
, pstPosixInfo
->uiLinkLen
);
83 memcpy(pcNewBuf
+ pstPosixInfo
->uiLinkLen
, pcBuf
, uiBufLen
);
84 BISO_FREE(pstPosixInfo
->pcLinkSrc
);
88 pstPosixInfo
->pcLinkSrc
= pcNewBuf
;
89 pstPosixInfo
->uiLinkLen
+= uiBufLen
;
92 STATIC UINT BISO_RRIP_CalcLinkLen
94 IN CONST CHAR
*pcComponet
,
101 BISO_RRIP_SL_COMPONENT_S
*pstComp
= NULL
;
103 DBGASSERT(NULL
!= pcComponet
);
104 DBGASSERT(uiComponetLen
> 0);
107 while (uiOffset
< uiComponetLen
)
110 pstComp
= (BISO_RRIP_SL_COMPONENT_S
*)(pcComponet
+ uiOffset
);
112 if (BOOL_TRUE
== BISO_SLCOMP_IS_ROOT(pstComp
->ucFlags
))
114 /* ROOT不需处理,后面会添加/ */
116 else if (BOOL_TRUE
== BISO_SLCOMP_IS_CURRENT(pstComp
->ucFlags
))
118 uiBufLen
= 1; /* . */
120 else if (BOOL_TRUE
== BISO_SLCOMP_IS_PARENT(pstComp
->ucFlags
))
122 uiBufLen
= 2; /* .. */
126 uiBufLen
= pstComp
->ucLength
;
129 /* ucLength不包括头两个字节 */
130 uiOffset
+= pstComp
->ucLength
+ 2;
133 * 如果是link路径的一部分完结,则需要在后面加上'/',否则不加.
134 * 不加的情况有两种: 1是整体已经完了 2是路径的一部分还没有完整
135 * 比如说链接的位置是 /root/xxxx/a.txt 而xxxx可能非常长(200+个字符)
136 * 那么此时光xxxx的部分可能就需要两个Componet部分才能表达完,而这两个
139 if ((uiOffset
< uiComponetLen
) && (BOOL_TRUE
!= BISO_SLCOMP_IS_CONTINUE(pstComp
->ucFlags
)))
144 uiTotLen
+= uiBufLen
;
150 STATIC UINT BISO_RRIP_GetPartLink
152 IN CONST BISO_RRIP_SL_COMPONENT_S
*pstComponent
,
159 DBGASSERT(NULL
!= pstComponent
);
160 DBGASSERT(NULL
!= pcBuf
);
162 if (BOOL_TRUE
== BISO_SLCOMP_IS_ROOT(pstComponent
->ucFlags
))
164 /* ROOT不需处理,后面会添加/ */
166 else if (BOOL_TRUE
== BISO_SLCOMP_IS_CURRENT(pstComponent
->ucFlags
))
168 scnprintf(pcBuf
, uiBufSize
, ".");
171 else if (BOOL_TRUE
== BISO_SLCOMP_IS_PARENT(pstComponent
->ucFlags
))
173 scnprintf(pcBuf
, uiBufSize
, "..");
178 memcpy(pcBuf
, pstComponent
->aucData
, pstComponent
->ucLength
);
179 uiBufLen
= pstComponent
->ucLength
;
185 STATIC BOOL_T
BISO_RRIP_IsThisType(IN BISO_SUSP_ENTRY_S
*pstEntry
, IN CONST CHAR
*pcType
)
187 if (NULL
== pstEntry
|| NULL
== pcType
)
192 if ((pstEntry
->cSignature1
== pcType
[0]) && (pstEntry
->cSignature2
== pcType
[1]))
200 STATIC UCHAR
* BISO_RRIP_GetSysUseArea
202 IN BISO_FILE_S
*pstFile
,
203 IN UCHAR
*pucSysUseField
,
204 IN UINT uiSysUseFieldLen
,
205 OUT UINT
*puiAreaSize
212 UCHAR
*pucSysUseArea
= NULL
;
213 BISO_SUSP_ENTRY_S
*pstEntry
= NULL
;
214 BISO_SUSP_ENTRY_CE_S
*pstCEEntry
= NULL
;
216 DBGASSERT(NULL
!= pstFile
);
217 DBGASSERT(NULL
!= pucSysUseField
);
218 DBGASSERT(NULL
!= puiAreaSize
);
221 * 虽然Rock Ridge扩展标准中允许整个System Use Area中有多个CE表项来扩展,
222 * 但是由于一条CE表项可以扩展的长度就足够了(32bit) 所以这里我感觉正常情况下
223 * 没有必要使用多个CE表项扩展空间。因此这里只支持1条CE表项的情况。
226 /* 遍历当前System Use Field, 标准规定剩余空间小于4字节,则后面的忽略 */
227 for (uiCurPos
= 0; uiCurPos
+ 4 < uiSysUseFieldLen
; uiCurPos
+= pstEntry
->ucEntryLen
)
229 pstEntry
= (BISO_SUSP_ENTRY_S
*)(pucSysUseField
+ uiCurPos
);
231 /* 找到1个CE表项就停止,这里默认CE表项是最后一条表项 */
232 if (BOOL_TRUE
== BISO_RRIP_IsThisType(pstEntry
, "CE"))
234 pstCEEntry
= (BISO_SUSP_ENTRY_CE_S
*)pstEntry
;
235 uiCELen
= pstCEEntry
->uiContinuationLen
;
236 /* BISO_DUMP_ShowSUSPEntry(pstCEEntry); */
241 /* 申请一块内存把这两部分合并起来 */
242 pucSysUseArea
= (UCHAR
*)BISO_MALLOC(uiCurPos
+ uiCELen
);
243 if (NULL
== pucSysUseArea
)
248 /* 先拷贝System Use Field字段 */
249 memcpy(pucSysUseArea
, pucSysUseField
, uiCurPos
);
251 /* 如果有CE表项则再同文件中读出CE部分的数据 */
252 if (NULL
!= pstCEEntry
)
254 ui64Seek
= (UINT64
)pstCEEntry
->uiBlockLoc
* BISO_BLOCK_SIZE
+ pstCEEntry
->uiByteOffset
;
255 BISO_PLAT_SeekFile(pstFile
, ui64Seek
, SEEK_SET
);
256 uiReadLen
= (UINT
)BISO_PLAT_ReadFile(pstFile
, 1, uiCELen
, pucSysUseArea
+ uiCurPos
);
257 if (uiReadLen
!= uiCELen
)
259 BISO_DIAG("Read len %u buf len %u.", uiReadLen
, uiCELen
);
260 BISO_FREE(pucSysUseArea
);
265 *puiAreaSize
= uiCurPos
+ uiCELen
;
266 return pucSysUseArea
;
269 VOID
BISO_RRIP_GetPXInfo(IN VOID
*pEntry
, OUT BISO_DIR_TREE_S
*pstDirTree
)
271 BISO_POSIX_INFO_S
*pstPosixInfo
= NULL
;
272 BISO_ROCK_RIDGE_ENTRY_PX_S
*pstPXEntry
= NULL
;
274 DBGASSERT(NULL
!= pEntry
);
275 DBGASSERT(NULL
!= pstDirTree
);
276 DBGASSERT(NULL
!= pstDirTree
->pstPosixInfo
);
278 pstPXEntry
= (BISO_ROCK_RIDGE_ENTRY_PX_S
*)pEntry
;
279 pstPosixInfo
= pstDirTree
->pstPosixInfo
;
281 pstPosixInfo
->uiPosixFileMode
= pstPXEntry
->uiPosixFileMode
;
282 pstPosixInfo
->uiPosixFileLink
= pstPXEntry
->uiPosixFileLink
;
283 pstPosixInfo
->uiPosixFileUserId
= pstPXEntry
->uiPosixFileUserId
;
284 pstPosixInfo
->uiPosixFileGroupId
= pstPXEntry
->uiPosixFileGroupId
;
285 pstPosixInfo
->uiPosixFileSNO
= pstPXEntry
->uiPosixFileSNO
;
288 VOID
BISO_RRIP_GetNMInfo(IN VOID
*pEntry
, OUT BISO_DIR_TREE_S
*pstDirTree
)
290 BISO_ROCK_RIDGE_ENTRY_NM_S
*pstNMEntry
= NULL
;
292 DBGASSERT(NULL
!= pEntry
);
293 DBGASSERT(NULL
!= pstDirTree
);
294 DBGASSERT(NULL
!= pstDirTree
->pstPosixInfo
);
296 pstNMEntry
= (BISO_ROCK_RIDGE_ENTRY_NM_S
*)pEntry
;
298 /* 如有NM表项就替换ISO9660文件名 */
299 if (BOOL_TRUE
!= pstDirTree
->pstPosixInfo
->bHasNMEntry
)
301 pstDirTree
->pstPosixInfo
->bHasNMEntry
= BOOL_TRUE
;
302 memset(pstDirTree
->szName
, 0, sizeof(pstDirTree
->szName
));
303 pstDirTree
->usNameLen
= 0;
307 * 拼接文件名, 有可能本函数会多次调用,多次拼接(文件名超长的情况)
308 * TODO: 是否需要关注字符编码???
310 strncat(pstDirTree
->szName
, pstNMEntry
->szFileName
, pstNMEntry
->ucEntryLen
- 5);
311 pstDirTree
->usNameLen
+= pstNMEntry
->ucEntryLen
- 5;
314 VOID
BISO_RRIP_GetTFInfo(IN VOID
*pEntry
, OUT BISO_DIR_TREE_S
*pstDirTree
)
317 UCHAR
*pucCur
= NULL
;
318 BISO_DATE_915_S
*pst915Date
= NULL
;
319 BISO_ROCK_RIDGE_ENTRY_TF_S
*pstTFEntry
= NULL
;
320 BISO_DATE_S
*apstDate
[] =
322 &(pstDirTree
->pstPosixInfo
->stCreateTime
),
323 &(pstDirTree
->pstPosixInfo
->stModifyTime
),
324 &(pstDirTree
->pstPosixInfo
->stLastAccessTime
),
325 &(pstDirTree
->pstPosixInfo
->stLastAttrChangeTime
),
326 &(pstDirTree
->pstPosixInfo
->stLastBackupTime
),
327 &(pstDirTree
->pstPosixInfo
->stExpirationTime
),
328 &(pstDirTree
->pstPosixInfo
->stEffectiveTime
)
331 DBGASSERT(NULL
!= pEntry
);
332 DBGASSERT(NULL
!= pstDirTree
);
333 DBGASSERT(NULL
!= pstDirTree
->pstPosixInfo
);
335 pstTFEntry
= (BISO_ROCK_RIDGE_ENTRY_TF_S
*)pEntry
;
336 pucCur
= pstTFEntry
->aucTimeStamp
;
338 for (i
= 0; i
< ARRAY_SIZE(apstDate
); i
++)
341 if (0 == ((pstTFEntry
->ucFlags
>> i
) & 0x1))
346 /* Bit7决定是按照哪种格式记录的 */
347 if ((pstTFEntry
->ucFlags
>> 7) & 0x1)
349 (VOID
)BISO_9660_ParseDate84261((CHAR
*)pucCur
, apstDate
[i
]);
354 pst915Date
= (BISO_DATE_915_S
*)pucCur
;
357 apstDate
[i
]->usYear
= pst915Date
->ucYear
+ 1900;
358 apstDate
[i
]->ucMonth
= pst915Date
->ucMonth
;
359 apstDate
[i
]->ucDay
= pst915Date
->ucDay
;
360 apstDate
[i
]->ucHour
= pst915Date
->ucHour
;
361 apstDate
[i
]->ucMin
= pst915Date
->ucMin
;
362 apstDate
[i
]->ucSecond
= pst915Date
->ucSec
;
363 apstDate
[i
]->usMillSec
= 0;
364 apstDate
[i
]->cZone
= pst915Date
->cTimeZone
/ 4;
369 VOID
BISO_RRIP_GetPNInfo(IN VOID
*pEntry
, OUT BISO_DIR_TREE_S
*pstDirTree
)
371 BISO_ROCK_RIDGE_ENTRY_PN_S
*pstPNEntry
= NULL
;
373 DBGASSERT(NULL
!= pEntry
);
374 DBGASSERT(NULL
!= pstDirTree
);
375 DBGASSERT(NULL
!= pstDirTree
->pstPosixInfo
);
377 pstPNEntry
= (BISO_ROCK_RIDGE_ENTRY_PN_S
*)pEntry
;
379 pstDirTree
->pstPosixInfo
->ui64DevNum
= ((UINT64
)(pstPNEntry
->uiDevNumHigh
) << 32) | pstPNEntry
->uiDevNumLow
;
382 VOID
BISO_RRIP_GetSLInfo(IN VOID
*pEntry
, OUT BISO_DIR_TREE_S
*pstDirTree
)
387 UCHAR ucCompentLen
= 0;
388 CHAR
*pcFullLinkPath
= NULL
;
389 BISO_POSIX_INFO_S
*pstPosixInfo
= NULL
;
390 BISO_ROCK_RIDGE_ENTRY_SL_S
*pstSLEntry
= NULL
;
391 BISO_RRIP_SL_COMPONENT_S
*pstComp
= NULL
;
392 CHAR szBuf
[300]; /* 当前Length是用UCHAR存储的,一定不会超过300 */
394 DBGASSERT(NULL
!= pEntry
);
395 DBGASSERT(NULL
!= pstDirTree
);
396 DBGASSERT(NULL
!= pstDirTree
->pstPosixInfo
);
398 pstSLEntry
= (BISO_ROCK_RIDGE_ENTRY_SL_S
*)pEntry
;
399 pstPosixInfo
= pstDirTree
->pstPosixInfo
;
400 ucCompentLen
= pstSLEntry
->ucEntryLen
- 5;
403 * 把所有SL表项的Componet部分拼接起来,如果有连续几条SL表项
404 * 那么当前函数会依次被调用,每次都拼接一部分,直到整个Componet整合完成.
406 BISO_RRIP_AddLinkBuf((CHAR
*)(pstSLEntry
->aucComponet
), ucCompentLen
, pstPosixInfo
);
408 /* FLAG的Bit0为0表示是最后1个SL表项,此时Componet已经整合在一起了,这里直接处理 */
409 if (0 == (pstSLEntry
->ucFlags
& 0x1))
411 /* 申请一段内存用来保存符号链接的源路径 */
412 uiBufLen
= BISO_RRIP_CalcLinkLen(pstPosixInfo
->pcLinkSrc
, pstPosixInfo
->uiLinkLen
);
413 pcFullLinkPath
= (CHAR
*)BISO_MALLOC(uiBufLen
+ 10);
414 if (NULL
== pcFullLinkPath
)
416 BISO_FREE(pstPosixInfo
->pcLinkSrc
);
417 pstPosixInfo
->uiLinkLen
= 0;
422 while (uiOffset
< pstPosixInfo
->uiLinkLen
)
424 pstComp
= (BISO_RRIP_SL_COMPONENT_S
*)(pstPosixInfo
->pcLinkSrc
+ uiOffset
);
425 uiBufLen
= BISO_RRIP_GetPartLink(pstComp
, sizeof(szBuf
), szBuf
);
427 /* ucLength不包括头两个字节 */
428 uiOffset
+= pstComp
->ucLength
+ 2;
431 * 如果是link路径的一部分完结,则需要在后面加上'/',否则不加.
432 * 不加的情况有两种: 1是整体已经完了 2是路径的一部分还没有完整
433 * 比如说链接的位置是 /root/xxxx/a.txt 而xxxx可能非常长(200+个字符)
434 * 那么此时光xxxx的部分可能就需要两个Componet部分才能表达完,而这两个
437 if ((uiOffset
< pstPosixInfo
->uiLinkLen
) && (BOOL_TRUE
!= BISO_SLCOMP_IS_CONTINUE(pstComp
->ucFlags
)))
439 szBuf
[uiBufLen
++] = '/';
442 memcpy(pcFullLinkPath
+ uiCurPos
, szBuf
, uiBufLen
);
443 uiCurPos
+= uiBufLen
;
446 pcFullLinkPath
[uiCurPos
++] = 0;
449 BISO_FREE(pstPosixInfo
->pcLinkSrc
);
450 pstPosixInfo
->pcLinkSrc
= pcFullLinkPath
;
451 pstPosixInfo
->uiLinkLen
= uiCurPos
;
455 ULONG BISO_RRIP_ReadExtInfo
457 IN BISO_FILE_S
*pstFile
,
458 IN BISO_PARSER_S
*pstParser
,
459 IN BISO_DIR_RECORD_S
*pstRecord
,
460 OUT BISO_DIR_TREE_S
*pstDirTree
466 UCHAR
*pucSysUseArea
= NULL
;
467 BISO_SUSP_ENTRY_S
*pstEntry
= NULL
;
469 DBGASSERT(NULL
!= pstFile
);
470 DBGASSERT(NULL
!= pstParser
);
471 DBGASSERT(NULL
!= pstRecord
);
472 DBGASSERT(NULL
!= pstDirTree
);
474 /* 没有使用Rock Ridge扩展则直接返回 */
475 if (0 == pstParser
->ucRRIPVersion
)
480 /* 先申请POSIX INFO结构体内存 */
481 if (NULL
== pstDirTree
->pstPosixInfo
)
483 pstDirTree
->pstPosixInfo
= (BISO_POSIX_INFO_S
*)BISO_ZALLOC(sizeof(BISO_POSIX_INFO_S
));
484 if (NULL
== pstDirTree
->pstPosixInfo
)
486 return BISO_ERR_ALLOC_MEM
;
490 /* 偏移到System Use字段所在的位置,注意Padding字段, 保证偏移为偶数 */
491 uiOffset
= 33 + pstRecord
->ucNameLen
;
492 uiOffset
+= uiOffset
& 0x1;
494 /* 再加上SP Entry中定义的SkipLen长度 */
495 uiOffset
+= pstParser
->ucRRIPSkipLen
;
497 /* 获取整个Syetem Use区域的数据(包括CE扩展区) */
498 pucSysUseArea
= BISO_RRIP_GetSysUseArea(pstFile
, (UCHAR
*)pstRecord
+ uiOffset
,
499 pstRecord
->ucLength
- (UCHAR
)uiOffset
, &uiAreaSize
);
500 if (NULL
== pucSysUseArea
)
502 return BISO_ERR_ALLOC_MEM
;
506 for(uiOffset
= 0; uiOffset
+ 4 < uiAreaSize
; uiOffset
+= pstEntry
->ucEntryLen
)
508 pstEntry
= (BISO_SUSP_ENTRY_S
*)(pucSysUseArea
+ uiOffset
);
509 /* BISO_DUMP_ShowSUSPEntry(pstEntry); */
512 for (i
= 0; i
< ARRAY_SIZE(g_astBISO_RRIP_ParseFunc
); i
++)
514 if (BOOL_TRUE
== BISO_RRIP_IsThisType(pstEntry
, g_astBISO_RRIP_ParseFunc
[i
].szSignature
))
516 if (NULL
!= g_astBISO_RRIP_ParseFunc
[i
].pfFunc
)
518 g_astBISO_RRIP_ParseFunc
[i
].pfFunc(pstEntry
, pstDirTree
);
525 BISO_FREE(pucSysUseArea
);
529 ULONG
BISO_RRIP_ReadIndicator(INOUT BISO_PARSER_S
*pstParser
)
533 BISO_DIR_RECORD_S
*pstRootDir
= NULL
;
534 BISO_SUSP_ENTRY_SP_S
*pstSPEntry
= NULL
;
535 UCHAR aucBuf
[sizeof(BISO_DIR_RECORD_S
) + sizeof(BISO_SUSP_ENTRY_SP_S
)];
537 DBGASSERT(NULL
!= pstParser
);
539 /* 读出Root Directory Record */
540 pstRootDir
= &(pstParser
->pstPVD
->stRootDirRecord
);
541 ui64Seek
= BISO_BLOCK_SIZE
* (UINT64
)pstRootDir
->uiExtent
;
542 ulRet
= BISO_UTIL_ReadFile(pstParser
->szFileName
, ui64Seek
, sizeof(aucBuf
), aucBuf
);
543 if (BISO_SUCCESS
!= ulRet
)
548 /* 看看Root Directory Record的System Use字段里有没有SP Entry */
549 pstRootDir
= (BISO_DIR_RECORD_S
*)aucBuf
;
550 pstSPEntry
= (BISO_SUSP_ENTRY_SP_S
*)(pstRootDir
+ 1);
551 if (('S' != pstSPEntry
->cSignature1
) || ('P' != pstSPEntry
->cSignature2
) ||
552 (0xBE != pstSPEntry
->ucChkBE
) || (0xEF != pstSPEntry
->ucChkEF
))
554 pstParser
->ucRRIPVersion
= 0;
555 pstParser
->ucRRIPSkipLen
= 0;
559 pstParser
->ucRRIPVersion
= pstSPEntry
->ucVersion
;
560 pstParser
->ucRRIPSkipLen
= pstSPEntry
->ucSkipLen
;