/* * volumeid.c - Volume ID ADT module. */ /* Headers **********/ #include "project.h" #pragma hdrstop #include "volumeid.h" /* Constants ************/ /* local root path constants */ #define MAX_LOCAL_DRIVES (TEXT('z') - TEXT('a') + 1) /* Macros *********/ /* macros for accessing IVOLUMEID data */ #define IVOLID_Volume_Label_PtrA(pivolid) \ ((LPSTR)(((PBYTE)(pivolid)) + (pivolid)->ucbVolumeLabelOffset)) #ifdef UNICODE #define IVOLID_Volume_Label_PtrW(pivolid) \ ((LPTSTR)(((PBYTE)(pivolid)) + (pivolid)->ucbVolumeLabelOffsetW)) #endif #ifdef UNICODE #define IVOLID_Volume_Label_Ptr(pivolid) IVOLID_Volume_Label_PtrW(pivolid) #else #define IVOLID_Volume_Label_Ptr(pivolid) IVOLID_Volume_Label_PtrA(pivolid) #endif /* Types ********/ /* @doc INTERNAL @struct IVOLUMEID | Internal definition of relocatable volume ID structure. An structure may contain an IVOLUMEID structure. An IVOLUMEID structure consists of a header described as below, followed by variable-length data. */ typedef struct _ivolumeidA { /* @field UINT | ucbSize | Length of IVOLUMEID structure in bytes, including ucbSize field. */ UINT ucbSize; /* @field UINT | uDriveType | The volume's host drive type, as returned by GetDriveType() */ UINT uDriveType; /* @field DWORD | dwSerialNumber | The volume's serial number. */ DWORD dwSerialNumber; /* @field UINT | ucbVolumeLabelOffset | Offset in bytes of volume label string from base of structure. */ UINT ucbVolumeLabelOffset; } IVOLUMEIDA; DECLARE_STANDARD_TYPES(IVOLUMEIDA); #ifdef UNICODE typedef struct _ivolumeidW { /* @field UINT | ucbSize | Length of IVOLUMEID structure in bytes, including ucbSize field. */ UINT ucbSize; /* @field UINT | uDriveType | The volume's host drive type, as returned by GetDriveType() */ UINT uDriveType; /* @field DWORD | dwSerialNumber | The volume's serial number. */ DWORD dwSerialNumber; /* @field UINT | ucbVolumeLabelOffset | Offset in bytes of volume label string from base of structure. */ UINT ucbVolumeLabelOffset; /* This member is for storing the unicode version of the string */ UINT ucbVolumeLabelOffsetW; } IVOLUMEIDW; DECLARE_STANDARD_TYPES(IVOLUMEIDW); #endif #ifdef UNICODE #define IVOLUMEID IVOLUMEIDW #define PIVOLUMEID PIVOLUMEIDW #define CIVOLUMEID CIVOLUMEIDW #define PCIVOLUMEID PCIVOLUMEIDW #else #define IVOLUMEID IVOLUMEIDA #define PIVOLUMEID PIVOLUMEIDA #define CIVOLUMEID CIVOLUMEIDA #define PCIVOLUMEID PCIVOLUMEIDA #endif /***************************** Private Functions *****************************/ /* Module Prototypes ********************/ PRIVATE_CODE BOOL UnifyIVolumeIDInfo(UINT, DWORD, LPCTSTR, PIVOLUMEID *, PUINT); PRIVATE_CODE BOOL IsPathOnVolume(LPCTSTR, PCIVOLUMEID, PBOOL); PRIVATE_CODE COMPARISONRESULT CompareUINTs(UINT, UINT); #if defined(DEBUG) || defined (VSTF) PRIVATE_CODE BOOL IsValidPCIVOLUMEID(PCIVOLUMEID); #endif /* ** UnifyIVolumeIDInfo() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL UnifyIVolumeIDInfo(UINT uDriveType, DWORD dwSerialNumber, LPCTSTR pcszVolumeLabel, PIVOLUMEID *ppivolid, PUINT pucbIVolumeIDLen) { BOOL bResult; #ifdef UNICODE CHAR szAnsiVolumeLabel[MAX_PATH]; BOOL bUnicode; UINT cchVolumeLabel; UINT cchChars; #endif /* dwSerialNumber may be any value. */ ASSERT(IsValidDriveType(uDriveType)); ASSERT(IS_VALID_STRING_PTR(pcszVolumeLabel, CSTR)); ASSERT(IS_VALID_WRITE_PTR(ppivolid, PIVOLUMEID)); ASSERT(IS_VALID_WRITE_PTR(pucbIVolumeIDLen, UINT)); /* Assume we won't overflow *pucbIVolumeIDLen here. */ #ifdef UNICODE /* Determine whether we need a full fledged UNICODE volume ID */ bUnicode = FALSE; cchVolumeLabel = WideCharToMultiByte(CP_ACP, 0, pcszVolumeLabel, -1, szAnsiVolumeLabel, MAX_PATH, 0, 0); if ( cchVolumeLabel == 0 ) { bUnicode = TRUE; } else { WCHAR szWideVolumeLabel[MAX_PATH]; cchChars = MultiByteToWideChar(CP_ACP, 0, szAnsiVolumeLabel, -1, szWideVolumeLabel, MAX_PATH); if ( cchChars == 0 || lstrcmp(pcszVolumeLabel,szWideVolumeLabel) != 0 ) { bUnicode = TRUE; } } if ( bUnicode ) { UINT ucbDataSize; /* (+ 1) for null terminator. */ ucbDataSize = SIZEOF(IVOLUMEIDW) + cchVolumeLabel; ucbDataSize = ALIGN_WORD_CNT(ucbDataSize); ucbDataSize += (lstrlen(pcszVolumeLabel) + 1) * SIZEOF(TCHAR); *pucbIVolumeIDLen = ucbDataSize; } else { /* (+ 1) for null terminator. */ *pucbIVolumeIDLen = SIZEOF(IVOLUMEIDA) + cchVolumeLabel; } #else /* (+ 1) for null terminator. */ *pucbIVolumeIDLen = SIZEOF(**ppivolid) + (lstrlen(pcszVolumeLabel) + 1) * SIZEOF(TCHAR); #endif bResult = AllocateMemory(*pucbIVolumeIDLen, ppivolid); if (bResult) { (*ppivolid)->ucbSize = *pucbIVolumeIDLen; (*ppivolid)->uDriveType = uDriveType; (*ppivolid)->dwSerialNumber = dwSerialNumber; /* Append volume label. */ #ifdef UNICODE if ( bUnicode ) { (*ppivolid)->ucbVolumeLabelOffset = SIZEOF(IVOLUMEIDW); (*ppivolid)->ucbVolumeLabelOffsetW = ALIGN_WORD_CNT( SIZEOF(IVOLUMEIDW)+cchVolumeLabel); lstrcpy(IVOLID_Volume_Label_PtrW(*ppivolid), pcszVolumeLabel); } else { (*ppivolid)->ucbVolumeLabelOffset = SIZEOF(IVOLUMEIDA); } lstrcpyA(IVOLID_Volume_Label_PtrA(*ppivolid), szAnsiVolumeLabel); #else lstrcpy(IVOLID_Volume_Label_Ptr(*ppivolid), pcszVolumeLabel); #endif } ASSERT(! bResult || (IS_VALID_STRUCT_PTR(*ppivolid, CIVOLUMEID) && EVAL(*pucbIVolumeIDLen == GetVolumeIDLen((PCVOLUMEID)*ppivolid)))); return(bResult); } /* ** IsPathOnVolume() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsPathOnVolume(LPCTSTR pcszDrivePath, PCIVOLUMEID pcivolid, PBOOL pbOnVolume) { BOOL bResult; PVOLUMEID pvolid; UINT ucbVolumeIDLen; ASSERT(IsDrivePath(pcszDrivePath)); ASSERT(IS_VALID_STRUCT_PTR(pcivolid, CIVOLUMEID)); ASSERT(IS_VALID_WRITE_PTR(pcivolid, CIVOLUMEID)); bResult = CreateVolumeID(pcszDrivePath, &pvolid, &ucbVolumeIDLen); if (bResult) { *pbOnVolume = (CompareVolumeIDs(pvolid, (PCVOLUMEID)pcivolid) == CR_EQUAL); DestroyVolumeID(pvolid); } return(bResult); } /* ** CompareUINTs() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE COMPARISONRESULT CompareUINTs(UINT uFirst, UINT uSecond) { COMPARISONRESULT cr; /* Any UINTs are valid input. */ if (uFirst < uSecond) cr = CR_FIRST_SMALLER; else if (uFirst > uSecond) cr = CR_FIRST_LARGER; else cr = CR_EQUAL; ASSERT(IsValidCOMPARISONRESULT(cr)); return(cr); } #if defined(DEBUG) || defined (VSTF) /* ** IsValidPCIVOLUMEID() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidPCIVOLUMEID(PCIVOLUMEID pcivolid) { /* dwSerialNumber may be any value. */ return(IS_VALID_READ_PTR(pcivolid, CIVOLUMEID) && IS_VALID_READ_BUFFER_PTR(pcivolid, CIVOLUMEID, pcivolid->ucbSize) && EVAL(IsValidDriveType(pcivolid->uDriveType)) && EVAL(IsContained(pcivolid, pcivolid->ucbSize, IVOLID_Volume_Label_Ptr(pcivolid), lstrlen(IVOLID_Volume_Label_Ptr(pcivolid))*SIZEOF(TCHAR)))); } #endif /****************************** Public Functions *****************************/ /* ** CreateVolumeID() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL CreateVolumeID(LPCTSTR pcszDrivePath, PVOLUMEID *ppvolid, PUINT pucbVolumeIDLen) { BOOL bResult; /* "C:\" + null terminator. */ TCHAR rgchRootPath[3 + 1]; TCHAR rgchVolumeLabel[MAX_PATH_LEN]; DWORD dwSerialNumber; ASSERT(IsDrivePath(pcszDrivePath)); ASSERT(IS_VALID_WRITE_PTR(ppvolid, PVOLUMEID)); ASSERT(IS_VALID_WRITE_PTR(pucbVolumeIDLen, UINT)); /* Get volume's label and serial number. */ MyLStrCpyN(rgchRootPath, pcszDrivePath, ARRAYSIZE(rgchRootPath)); bResult = GetVolumeInformation(rgchRootPath, rgchVolumeLabel, ARRAYSIZE(rgchVolumeLabel), &dwSerialNumber, NULL, NULL, NULL, 0); if (bResult) /* Wrap them up. */ bResult = UnifyIVolumeIDInfo(GetDriveType(rgchRootPath), dwSerialNumber, rgchVolumeLabel, (PIVOLUMEID *)ppvolid, pucbVolumeIDLen); ASSERT(! bResult || IS_VALID_STRUCT_PTR((PCIVOLUMEID)*ppvolid, CIVOLUMEID)); return(bResult); } /* ** DestroyVolumeID() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void DestroyVolumeID(PVOLUMEID pvolid) { ASSERT(IS_VALID_STRUCT_PTR(pvolid, CVOLUMEID)); FreeMemory(pvolid); return; } /* ** CompareVolumeIDs() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none ** ** Volume ID data is compared in the following order: ** 1) drive type ** 2) volume serial number ** ** N.b., volume labels are ignored. */ PUBLIC_CODE COMPARISONRESULT CompareVolumeIDs(PCVOLUMEID pcvolidFirst, PCVOLUMEID pcvolidSecond) { COMPARISONRESULT cr; ASSERT(IS_VALID_STRUCT_PTR(pcvolidFirst, CVOLUMEID)); ASSERT(IS_VALID_STRUCT_PTR(pcvolidSecond, CVOLUMEID)); /* Compare VOLUMEIDs piece by piece. */ cr = CompareUINTs(((PCIVOLUMEID)pcvolidFirst)->uDriveType, ((PCIVOLUMEID)pcvolidSecond)->uDriveType); if (cr == CR_EQUAL) cr = CompareDWORDs(((PCIVOLUMEID)pcvolidFirst)->dwSerialNumber, ((PCIVOLUMEID)pcvolidSecond)->dwSerialNumber); return(cr); } /* ** SearchForLocalPath() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL SearchForLocalPath(PCVOLUMEID pcvolid, LPCTSTR pcszFullPath, DWORD dwInFlags, LPTSTR pszFoundPathBuf) { BOOL bResult; BOOL bAvailable; #if defined(DEBUG) && defined(UNICODE) WCHAR szWideVolumeLabel[MAX_PATH]; LPWSTR pszWideVolumeLabel; #endif ASSERT(IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID)); ASSERT(IsFullPath(pcszFullPath)); ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_SFLP_IFLAGS)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszFoundPathBuf, STR, MAX_PATH_LEN)); #if defined(DEBUG) && defined(UNICODE) if (((PCIVOLUMEID)pcvolid)->ucbVolumeLabelOffset == SIZEOF(IVOLUMEIDA)) { pszWideVolumeLabel = szWideVolumeLabel; MultiByteToWideChar(CP_ACP, 0, IVOLID_Volume_Label_PtrA((PCIVOLUMEID)pcvolid), -1, szWideVolumeLabel, MAX_PATH); } else { pszWideVolumeLabel = IVOLID_Volume_Label_Ptr((PCIVOLUMEID)pcvolid); } #endif /* Were we given a local path to check first? */ if (IsLocalDrivePath(pcszFullPath)) /* Yes. Check it. */ bResult = IsPathOnVolume(pcszFullPath, (PCIVOLUMEID)pcvolid, &bAvailable); else { /* No. */ bAvailable = FALSE; bResult = TRUE; } if (bResult) { /* Did we find the volume? */ if (bAvailable) { /* Yes. */ ASSERT(lstrlen(pcszFullPath) < MAX_PATH_LEN); lstrcpy(pszFoundPathBuf, pcszFullPath); } else { /* * No. Should we search other matching local devices for the volume? */ if (IS_FLAG_SET(dwInFlags, SFLP_IFL_LOCAL_SEARCH)) { TCHAR chOriginalDrive; UINT uDrive; DWORD dwLogicalDrives; /* Yes. */ #ifdef UNICODE WARNING_OUT((TEXT("SearchForLocalPath(): Searching for local volume \"%s\", as requested."), pszWideVolumeLabel)); #else WARNING_OUT((TEXT("SearchForLocalPath(): Searching for local volume \"%s\", as requested."), IVOLID_Volume_Label_Ptr((PCIVOLUMEID)pcvolid))); #endif ASSERT(IsCharAlpha(*pcszFullPath)); chOriginalDrive = *pcszFullPath; ASSERT(lstrlen(pcszFullPath) < MAX_PATH_LEN); lstrcpy(pszFoundPathBuf, pcszFullPath); /* Get bit mask of local logical drives. */ dwLogicalDrives = GetLogicalDrives(); for (uDrive = 0; uDrive < MAX_LOCAL_DRIVES; uDrive++) { if (IS_FLAG_SET(dwLogicalDrives, (1 << uDrive))) { TCHAR chDrive; chDrive = (TCHAR)(TEXT('A') + uDrive); ASSERT(IsCharAlpha(chDrive)); if (chDrive != chOriginalDrive) { TCHAR rgchLocalRootPath[DRIVE_ROOT_PATH_LEN]; lstrcpy(rgchLocalRootPath, TEXT("A:\\")); rgchLocalRootPath[0] = chDrive; /* * Does this drive's type match the target volume's drive * type? */ if (GetDriveType(rgchLocalRootPath) == ((PCIVOLUMEID)pcvolid)->uDriveType) { /* Yes. Check the volume. */ TRACE_OUT((TEXT("SearchForLocalPath(): Checking local root path %s."), rgchLocalRootPath)); bResult = IsPathOnVolume(rgchLocalRootPath, (PCIVOLUMEID)pcvolid, &bAvailable); if (bResult) { if (bAvailable) { ASSERT(lstrlen(pcszFullPath) < MAX_PATH_LEN); lstrcpy(pszFoundPathBuf, pcszFullPath); ASSERT(IsCharAlpha(*pszFoundPathBuf)); *pszFoundPathBuf = chDrive; TRACE_OUT((TEXT("SearchForLocalPath(): Found matching volume on local path %s."), pszFoundPathBuf)); break; } } else break; } } } } } else /* No. */ #ifdef UNICODE WARNING_OUT((TEXT("SearchForLocalPath(): Not searching for local volume \"%s\", as requested."), pszWideVolumeLabel)); #else WARNING_OUT((TEXT("SearchForLocalPath(): Not searching for local volume \"%s\", as requested."), IVOLID_Volume_Label_Ptr((PCIVOLUMEID)pcvolid))); #endif } } ASSERT(! bResult || ! bAvailable || IsLocalDrivePath(pszFoundPathBuf)); return(bResult && bAvailable); } /* ** GetVolumeIDLen() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE UINT GetVolumeIDLen(PCVOLUMEID pcvolid) { ASSERT(IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID)); return(((PCIVOLUMEID)pcvolid)->ucbSize); } /* ** GetVolumeSerialNumber() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetVolumeSerialNumber(PCVOLUMEID pcvolid, PCDWORD *ppcdwSerialNumber) { ASSERT(IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID)); ASSERT(IS_VALID_WRITE_PTR(ppcdwSerialNumber, PCDWORD)); *ppcdwSerialNumber = &(((PCIVOLUMEID)pcvolid)->dwSerialNumber); ASSERT(IS_VALID_READ_PTR(*ppcdwSerialNumber, CDWORD)); return(TRUE); } /* ** GetVolumeDriveType() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetVolumeDriveType(PCVOLUMEID pcvolid, PCUINT *ppcuDriveType) { ASSERT(IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID)); ASSERT(IS_VALID_WRITE_PTR(ppcuDriveType, PCUINT)); *ppcuDriveType = &(((PCIVOLUMEID)pcvolid)->uDriveType); ASSERT(IS_VALID_READ_PTR(*ppcuDriveType, CUINT)); return(TRUE); } /* ** GetVolumeLabel() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetVolumeLabel(PCVOLUMEID pcvolid, LPCSTR *ppcszVolumeLabel) { ASSERT(IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID)); ASSERT(IS_VALID_WRITE_PTR(ppcszVolumeLabel, LPCTSTR)); *ppcszVolumeLabel = IVOLID_Volume_Label_PtrA((PCIVOLUMEID)pcvolid); ASSERT(IS_VALID_STRING_PTRA(*ppcszVolumeLabel, CSTR)); return(TRUE); } #ifdef UNICODE /* ** GetVolumeLabelW() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetVolumeLabelW(PCVOLUMEID pcvolid, LPCWSTR *ppcszVolumeLabel) { ASSERT(IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID)); ASSERT(IS_VALID_WRITE_PTR(ppcszVolumeLabel, LPCTSTR)); if (((PCIVOLUMEID)pcvolid)->ucbVolumeLabelOffset == SIZEOF(IVOLUMEIDW)) { *ppcszVolumeLabel = IVOLID_Volume_Label_PtrW((PCIVOLUMEID)pcvolid); ASSERT(IS_VALID_STRING_PTR(*ppcszVolumeLabel, CSTR)); } else { *ppcszVolumeLabel = NULL; } return(TRUE); } #endif /* ** CompareDWORDs() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE COMPARISONRESULT CompareDWORDs(DWORD dwFirst, DWORD dwSecond) { COMPARISONRESULT cr; /* Any DWORDs are valid input. */ if (dwFirst < dwSecond) cr = CR_FIRST_SMALLER; else if (dwFirst > dwSecond) cr = CR_FIRST_LARGER; else cr = CR_EQUAL; ASSERT(IsValidCOMPARISONRESULT(cr)); return(cr); } #if defined(DEBUG) || defined (VSTF) /* ** IsValidPCVOLUMEID() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL IsValidPCVOLUMEID(PCVOLUMEID pcvolid) { return(IS_VALID_STRUCT_PTR((PCIVOLUMEID)pcvolid, CIVOLUMEID)); } #endif #ifdef DEBUG /* ** DumpVolumeID() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void DumpVolumeID(PCVOLUMEID pcvolid) { ASSERT(IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID)); PLAIN_TRACE_OUT((TEXT("%s%s[local volume ID] ucbSize = %#x"), INDENT_STRING, INDENT_STRING, ((PCIVOLUMEID)pcvolid)->ucbSize)); PLAIN_TRACE_OUT((TEXT("%s%s[local volume ID] drive type %u"), INDENT_STRING, INDENT_STRING, ((PCIVOLUMEID)pcvolid)->uDriveType)); PLAIN_TRACE_OUT((TEXT("%s%s[local volume ID] serial number %#08lx"), INDENT_STRING, INDENT_STRING, ((PCIVOLUMEID)pcvolid)->dwSerialNumber)); PLAIN_TRACE_OUT((TEXT("%s%s[local volume ID] label \"%s\""), INDENT_STRING, INDENT_STRING, IVOLID_Volume_Label_Ptr((PCIVOLUMEID)pcvolid))); return; } #endif