|
|
/*
* 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 <t ILINKINFO> 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
|