pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


Untitled
Posted by Anonymous on Wed 21st Jan 2026 02:20
raw | new post

  1.  
  2. #define WIN32_LEAN_AND_MEAN
  3. #include <windows.h>
  4. #include <wchar.h>
  5. #include <stdbool.h>
  6. #include <stdio.h>
  7. #include <stdint.h>
  8. #include <stddef.h>
  9.  
  10. #ifdef _MSC_VER
  11. #pragma comment(lib, "ntdll.lib")
  12. #endif
  13.  
  14. typedef LONG NTSTATUS;
  15. #ifndef NT_SUCCESS
  16. #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
  17. #endif
  18.  
  19. typedef struct _IO_STATUS_BLOCK {
  20.     union { NTSTATUS Status; PVOID Pointer; } DUMMYUNIONNAME;
  21.     ULONG_PTR Information;
  22. } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
  23.  
  24. typedef enum _FILE_INFORMATION_CLASS {
  25.     FileRenameInformation = 10
  26. } FILE_INFORMATION_CLASS;
  27.  
  28. typedef struct _FILE_RENAME_INFORMATION {
  29.     BOOLEAN ReplaceIfExists;
  30.     HANDLE  RootDirectory;
  31.     ULONG   FileNameLength;
  32.     WCHAR   FileName[1];
  33. } FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
  34.  
  35. #ifdef __cplusplus
  36. extern "C" {
  37. #endif
  38. NTSTATUS NTAPI NtSetInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS);
  39. ULONG NTAPI RtlNtStatusToDosError(NTSTATUS);
  40. #ifdef __cplusplus
  41. }
  42. #endif
  43.  
  44. static BOOL ToFullDosPathW(const wchar_t* inPath, wchar_t** outFull)
  45. {
  46.     if (!inPath || !outFull) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
  47.     if (wcslen(inPath) >= 4 && inPath[0] == L'\\' && inPath[1] == L'\\' && inPath[2] == L'?' && inPath[3] == L'\\') {
  48.         size_t len = wcslen(inPath) + 1;
  49.         wchar_t* dup = (wchar_t*)HeapAlloc(GetProcessHeap(), 0, len * sizeof(wchar_t));
  50.         if (!dup) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; }
  51.         wcscpy(dup, inPath);
  52.         *outFull = dup;
  53.         return TRUE;
  54.     }
  55.     DWORD need = GetFullPathNameW(inPath, 0, NULL, NULL);
  56.     if (need == 0) return FALSE;
  57.     wchar_t* buf = (wchar_t*)HeapAlloc(GetProcessHeap(), 0, need * sizeof(wchar_t));
  58.     if (!buf) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; }
  59.     if (GetFullPathNameW(inPath, need, buf, NULL) == 0) {
  60.         DWORD err = GetLastError();
  61.         HeapFree(GetProcessHeap(), 0, buf);
  62.         SetLastError(err);
  63.         return FALSE;
  64.     }
  65.     *outFull = buf;
  66.     return TRUE;
  67. }
  68.  
  69. static HANDLE OpenForRenameW(const wchar_t* fullDosPath)
  70. {
  71.     DWORD share  = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  72.     DWORD flags  = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
  73.     return CreateFileW(fullDosPath, DELETE | SYNCHRONIZE, share, NULL, OPEN_EXISTING, flags, NULL);
  74. }
  75.  
  76. static BOOL SplitParentAndLeafW(const wchar_t* fullPath, wchar_t** parentOut, const wchar_t** leafOut)
  77. {
  78.     if (!fullPath || !parentOut || !leafOut) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
  79.     size_t len = wcslen(fullPath);
  80.     if (len == 0) { SetLastError(ERROR_INVALID_NAME); return FALSE; }
  81.     const wchar_t* last = wcsrchr(fullPath, L'\\');
  82.     if (!last || last == fullPath) { SetLastError(ERROR_INVALID_NAME); return FALSE; }
  83.     size_t parentLen = (size_t)(last - fullPath);
  84.     const wchar_t* leaf = last + 1;
  85.     if (*leaf == L'\0') { SetLastError(ERROR_INVALID_NAME); return FALSE; }
  86.     wchar_t* parent = (wchar_t*)HeapAlloc(GetProcessHeap(), 0, (parentLen + 1) * sizeof(wchar_t));
  87.     if (!parent) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; }
  88.     wmemcpy(parent, fullPath, parentLen);
  89.     parent[parentLen] = L'\0';
  90.     *parentOut = parent;
  91.     *leafOut = leaf;
  92.     return TRUE;
  93. }
  94.  
  95. static BOOL IsLeafOnlyTarget(const wchar_t* target)
  96. {
  97.     if (!target || !*target) return FALSE;
  98.     if (wcschr(target, L'\\') != NULL) return FALSE;
  99.     if (((target[0] >= L'A' && target[0] <= L'Z') || (target[0] >= L'a' && target[0] <= L'z')) && target[1] == L':')
  100.         return FALSE;
  101.     return TRUE;
  102. }
  103.  
  104. static BOOL ExtractBaseFilePathW(const wchar_t* fullPath, wchar_t** baseOut, BOOL* hadStreamOut)
  105. {
  106.     if (!fullPath || !baseOut || !hadStreamOut) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
  107.     const wchar_t* afterSlash = wcsrchr(fullPath, L'\\');
  108.     const wchar_t* searchStart = afterSlash ? afterSlash + 1 : fullPath;
  109.     const wchar_t* colon = wcschr(searchStart, L':');
  110.     if (!colon) {
  111.         size_t n = wcslen(fullPath) + 1;
  112.         wchar_t* dup = (wchar_t*)HeapAlloc(GetProcessHeap(), 0, n * sizeof(wchar_t));
  113.         if (!dup) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; }
  114.         wcscpy(dup, fullPath);
  115.         *baseOut = dup;
  116.         *hadStreamOut = FALSE;
  117.         return TRUE;
  118.     }
  119.     size_t baseLen = (size_t)(colon - fullPath);
  120.     wchar_t* base = (wchar_t*)HeapAlloc(GetProcessHeap(), 0, (baseLen + 1) * sizeof(wchar_t));
  121.     if (!base) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; }
  122.     wmemcpy(base, fullPath, baseLen);
  123.     base[baseLen] = L'\0';
  124.     *baseOut = base;
  125.     *hadStreamOut = TRUE;
  126.     return TRUE;
  127. }
  128.  
  129. BOOL RenameFileW(const wchar_t* fromPathW, const wchar_t* toPathW)
  130. {
  131.     if (!fromPathW || !toPathW) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
  132.  
  133.     wchar_t *fromFull = NULL;
  134.     if (!ToFullDosPathW(fromPathW, &fromFull)) return FALSE;
  135.  
  136.     HANDLE hSrc = OpenForRenameW(fromFull);
  137.     if (hSrc == INVALID_HANDLE_VALUE) {
  138.         DWORD err = GetLastError();
  139.         HeapFree(GetProcessHeap(), 0, fromFull);
  140.         SetLastError(err);
  141.         return FALSE;
  142.     }
  143.  
  144.     HANDLE hRoot = INVALID_HANDLE_VALUE;
  145.     const wchar_t* fileNamePtr = NULL;
  146.     wchar_t *destParent = NULL, *toFull = NULL;
  147.  
  148.     if (IsLeafOnlyTarget(toPathW)) {
  149.         if (toPathW[0] == L':') {
  150.             BOOL hadStream = FALSE;
  151.             wchar_t* baseFull = NULL;
  152.             if (!ExtractBaseFilePathW(fromFull, &baseFull, &hadStream)) {
  153.                 DWORD err = GetLastError();
  154.                 CloseHandle(hSrc);
  155.                 HeapFree(GetProcessHeap(), 0, fromFull);
  156.                 SetLastError(err);
  157.                 return FALSE;
  158.             }
  159.             if (!hadStream) {
  160.                 HeapFree(GetProcessHeap(), 0, baseFull);
  161.                 CloseHandle(hSrc);
  162.                 HeapFree(GetProcessHeap(), 0, fromFull);
  163.                 SetLastError(ERROR_INVALID_PARAMETER);
  164.                 return FALSE;
  165.             }
  166.             hRoot = CreateFileW(baseFull,
  167.                                 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  168.                                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  169.                                 NULL, OPEN_EXISTING, 0, NULL);
  170.             HeapFree(GetProcessHeap(), 0, baseFull);
  171.             if (hRoot == INVALID_HANDLE_VALUE) {
  172.                 DWORD err = GetLastError();
  173.                 CloseHandle(hSrc);
  174.                 HeapFree(GetProcessHeap(), 0, fromFull);
  175.                 SetLastError(err);
  176.                 return FALSE;
  177.             }
  178.             fileNamePtr = toPathW;
  179.         } else {
  180.             const wchar_t* srcLeaf = NULL;
  181.             if (!SplitParentAndLeafW(fromFull, &destParent, &srcLeaf)) {
  182.                 DWORD err = GetLastError();
  183.                 CloseHandle(hSrc);
  184.                 HeapFree(GetProcessHeap(), 0, fromFull);
  185.                 SetLastError(err);
  186.                 return FALSE;
  187.             }
  188.             hRoot = CreateFileW(destParent,
  189.                                 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  190.                                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  191.                                 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
  192.             if (hRoot == INVALID_HANDLE_VALUE) {
  193.                 DWORD err = GetLastError();
  194.                 HeapFree(GetProcessHeap(), 0, destParent);
  195.                 CloseHandle(hSrc);
  196.                 HeapFree(GetProcessHeap(), 0, fromFull);
  197.                 SetLastError(err);
  198.                 return FALSE;
  199.             }
  200.             fileNamePtr = toPathW;
  201.         }
  202.     } else {
  203.         if (!ToFullDosPathW(toPathW, &toFull)) {
  204.             DWORD err = GetLastError();
  205.             CloseHandle(hSrc);
  206.             HeapFree(GetProcessHeap(), 0, fromFull);
  207.             SetLastError(err);
  208.             return FALSE;
  209.         }
  210.         const wchar_t* destLeaf = NULL;
  211.         if (!SplitParentAndLeafW(toFull, &destParent, &destLeaf)) {
  212.             DWORD err = GetLastError();
  213.             CloseHandle(hSrc);
  214.             HeapFree(GetProcessHeap(), 0, fromFull);
  215.             HeapFree(GetProcessHeap(), 0, toFull);
  216.             SetLastError(err);
  217.             return FALSE;
  218.         }
  219.         hRoot = CreateFileW(destParent,
  220.                             FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  221.                             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  222.                             NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
  223.         if (hRoot == INVALID_HANDLE_VALUE) {
  224.             DWORD err = GetLastError();
  225.             HeapFree(GetProcessHeap(), 0, destParent);
  226.             CloseHandle(hSrc);
  227.             HeapFree(GetProcessHeap(), 0, fromFull);
  228.             HeapFree(GetProcessHeap(), 0, toFull);
  229.             SetLastError(err);
  230.             return FALSE;
  231.         }
  232.         fileNamePtr = destLeaf;
  233.     }
  234.  
  235.     size_t nameChars = wcslen(fileNamePtr);
  236.     if (nameChars == 0) {
  237.         if (toFull) HeapFree(GetProcessHeap(), 0, toFull);
  238.         if (destParent) HeapFree(GetProcessHeap(), 0, destParent);
  239.         if (hRoot != INVALID_HANDLE_VALUE) CloseHandle(hRoot);
  240.         CloseHandle(hSrc);
  241.         HeapFree(GetProcessHeap(), 0, fromFull);
  242.         SetLastError(ERROR_INVALID_NAME);
  243.         return FALSE;
  244.     }
  245.  
  246.     ULONG nameBytes = (ULONG)(nameChars * sizeof(WCHAR));
  247.     ULONG infoSize = (ULONG)(offsetof(FILE_RENAME_INFORMATION, FileName) + nameBytes);
  248.     PFILE_RENAME_INFORMATION fri = (PFILE_RENAME_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, infoSize);
  249.     if (!fri) {
  250.         if (toFull) HeapFree(GetProcessHeap(), 0, toFull);
  251.         if (destParent) HeapFree(GetProcessHeap(), 0, destParent);
  252.         if (hRoot != INVALID_HANDLE_VALUE) CloseHandle(hRoot);
  253.         CloseHandle(hSrc);
  254.         HeapFree(GetProcessHeap(), 0, fromFull);
  255.         SetLastError(ERROR_OUTOFMEMORY);
  256.         return FALSE;
  257.     }
  258.  
  259.     fri->ReplaceIfExists = FALSE;
  260.     fri->RootDirectory   = NULL/*hRoot*/;
  261.     fri->FileNameLength  = nameBytes;
  262.     memcpy(fri->FileName, fileNamePtr, nameBytes);
  263.  
  264.     IO_STATUS_BLOCK iosb = { 0 };
  265.     NTSTATUS status = NtSetInformationFile(hSrc, &iosb, fri, infoSize, FileRenameInformation);
  266.  
  267.     BOOL ok = NT_SUCCESS(status);
  268.     if (!ok) SetLastError(RtlNtStatusToDosError(status)); else SetLastError(ERROR_SUCCESS);
  269.  
  270.     HeapFree(GetProcessHeap(), 0, fri);
  271.     if (toFull) HeapFree(GetProcessHeap(), 0, toFull);
  272.     if (destParent) HeapFree(GetProcessHeap(), 0, destParent);
  273.     if (hRoot != INVALID_HANDLE_VALUE) CloseHandle(hRoot);
  274.     CloseHandle(hSrc);
  275.     HeapFree(GetProcessHeap(), 0, fromFull);
  276.  
  277.     return ok;
  278. }
  279.  
  280. static void PrintLastErrorMessageW(DWORD err)
  281. {
  282.     wchar_t* msg = NULL;
  283.     DWORD n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  284.                              NULL, err, 0, (LPWSTR)&msg, 0, NULL);
  285.     if (n && msg) {
  286.         for (wchar_t* p = msg; *p; ++p) { if (*p == L'\r' || *p == L'\n') { *p = L'\0'; break; } }
  287.         fwprintf(stderr, L"Win32 error %lu: %ls\n", err, msg);
  288.         LocalFree(msg);
  289.     } else {
  290.         fwprintf(stderr, L"Win32 error %lu\n", err);
  291.     }
  292. }
  293.  
  294. int wmain(int argc, wchar_t* argv[])
  295. {
  296.     if (argc != 3) {
  297.         fwprintf(stderr, L"Usage:\n  %ls <fromPath> <toPath>\n", argv[0]);
  298.         return 2;
  299.     }
  300.     if (!RenameFileW(argv[1], argv[2])) {
  301.         DWORD err = GetLastError();
  302.         fwprintf(stderr, L"Rename failed.\n");
  303.         PrintLastErrorMessageW(err);
  304.         return 1;
  305.     }
  306.     wprintf(L"Rename succeeded.\n");
  307.     return 0;
  308. }

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at