Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

853 lines
19 KiB

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