Tistory View

디스크와 볼륨은 다른 것이다. volume의 시리얼번호만으로 대부분의 상황에 대응이 가능하니 이 글에서는 Disk의 시리얼번호가 아니고 볼륨의 시리얼번호를 다룬다.

함수명은 GetVolumeInformation으로 드라이브이름, 파일시스템형태, 기본정보를 알아낼수 있습니다. VC에서 GetVolumeInformationW까지 치고 [F1]누르면 MS의 함수명세를 볼 수 있다.

GetVolumeInformation

BOOL GetVolumeInformationW(
  [in, optional]  LPCWSTR lpRootPathName,
  [out, optional] LPWSTR  lpVolumeNameBuffer,
  [in]            DWORD   nVolumeNameSize,
  [out, optional] LPDWORD lpVolumeSerialNumber,
  [out, optional] LPDWORD lpMaximumComponentLength,
  [out, optional] LPDWORD lpFileSystemFlags,
  [out, optional] LPWSTR  lpFileSystemNameBuffer,
  [in]            DWORD   nFileSystemNameSize
);

GetVolumeInformation(W/A)중에 이젠 'A'형은 잘 안 쓸테니, 아예 'W'형의 함수 선언입니다. 헤더파일은 'fileapi.h'지만, 그냥 'windows.h'만 include하면 된다.

 

사용상에 주의점은..

첫번째 파라미터는 루트의 폴더 명을 넣어야 한다. 다른 말로 끝에 [\] 나 [/]를 넣어야 잘 동작을 한다. 드라이브 명만 넣을 경우 동작은 하지만, [C:]보다는 [C:\]식으로 넣는 것을 권장한다. 파티션을 볼륨이 아닌 폴더로 마운트한 경우, 해당하는 폴더명을 넣어줄때도 '\'를 넣어야 한다. 빼먹으면 실패하게 됩니다. '\'를 넣으려면 당연히 '\\'로 넣어줘야 된다. '/'로 대체가 가능한 데, window니 window식으로 넣어주는 것이 좀 더 나을 듯하다 NULL을 넣으면, 현재 디레토리의 볼륨의 정보를 받을 수 있다. 하지만, 현재 디렉토리를 체크해야 하니 그리 권장하지는 않는다.

나머지 파라미터는 대부분 정보를 받기위한 미리 준비된 공간들이다.

예제의 샘플

#include <windows.h>
#include <iostream>
//#include <fileapi.h> : enough to include windows.h

