📄 cdromfslib.c
字号:
u_char ** ppPT, /* address of ptr to current record */ /* within buffer, containing PT */ u_long offset, /* offset of current record from PT start */ u_long PTSize /* path table size (stored in volume */ /* descriptor */ ) { short size; /* current PT record size */ /* skip current PT record */ PT_REC_SIZE(size, *ppPT); offset += size; *ppPT += size; /* * set of zero bytes may follow PT record, if that is last record in LB. * First non zero byte starts next record */ for (; offset < PTSize; offset ++, *ppPT += 1) if (**ppPT != 0) break; return (offset); }/********************************************************************************* cdromFsShiftCount - count shift for transfer <source> to <dest>.** This routine takes two values, that are power of two and counts* the difference of powers, which is, for instance, the number of* bits to shift <source> in order to get <dest>.* Because <dest> may be less, than <source>, (-1) may not be* used as error indication return code, so an impossible value of* 100 is taken for this purpose.** ERRNO: S_cdromFsLib_ONE_OF_VALUES_NOT_POWER_OF_2.** RETURNS: number of bits to shift <source>, in order to get <dest>* or a value of (100) if it is impossible to calculate shift count.*/LOCAL u_char cdromFsShiftCount ( u_long source, u_long dest ) { u_char i; if (source <= dest) { for (i = 0; i < sizeof (u_long) * 8; i++) if ((source << i) == dest) return i; } else /* source > dest */ { for (i = 1; i < sizeof (u_long) * 8; i++) if ((source >> i) == dest) return (-i); } errnoSet (S_cdromFsLib_ONE_OF_VALUES_NOT_POWER_OF_2); return (100); }/********************************************************************************* cdromFsVDAddToList - add VD to VD list.** Allocate VD list structure, fill in its fields (from <pVDData> buffer)* and add to VD list.** RETURNS: OK or ERROR if any failed.*/LOCAL STATUS cdromFsVDAddToList ( CDROM_VOL_DESC_ID pVolDesc, u_char * pVDData, /* data, has been got from disk */ u_int VDPseudoLBNum, /* LB number, contains given VD, */ /* if let (LB size = VD size) */ u_char VDSizeToLSSizeShift /* relation between VD size */ /* and LS size */ ) { T_CDROMFS_VD_LST_ID pVDList; assert (pVolDesc != NULL); assert (pVDData != NULL); pVDList = malloc (sizeof (T_CDROMFS_VD_LST)); if (pVDList == NULL) return (ERROR); bzero((u_char *) pVDList, sizeof (T_CDROMFS_VD_LST)); pVDList->pVolDesc = pVolDesc; C_BUF_TO_LONG (pVDList->volSize, pVDData, ISO_VD_VOL_SPACE_SIZE); /* since PT is stored in memory, max PT size is restricted */ C_BUF_TO_LONG (pVDList->PTSize, pVDData, ISO_VD_PT_SIZE); if (pVDList->PTSize > CDROM_LIB_MAX_PT_SIZE) { errnoSet (S_cdromFsLib_SUCH_PATH_TABLE_SIZE_NOT_SUPPORTED); free (pVDList); return (ERROR); } C_BUF_TO_LONG (pVDList->PTStartLB, pVDData, ISO_VD_PT_OCCUR); C_BUF_TO_LONG (pVDList->rootDirSize, pVDData, ISO_VD_ROOT_DIR_REC + ISO_DIR_REC_DATA_LEN); C_BUF_TO_LONG (pVDList->rootDirStartLB, pVDData, ISO_VD_ROOT_DIR_REC + ISO_DIR_REC_EXTENT_LOCATION); C_BUF_TO_SHORT (pVDList->volSetSize, pVDData, ISO_VD_VOL_SET_SIZE); C_BUF_TO_SHORT (pVDList->volSeqNum, pVDData, ISO_VD_VOL_SEQUENCE_N); C_BUF_TO_SHORT (pVDList->LBSize, pVDData, ISO_VD_LB_SIZE); pVDList->LBToLSShift = cdromFsShiftCount (pVDList->LBSize, pVolDesc->sectSize); pVDList->type = ((T_ISO_VD_HEAD_ID)pVDData)->type; pVDList->fileStructVersion = *(pVDData + ISO_VD_FILE_STRUCT_VER); pVDList->VDInSector = VDPseudoLBNum >> VDSizeToLSSizeShift; pVDList->VDOffInSect = LAST_BITS (VDPseudoLBNum, VDSizeToLSSizeShift) * ISO_VD_SIZE; /* * read PT to buffer and init dirLevBorders...[]. * In accordance with ISO9660 all directories records in * PT are sorted by hierarchy levels and are numbered from 1. * (only root has number 1 and lays on level 1). * Number of levels restricted to 8. * dirLevBordersOff[ n ] contains offset of first PT record on level * (n+2) (root excluded and array encounted from 0) from PT start. * dirLevLastRecNum[ n ] contains number of last PT record on level * (n+2). * Base of algorithm: * Storing number of last PT rec on hierarchy level <n> in * <prevLevLastRecNum>, will skip level <n+1>, on which all * directories have parent only within n; first directory * which parent dir number exceeds <prevLevLastRecNum> * starts level n+2. */ { u_char * pPT; u_int offset, /* absolute offset from PT start */ level, /* hierarchy level (minus 2) */ prevLevLastRecNum, /* number of last PT rec on */ /* previous hierarchy level */ prevRecNum ; /* previous PT record number */ pPT = cdromFsPTGet (pVDList, NULL); if (pPT == NULL) { free (pVDList); return (ERROR); } /* * pass over root dir entry, dir hierarchy level 1; * root dir record is first PT record and its number is 1 */ offset = cdromFsNextPTRec (&pPT, 0, pVDList->PTSize); level = 0; /* not put to array data for root directory */ prevRecNum = 1; /* root number in PT */ prevLevLastRecNum = 1; bzero ((u_char *)(pVDList->dirLevBordersOff), sizeof(pVDList->dirLevBordersOff)); bzero ((u_char *)(pVDList->dirLevLastRecNum), sizeof(pVDList->dirLevLastRecNum)); /* * over this loop all dir hierarchy levels' bounds in PT * will be found. */ pVDList->dirLevBordersOff[0] = offset; for(; offset < pVDList->PTSize && level < CDROM_MAX_DIR_LEV - 1;) { u_int prev; /* parent dir number for current record */ PT_PARENT_REC (prev, pPT);#ifdef DEBUG /* debugging */ DBG_COP_TO_BUF(pPT + ISO_PT_REC_DI, *pPT); DBG_MSG(200)("%4d\t%20s\tparent # %3d, D_ID_LEN %2d level %d\n", prevRecNum + 1, dbgvBuf, (int)prev, (int)*pPT, level + 2);#endif /* if directory level overed */ if(prev > prevLevLastRecNum) { /* close level */ pVDList->dirLevLastRecNum[level] = prevRecNum; level++; if (level > CDROM_MAX_DIR_LEV - 1) break; /* current level first record offset within PT */ pVDList->dirLevBordersOff[level] = offset; prevLevLastRecNum = prevRecNum; } prevRecNum ++; offset = cdromFsNextPTRec (&pPT, offset, pVDList->PTSize); } /* close last level */ pVDList->dirLevLastRecNum[level] = prevRecNum; /* * may be loop breaking only because CDROM_MAX_DIR_LEV overloading * before fully PT exhausting, that is an error */ if (offset < pVDList->PTSize) { free (pVDList); errnoSet (S_cdromFsLib_MAX_DIR_HIERARCHY_LEVEL_OVERFLOW); return (ERROR); } pVDList->numDirLevs = level + 1; /* <level> starts from 0 */ pVDList->numPTRecs = prevRecNum; } /* hierarchy bounds init */ /* VD have been built. Add it to VD list */ pVDList->magic = VD_LIST_MAG; lstAdd (&(pVolDesc->VDList), (NODE *)pVDList); return (OK); }/********************************************************************************* cdromFsVolUnmount - mark in all device depends data, that volume unmounted.* * All volume descriptors are deallocated.* FDList not deallocated, but only marked as "file unaccessible.** RETURN: N/A*/LOCAL void cdromFsVolUnmount ( CDROM_VOL_DESC_ID pVolDesc /* cdrom volume decriptor id */ ) { T_CDROM_FILE_ID pFDList; T_CDROMFS_VD_LST_ID pVDList; assert (pVolDesc != NULL); assert (pVolDesc->mDevSem != NULL); if (pVolDesc->unmounted) return; if (semTake(pVolDesc->mDevSem, WAIT_FOREVER) == ERROR) return; /* free VD list with PT buffers */ for (pVDList = (T_CDROMFS_VD_LST_ID)lstFirst(&(pVolDesc->VDList)); pVDList != NULL; pVDList = (T_CDROMFS_VD_LST_ID)lstNext((NODE *)pVDList)) { cdromFsSectBufFree(&(pVDList->PTBuf)); } lstFree (&(pVolDesc->VDList)); /* mark all opened files as unaccessible */ for (pFDList = (T_CDROM_FILE_ID)lstFirst(&(pVolDesc->FDList)); pFDList != NULL; pFDList = (T_CDROM_FILE_ID)lstNext((NODE *)pFDList)) { pFDList->volUnmount = 1; } /* mark in VD, that volume unmounted */ pVolDesc->unmounted = 1; if (semGive(pVolDesc->mDevSem) == ERROR) errnoSet (S_cdromFsLib_SEMGIVE_ERROR); }/********************************************************************************* cdromFsVolMount - mount cdrom volume.** This routine reads volume descriptors and creates VD list.** ERRNO: S_cdromFsLib_UNNOWN_FILE_SYSTEM or any errno may be set by* supplementary functions (such as malloc).** RETURNS: OK or ERROR*/LOCAL STATUS cdromFsVolMount ( CDROM_VOL_DESC_ID pVolDesc /* cdrom volume decriptor id */ ) { T_CDROMFS_VD_LST VDList; /* volume descriptor list */ u_long LBRead; /* logical blk to read */ u_char VDLast = 0; u_char primVDMounted; /* primary VD mounted flag */ assert (pVolDesc != NULL); assert (pVolDesc->mDevSem != NULL); /* private semaphore */ if (semTake (pVolDesc->mDevSem, WAIT_FOREVER) == ERROR) return ERROR; /* before mount new volume, it have to unmount previous */ if (! pVolDesc->unmounted) cdromFsVolUnmount (pVolDesc); pVolDesc->pBlkDev->bd_readyChanged = FALSE; /* * before VD was read let LB size equal to VD size, since * each VD defines its own LB size. Because VD size and LS size are * powers of 2, one may be get from second by means of shift. */ VDList.LBSize = ISO_VD_SIZE; VDList.LBToLSShift = cdromFsShiftCount (ISO_VD_SIZE, pVolDesc->sectSize); VDList.pVolDesc = pVolDesc; /* data in buffer remain from unmounted volume, so invalid */ LET_SECT_BUF_EMPTY (&(VDList.pVolDesc->sectBuf)); /* no one primary VD was found yet */ primVDMounted = 0; /* by ISO, first volume descriptor always lays in ISO_PVD_BASE_LS */ for (LBRead = ISO_PVD_BASE_LS << VDList.LBToLSShift; ! VDLast ; LBRead ++) { u_char * pVDData; /* read VD from disk */ pVDData = cdromFsGetLB (&VDList, LBRead, NULL); if (pVDData == NULL) { cdromFsVolUnmount (pVolDesc); semGive (pVolDesc->mDevSem); return ERROR; } /* check standard ISO volume ID */ if (strncmp(((T_ISO_VD_HEAD_ID)pVDData)->stdID, ISO_STD_ID , ISO_STD_ID_SIZE)) { /* not ISO volume ID */ /* * may be any unknown VD in set, but not first, that must be * ISO primary VD only (at least in current version) */ if (primVDMounted) /* primary have been found already */ continue; else { cdromFsVolUnmount (pVolDesc); semGive (pVolDesc->mDevSem); logMsg ("Warning: unknown CR-ROM format detected, ignored.\n", 0,0,0,0,0,0); errnoSet (S_cdromFsLib_UNNOWN_FILE_SYSTEM); return ERROR; } } /* check VD ID */ /* * only VD set termination, primary and supplementary VD are * interesting; and not process secondary copies of primary VD */ if (((T_ISO_VD_HEAD_ID)pVDData)->type == ISO_VD_SETTERM) VDLast = 1; else if ((((T_ISO_VD_HEAD_ID)pVDData)->type == ISO_VD_PRIMARY && ! primVDMounted) || ((T_ISO_VD_HEAD_ID)pVDData)->type == ISO_VD_SUPPLEM) { /* first VD on volume must be primary (look ISO 9660) */ if (((T_ISO_VD_HEAD_ID)pVDData)->type == ISO_VD_SUPPLEM && ! primVDMounted) { cdromFsVolUnmount (pVolDesc); semGive (pVolDesc->mDevSem); logMsg ("Warning: unknown CR-ROM format detected, ignored.\n", 0,0,0,0,0,0); errnoSet (S_cdromFsLib_UNNOWN_FILE_SYSTEM); return ERROR; } if (cdromFsVDAddToList (pVolDesc, pVDData, LBRead, VDList.LBToLSShift) == ERROR) { cdromFsVolUnmount (pVolDesc); semGive (pVolDesc->mDevSem); return ERROR; } /* if primary VD found in VD set */ if (((T_ISO_VD_HEAD_ID)pVDData)->type == ISO_VD_PRIMARY) primVDMounted = 1; } /* else if */ } /* for */ /* each volume contains at least one, primary volume descriptor. */ if (lstFirst(&(pVolDesc->VDList)) == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -