Browse Source

fixed MakeTempName() for paths > MAX_PATH

added tests

fixed MakeTempName() for paths > MAX_PATH
d3aee81b508fa0de3fea66b71618981594f262e4
star-dm 11 months ago
parent
commit
d2527272d4
4 changed files with 66 additions and 17 deletions
  1. 8 0
      build/long-path.manifest
  2. 13 17
      util/system/mktemp.cpp
  3. 41 0
      util/system/mktemp_ut.cpp
  4. 4 0
      util/system/ut/ya.make

+ 8 - 0
build/long-path.manifest

@@ -0,0 +1,8 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+    <asmv3:application>
+        <asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+            <ws2:longPathAware>true</ws2:longPathAware>
+        </asmv3:windowsSettings>
+    </asmv3:application>
+</assembly>

+ 13 - 17
util/system/mktemp.cpp

@@ -15,7 +15,6 @@
 extern "C" int mkstemps(char* path, int slen);
 
 TString MakeTempName(const char* wrkDir, const char* prefix, const char* extension) {
-#ifndef _win32_
     TString filePath;
 
     if (wrkDir && *wrkDir) {
@@ -24,6 +23,19 @@ TString MakeTempName(const char* wrkDir, const char* prefix, const char* extensi
         filePath += GetSystemTempDir();
     }
 
+#ifdef _win32_
+    // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamea?redirectedfrom=MSDN
+    const unsigned int DirPathMaxLen = 247;
+    if (filePath.length() <= DirPathMaxLen) {
+        // it always takes up to 3 characters, no more
+        char winFilePath[MAX_PATH];
+        if (GetTempFileName(filePath.c_str(), (prefix) ? (prefix) : "yan", 0,
+                            winFilePath)) {
+            return winFilePath;
+        }
+    }
+#endif // _win32_
+
     if (filePath.back() != '/') {
         filePath += '/';
     }
@@ -49,22 +61,6 @@ TString MakeTempName(const char* wrkDir, const char* prefix, const char* extensi
         close(fd);
         return filePath;
     }
-#else
-    char tmpDir[MAX_PATH + 1]; // +1 -- for terminating null character
-    char filePath[MAX_PATH];
-    const char* pDir = 0;
-
-    if (wrkDir && *wrkDir) {
-        pDir = wrkDir;
-    } else if (GetTempPath(MAX_PATH + 1, tmpDir)) {
-        pDir = tmpDir;
-    }
-
-    // it always takes up to 3 characters, no more
-    if (GetTempFileName(pDir, (prefix) ? (prefix) : "yan", 0, filePath)) {
-        return filePath;
-    }
-#endif
 
     ythrow TSystemError() << "can not create temp name(" << wrkDir << ", " << prefix << ", " << extension << ")";
 }

+ 41 - 0
util/system/mktemp_ut.cpp

@@ -0,0 +1,41 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <filesystem>
+
+#include "tempfile.h"
+
+#include <util/folder/dirut.h>
+
+Y_UNIT_TEST_SUITE(MakeTempFileSuite) {
+    static const char TestDir[] = "Test";
+    static const char Prefix[] = "PREFIX_____PREFIX";
+    static const char Extension[] = "txt";
+    static const unsigned int PathSegmentSizeNormal = 55;
+    static const unsigned int PathSegmentSizeLong = 255;
+
+    Y_UNIT_TEST(TestMakeTempName) {
+        const TFsPath systemTemp{GetSystemTempDir()};
+        UNIT_ASSERT(systemTemp.Exists());
+
+        for (auto dirNameLength : {PathSegmentSizeNormal, PathSegmentSizeLong}) {
+            const TFsPath testDir{systemTemp / TestDir};
+            testDir.MkDir();
+            UNIT_ASSERT(testDir.Exists());
+            Y_DEFER {
+                std::filesystem::remove_all(testDir.c_str());
+            };
+
+            const TString dirName(dirNameLength, 'X');
+            const TFsPath dirPath = testDir / dirName;
+            UNIT_ASSERT(std::filesystem::create_directory(dirPath.GetPath().c_str()));
+
+            TString tempFilePath;
+            try {
+                tempFilePath = MakeTempName(dirPath.c_str(), Prefix, Extension);
+            } catch (const TSystemError& ex) {
+                Cerr << "Unexpected exception: " << ex.what() << Endl;
+            }
+            UNIT_ASSERT(TFsPath{tempFilePath}.Exists());
+        }
+    }
+}

+ 4 - 0
util/system/ut/ya.make

@@ -83,10 +83,14 @@ ENDIF()
 IF (OS_WINDOWS)
     SRCS(
         system/fs_win_ut.cpp
+        system/mktemp_ut.cpp
     )
     DEPENDS(
         util/system/ut/stdin_osfhandle
     )
+    IF (ARCH_X86_64)
+        WINDOWS_LONG_PATH_MANIFEST()
+    ENDIF()
 ENDIF()
 
 REQUIREMENTS(ram:12)