int main()
{
    BOOL rcc = FALSE;
    
    wchar_t rootPathName[] = L"C:\\";
    wchar_t volumeNameBuffer[256]; // not works on subst(virtual drive)
    DWORD   nVolumeNameSize = sizeof( volumeNameBuffer );
    DWORD volumeSerialNumber;
    DWORD maximumComponentLength;
    DWORD fileSystemFlags;
    wchar_t fileSystemNameBuffer[32];
    DWORD   nFileSystemNameSize = sizeof(fileSystemNameBuffer);


    setlocale(LC_ALL, "ko-KR");

    rcc = GetVolumeInformationW(NULL, 0, nVolumeNameSize, &volumeSerialNumber,
        &maximumComponentLength,
        &fileSystemFlags,
        fileSystemNameBuffer,
        nFileSystemNameSize
    );

    if (rcc) {
        wprintf(L"success : Drive=%s\n", rootPathName);
        wprintf(L"volumeNameBuffer=%s\n", volumeNameBuffer );
        printf("volumeSerialNumber=%08x\n", volumeSerialNumber );
        printf("maximumComponentLength=%d\n", (int)maximumComponentLength);
        printf("fileSystemNameBuffer=%S\n", fileSystemNameBuffer);
        printf("nFileSystemNameSize=%d\n", (int)nFileSystemNameSize);
        printf("fileSystemFlags=%08x\n", (int)fileSystemFlags);

        printf("\tFILE_CASE_PRESERVED_NAMES=%s\n",       fileSystemFlags & FILE_CASE_PRESERVED_NAMES       ? "Y" : "N" );
        printf("\tFILE_CASE_SENSITIVE_SEARCH=%s\n",      fileSystemFlags & FILE_CASE_SENSITIVE_SEARCH      ? "Y" : "N");
        printf("\tFILE_DAX_VOLUME=%s\n",                 fileSystemFlags & FILE_DAX_VOLUME                 ? "Y" : "N");
        printf("\tFILE_FILE_COMPRESSION=%s\n",           fileSystemFlags & FILE_FILE_COMPRESSION           ? "Y" : "N");
        printf("\tFILE_NAMED_STREAMS=%s\n",              fileSystemFlags & FILE_NAMED_STREAMS              ? "Y" : "N");
        printf("\tFILE_PERSISTENT_ACLS=%s\n",            fileSystemFlags & FILE_PERSISTENT_ACLS            ? "Y" : "N");
        printf("\tFILE_READ_ONLY_VOLUME=%s\n",           fileSystemFlags & FILE_READ_ONLY_VOLUME           ? "Y" : "N");
        printf("\tFILE_SEQUENTIAL_WRITE_ONCE=%s\n",      fileSystemFlags & FILE_SEQUENTIAL_WRITE_ONCE      ? "Y" : "N");
        printf("\tFILE_SUPPORTS_ENCRYPTION=%s\n",        fileSystemFlags & FILE_SUPPORTS_ENCRYPTION        ? "Y" : "N");
        printf("\tFILE_SUPPORTS_HARD_LINKS=%s\n",        fileSystemFlags & FILE_SUPPORTS_HARD_LINKS        ? "Y" : "N");
        printf("\tFILE_SUPPORTS_OBJECT_IDS=%s\n",        fileSystemFlags & FILE_SUPPORTS_OBJECT_IDS        ? "Y" : "N");
        printf("\tFILE_SUPPORTS_REPARSE_POINTS=%s\n",    fileSystemFlags & FILE_SUPPORTS_REPARSE_POINTS    ? "Y" : "N");
        printf("\tFILE_SUPPORTS_SPARSE_FILES=%s\n",      fileSystemFlags & FILE_SUPPORTS_SPARSE_FILES      ? "Y" : "N");
        printf("\tFILE_SUPPORTS_TRANSACTIONS=%s\n",      fileSystemFlags & FILE_SUPPORTS_TRANSACTIONS      ? "Y" : "N");
        printf("\tFILE_SUPPORTS_USN_JOURNAL=%s\n",       fileSystemFlags & FILE_SUPPORTS_USN_JOURNAL       ? "Y" : "N");
        printf("\tFILE_UNICODE_ON_DISK=%s\n",            fileSystemFlags & FILE_UNICODE_ON_DISK            ? "Y" : "N");
        printf("\tFILE_VOLUME_IS_COMPRESSED=%s\n",       fileSystemFlags & FILE_VOLUME_IS_COMPRESSED       ? "Y" : "N");
        printf("\tFILE_VOLUME_QUOTAS=%s\n",              fileSystemFlags & FILE_VOLUME_QUOTAS              ? "Y" : "N");
        printf("\tFILE_SUPPORTS_BLOCK_REFCOUNTING=%s\n", fileSystemFlags & FILE_SUPPORTS_BLOCK_REFCOUNTING ? "Y" : "N");

    }
    else {
        printf("Can't GetVolumeInformationW\n");
    }

    return 0;
}

rootPathName 변수만 변경해가며 사용할 수 있게 만들었다..

네트워크드라이브는?

네트워크 드라이브의 경우 NTFS로 필자는 잡혔다. 실제로 SPARSED같은 것을 지원하는 지의 의문이다. 이 부분은 테스트 후 내용을 업데이트할 예정이다.

나오는 정보중에 maximumComponentLength값은... 필자는 못 믿겠다.

시리얼번호

단순한 32bits의 코드일 뿐이고, 명령창의 dir명령에서 확인할 수 있다.

이 시리얼번호는 포맷할 때마다 변하게 된다. 그리고 32bits라는 한계로인해 "겹치지 않는다"고 확정은 할 수 없고, 겹칠 확률이 아주 적기는 하지만 UUID같이 아주 희박한 것은 아니다. 문제는 디스크복사기와 같은 것을 사용할 경우 동일한 시리얼번호를 가질 수 있으니, 이 시리얼번호를 이용한 처리는 신중할 필요가 있다.

퀄리티어슈런스의 disk clone 기기

 

ext4같은 파티션도 시리얼 번호를 읽을 수 있는가? 아니오, 마운트된 드라이브만 가능하기에 루트폴더를 지정할 수 없다면 시리얼번호를 읽을 수 없다. EXT4와 같은 것을 마운트해주는 프로그램을 테스트해보지는 않았다.(있긴 있는지..)

 

 

보통의 NTFS정보

일반적으로 NTFS포맷을 사용한 드라이브의 정보는 다음과 같다. 물론 DAX같은 경우는 변경이 가능하기 때문에, 다른 값을 가질 수 있지만, 일반적으로 다음과 같다.

 

NTFS의 일반적인 정보

레퍼런스

GetVolumeInformation 함수명세

 

GetVolumeInformationW function (fileapi.h) - Win32 apps

Retrieves information about the file system and volume associated with the specified root directory.

docs.microsoft.com

UUID정보

 

Universally unique identifier - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search 128-bit label used to identify information in computer systems A universally unique identifier (UUID) is a 128-bit label used for information in computer systems. The term globally uni

en.wikipedia.org

 

Replies
Reply Write