From 054cabf6002d2f4f24ee88f155f4d83b015d851e Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Thu, 5 Oct 2023 08:27:53 +0900 Subject: [PATCH] Allow NUL and \\.\NUL in paths specified as command line arguments (#2056) --- Src/DiffContext.cpp | 2 +- Src/DiffWrapper.cpp | 4 ++-- Src/DirDoc.cpp | 2 +- Src/DirView.cpp | 4 ++-- Src/FolderCmp.cpp | 2 +- Src/HexMergeDoc.cpp | 4 +++- Src/ImgMergeFrm.cpp | 6 +++++- Src/MainFrm.cpp | 3 ++- Src/MergeDoc.cpp | 4 +++- Src/OpenView.cpp | 5 +++-- Src/PatchDlg.cpp | 4 ++-- Src/PatchTool.cpp | 4 ++-- Src/WebPageDiffFrm.cpp | 8 +++++++- Src/codepage_detect.cpp | 2 +- Src/diffutils/src/io.c | 9 +++++++-- Src/paths.cpp | 6 ++++++ Src/paths.h | 4 ++++ 17 files changed, 52 insertions(+), 21 deletions(-) diff --git a/Src/DiffContext.cpp b/Src/DiffContext.cpp index d29c98fe1..868edbdb1 100644 --- a/Src/DiffContext.cpp +++ b/Src/DiffContext.cpp @@ -268,7 +268,7 @@ void CDiffContext::GetComparePaths(const DIFFITEM &di, PathContext & tFiles) con } else { - tFiles.SetPath(nIndex, _T("NUL"), false); + tFiles.SetPath(nIndex, paths::NATIVE_NULL_DEVICE_NAME, false); } } } diff --git a/Src/DiffWrapper.cpp b/Src/DiffWrapper.cpp index c990d5608..b0887a75d 100644 --- a/Src/DiffWrapper.cpp +++ b/Src/DiffWrapper.cpp @@ -1648,12 +1648,12 @@ void CDiffWrapper::WritePatchFile(struct change * script, file_data * inf) return; } - if (strcmp(inf[0].name, "NUL") == 0) + if (paths::IsNullDeviceName(ucr::toTString(inf[0].name))) { free((void *)inf_patch[0].name); inf_patch[0].name = strdup("/dev/null"); } - if (strcmp(inf[1].name, "NUL") == 0) + if (paths::IsNullDeviceName(ucr::toTString(inf[1].name))) { free((void *)inf_patch[1].name); inf_patch[1].name = strdup("/dev/null"); diff --git a/Src/DirDoc.cpp b/Src/DirDoc.cpp index 7b4d8da13..fe9f55c35 100644 --- a/Src/DirDoc.cpp +++ b/Src/DirDoc.cpp @@ -942,7 +942,7 @@ bool CDirDoc::CompareFilesIfFilesAreLarge(int nFiles, const FileLocation ifilelo PathContext paths; for (int i = 0; i < nFiles; ++i) - paths.SetPath(i, ifileloc[i].filepath.empty() ? _T("NUL") : paths::GetParentPath(ifileloc[i].filepath)); + paths.SetPath(i, ifileloc[i].filepath.empty() ? paths::NATIVE_NULL_DEVICE_NAME : paths::GetParentPath(ifileloc[i].filepath)); CDiffContext ctxt(paths, CMP_QUICK_CONTENT); DirViewColItems ci(nFiles, std::vector{}); String msg = LoadResString(IDS_COMPARE_LARGE_FILES); diff --git a/Src/DirView.cpp b/Src/DirView.cpp index 078a5a902..eacd819e2 100644 --- a/Src/DirView.cpp +++ b/Src/DirView.cpp @@ -1405,7 +1405,7 @@ void CDirView::Open(CDirDoc *pDoc, const PathContext& paths, fileopenflags_t dwF if (paths::DoesPathExist(paths[i]) == paths::DOES_NOT_EXIST) { strDesc[i] = sUntitled[i]; - filteredPaths.SetPath(i, _T("NUL"), false); + filteredPaths.SetPath(i, paths::NATIVE_NULL_DEVICE_NAME, false); } else { @@ -1583,7 +1583,7 @@ void CDirView::OpenSelectionAs(UINT id) if (paths::DoesPathExist(paths[pane]) == paths::DOES_NOT_EXIST) { strDesc[pane] = sUntitled[pane]; - filteredPaths.SetPath(pane, _T("NUL"), false); + filteredPaths.SetPath(pane, paths::NATIVE_NULL_DEVICE_NAME, false); } else { diff --git a/Src/FolderCmp.cpp b/Src/FolderCmp.cpp index 4a3fd5ec8..1bbe4c1ec 100644 --- a/Src/FolderCmp.cpp +++ b/Src/FolderCmp.cpp @@ -137,7 +137,7 @@ int FolderCmp::prepAndCompareFiles(DIFFITEM &di) //DiffFileData diffdata; //(filepathTransformed1, filepathTransformed2); // Invoke unpacking plugins - if (infoUnpacker && strutils::compare_nocase(filepathUnpacked[nIndex], _T("NUL")) != 0) + if (infoUnpacker && !paths::IsNullDeviceName(filepathUnpacked[nIndex])) { if (!infoUnpacker->Unpacking(nullptr, filepathUnpacked[nIndex], filteredFilenames, { tFiles[nIndex] })) goto exitPrepAndCompare; diff --git a/Src/HexMergeDoc.cpp b/Src/HexMergeDoc.cpp index a35fe4168..598d6aede 100644 --- a/Src/HexMergeDoc.cpp +++ b/Src/HexMergeDoc.cpp @@ -484,7 +484,7 @@ CString CHexMergeDoc::GetTooltipString() const */ HRESULT CHexMergeDoc::LoadOneFile(int index, const tchar_t* filename, bool readOnly, const String& strDesc) { - if (filename[0]) + if (filename[0] && !paths::IsNullDeviceName(filename)) { if (Try(m_pView[index]->LoadFile(filename), MB_ICONSTOP) != 0) return E_FAIL; @@ -501,6 +501,8 @@ HRESULT CHexMergeDoc::LoadOneFile(int index, const tchar_t* filename, bool readO { m_nBufferType[index] = BUFFERTYPE::UNNAMED; m_strDesc[index] = strDesc; + if (m_strDesc[index].empty()) + m_strDesc[index] = (index == 0) ? _("Untitled left") : ((m_nBuffers < 3 || index == 2) ? _("Untitled right") : _("Untitled middle")); } UpdateHeaderPath(index); m_pView[index]->ResizeWindow(); diff --git a/Src/ImgMergeFrm.cpp b/Src/ImgMergeFrm.cpp index 3bbf90f37..45210b5ac 100644 --- a/Src/ImgMergeFrm.cpp +++ b/Src/ImgMergeFrm.cpp @@ -227,8 +227,12 @@ bool CImgMergeFrame::OpenDocs(int nFiles, const FileLocation fileloc[], const bo m_filePaths.SetPath(pane, fileloc[pane].filepath, false); m_bRO[pane] = bRO[pane]; m_strDesc[pane] = strDesc ? strDesc[pane] : _T(""); - if (fileloc[pane].filepath.empty()) + if (fileloc[pane].filepath.empty() || paths::IsNullDeviceName(fileloc[pane].filepath)) + { m_nBufferType[pane] = BUFFERTYPE::UNNAMED; + if (m_strDesc[pane].empty()) + m_strDesc[pane] = (pane == 0) ? _("Untitled left") : ((nFiles < 3 || pane == 2) ? _("Untitled right") : _("Untitled middle")); + } else { m_nBufferType[pane] = (!strDesc || strDesc[pane].empty()) ? BUFFERTYPE::NORMAL : BUFFERTYPE::NORMAL_NAMED; diff --git a/Src/MainFrm.cpp b/Src/MainFrm.cpp index 2d64ff8aa..330357589 100644 --- a/Src/MainFrm.cpp +++ b/Src/MainFrm.cpp @@ -1346,7 +1346,8 @@ bool CMainFrame::DoFileOrFolderOpen(const PathContext * pFiles /*= nullptr*/, paths::PATH_EXISTENCE pathsType = paths::GetPairComparability(tFiles, IsArchiveFile); bool allowFolderCompare = (static_cast(nID) <= 0); if (tFiles.GetSize() < 2 || pathsType == paths::DOES_NOT_EXIST && - !std::any_of(tFiles.begin(), tFiles.end(), [](const auto& path) { return path.empty() || paths::IsURL(path); })) + !std::any_of(tFiles.begin(), tFiles.end(), + [](const auto& path) { return path.empty() || paths::IsNullDeviceName(path) || paths::IsURL(path); })) { CMultiDocTemplate* pOpenTemplate = theApp.GetOpenTemplate(); if (m_pMenus[MENU_OPENVIEW] == nullptr) diff --git a/Src/MergeDoc.cpp b/Src/MergeDoc.cpp index 3d20dce5d..ddcb980f9 100644 --- a/Src/MergeDoc.cpp +++ b/Src/MergeDoc.cpp @@ -2870,7 +2870,7 @@ FileLoadResult::flags_t CMergeDoc::LoadOneFile(int index, const String& filename FileLoadResult::flags_t loadSuccess = FileLoadResult::FRESULT_ERROR;; m_strDesc[index] = strDesc; - if (!filename.empty()) + if (!filename.empty() && !paths::IsNullDeviceName(filename)) { if (strDesc.empty()) m_nBufferType[index] = BUFFERTYPE::NORMAL; @@ -2893,6 +2893,8 @@ FileLoadResult::flags_t CMergeDoc::LoadOneFile(int index, const String& filename } else { + if (m_strDesc[index].empty()) + m_strDesc[index] = (index == 0) ? _("Untitled left") : ((m_nBuffers < 3 || index == 2) ? _("Untitled right") : _("Untitled middle")); m_nBufferType[index] = BUFFERTYPE::UNNAMED; m_ptBuf[index]->InitNew(); m_ptBuf[index]->m_encoding = encoding; diff --git a/Src/OpenView.cpp b/Src/OpenView.cpp index d0e8b9943..bcf020a8f 100644 --- a/Src/OpenView.cpp +++ b/Src/OpenView.cpp @@ -639,7 +639,8 @@ void COpenView::OnCompare(UINT nID) pathsType = paths::GetPairComparability(m_files, IsArchiveFile); if (pathsType == paths::DOES_NOT_EXIST && - !std::any_of(m_files.begin(), m_files.end(), [](const auto& path) { return paths::IsURL(path); })) + !std::any_of(m_files.begin(), m_files.end(), + [](const auto& path) { return paths::IsURL(path) || paths::IsNullDeviceName(path); })) { LangMessageBox(IDS_ERROR_INCOMPARABLE, MB_ICONSTOP); return; @@ -1124,7 +1125,7 @@ static UINT UpdateButtonStatesThread(LPVOID lpParam) pathType[i] = paths::DoesPathExist(paths[i], IsArchiveFile); if (pathType[i] == paths::DOES_NOT_EXIST) { - if (paths::IsURL(paths[i])) + if (paths::IsURL(paths[i]) || paths::IsNullDeviceName(paths[i])) pathType[i] = paths::IS_EXISTING_FILE; else bInvalid[i] = true; diff --git a/Src/PatchDlg.cpp b/Src/PatchDlg.cpp index 005727202..2654491d9 100644 --- a/Src/PatchDlg.cpp +++ b/Src/PatchDlg.cpp @@ -103,8 +103,8 @@ void CPatchDlg::OnOK() } if (selectCount == 1) { - bool file1Ok = (paths::DoesPathExist(m_file1) != paths::DOES_NOT_EXIST); - bool file2Ok = (paths::DoesPathExist(m_file2) != paths::DOES_NOT_EXIST); + bool file1Ok = (paths::DoesPathExist(m_file1) != paths::DOES_NOT_EXIST) || paths::IsNullDeviceName(m_file1); + bool file2Ok = (paths::DoesPathExist(m_file2) != paths::DOES_NOT_EXIST) || paths::IsNullDeviceName(m_file2); if (!file1Ok || !file2Ok) { diff --git a/Src/PatchTool.cpp b/Src/PatchTool.cpp index d6b276f2d..1793023d6 100644 --- a/Src/PatchTool.cpp +++ b/Src/PatchTool.cpp @@ -143,8 +143,8 @@ int CPatchTool::CreatePatch() for (size_t index = 0; index < fileCount; index++) { const PATCHFILES& tFiles = fileList[index]; - String filename1 = tFiles.lfile.length() == 0 ? _T("NUL") : tFiles.lfile; - String filename2 = tFiles.rfile.length() == 0 ? _T("NUL") : tFiles.rfile; + String filename1 = tFiles.lfile.length() == 0 ? paths::NATIVE_NULL_DEVICE_NAME : tFiles.lfile; + String filename2 = tFiles.rfile.length() == 0 ? paths::NATIVE_NULL_DEVICE_NAME : tFiles.rfile; // Set up DiffWrapper m_diffWrapper.SetPaths(PathContext(filename1, filename2), false); diff --git a/Src/WebPageDiffFrm.cpp b/Src/WebPageDiffFrm.cpp index 2e9b3b605..cb5431e23 100644 --- a/Src/WebPageDiffFrm.cpp +++ b/Src/WebPageDiffFrm.cpp @@ -203,8 +203,14 @@ bool CWebPageDiffFrame::OpenDocs(int nFiles, const FileLocation fileloc[], const m_filePaths.SetPath(pane, fileloc[pane].filepath, false); m_bRO[pane] = bRO[pane]; m_strDesc[pane] = strDesc ? strDesc[pane] : _T(""); - if (fileloc[pane].filepath.empty()) + if (fileloc[pane].filepath.empty() || paths::IsNullDeviceName(fileloc[pane].filepath)) + { m_nBufferType[pane] = BUFFERTYPE::UNNAMED; + if (m_strDesc[pane].empty()) + m_strDesc[pane] = (pane == 0) ? _("Untitled left") : ((nFiles < 3 || pane == 2) ? _("Untitled right") : _("Untitled middle")); + if (paths::IsNullDeviceName(fileloc[pane].filepath)) + m_filePaths.SetPath(pane, _T("about:blank"), false); + } else { m_nBufferType[pane] = (!strDesc || strDesc[pane].empty()) ? BUFFERTYPE::NORMAL : BUFFERTYPE::NORMAL_NAMED; diff --git a/Src/codepage_detect.cpp b/Src/codepage_detect.cpp index a6a66542b..563896697 100644 --- a/Src/codepage_detect.cpp +++ b/Src/codepage_detect.cpp @@ -243,7 +243,7 @@ FileTextEncoding Guess(const String& ext, const void * src, size_t len, int gues */ FileTextEncoding Guess(const String& filepath, int guessEncodingType, ptrdiff_t mapmaxlen) { - CMarkdown::FileImage fi(filepath != _T("NUL") ? filepath.c_str() : nullptr, mapmaxlen); + CMarkdown::FileImage fi(!paths::IsNullDeviceName(filepath) ? filepath.c_str() : nullptr, mapmaxlen); String ext = paths::FindExtension(filepath); return Guess(ext, fi.pImage, fi.cbImage, guessEncodingType); } diff --git a/Src/diffutils/src/io.c b/Src/diffutils/src/io.c index 5ec82ad74..4611ff78b 100644 --- a/Src/diffutils/src/io.c +++ b/Src/diffutils/src/io.c @@ -997,6 +997,11 @@ static int const primes[] = 0 }; +static int isnulldev(const char* filename) +{ + return (_stricmp(filename, "NUL") == 0 || _stricmp(filename, "\\\\.\\NUL") == 0); +} + /* Given a vector of two file_data objects, read the file associated with each one, and build the table of equivalence classes. Return 1 if either file appears to be a binary file. @@ -1033,8 +1038,8 @@ read_files (struct file_data filevec[], int pretend_binary, int *bin_file) // Are both files Open and Regular (no Pipes, Directories, Devices (except NUL)) if (filevec[0].desc < 0 || filevec[1].desc < 0 || - (!(S_ISREG (filevec[0].stat.st_mode)) && strcmp(filevec[0].name, "NUL") != 0) || - (!(S_ISREG (filevec[1].stat.st_mode)) && strcmp(filevec[1].name, "NUL") != 0)) + (!(S_ISREG (filevec[0].stat.st_mode)) && !isnulldev(filevec[0].name)) || + (!(S_ISREG (filevec[1].stat.st_mode)) && !isnulldev(filevec[1].name))) { assert(!S_ISCHR(filevec[0].stat.st_mode)); assert(!S_ISCHR(filevec[1].stat.st_mode)); diff --git a/Src/paths.cpp b/Src/paths.cpp index baaf6c616..335299b68 100644 --- a/Src/paths.cpp +++ b/Src/paths.cpp @@ -815,4 +815,10 @@ bool IsValidName(const String& name) return true; } +bool IsNullDeviceName(const String& name) +{ + return (tc::tcsicmp(name.c_str(), NATIVE_NULL_DEVICE_NAME) == 0 || + tc::tcsicmp(name.c_str(), NATIVE_NULL_DEVICE_NAME_LONG) == 0); +} + } diff --git a/Src/paths.h b/Src/paths.h index fb9e51d6f..79f286cfb 100644 --- a/Src/paths.h +++ b/Src/paths.h @@ -25,6 +25,9 @@ typedef enum IS_EXISTING_DIR, /**< It is existing folder */ } PATH_EXISTENCE; +constexpr tchar_t* NATIVE_NULL_DEVICE_NAME = _T("NUL"); +constexpr tchar_t* NATIVE_NULL_DEVICE_NAME_LONG = _T("\\\\.\\NUL"); + bool EndsWithSlash(const String& s); PATH_EXISTENCE DoesPathExist(const String& szPath, bool (*IsArchiveFile)(const String&) = nullptr); @@ -54,4 +57,5 @@ inline String AddTrailingSlash(const String& path) { return !EndsWithSlash(path) String ToWindowsPath(const String& path); String ToUnixPath(const String& path); bool IsValidName(const String& name); +bool IsNullDeviceName(const String& name); } -- 2.11.0