dirent.cc (4625B)
1 // Copyright (c) the JPEG XL Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #if defined(_WIN32) || defined(_WIN64) 16 #include "third_party/dirent.h" 17 18 #include "lib/jxl/base/status.h" 19 20 #ifndef NOMINMAX 21 #define NOMINMAX 22 #endif // NOMINMAX 23 24 #include <errno.h> 25 #include <windows.h> 26 27 #include <memory> 28 #include <string> 29 30 int mkdir(const char* path, mode_t /*mode*/) { 31 const LPSECURITY_ATTRIBUTES sec = nullptr; 32 if (!CreateDirectory(path, sec)) { 33 JXL_NOTIFY_ERROR("Failed to create directory %s", path); 34 return -1; 35 } 36 return 0; 37 } 38 39 // Modified from code bearing the following notice: 40 // https://trac.wildfiregames.com/browser/ps/trunk/source/lib/sysdep/os/ 41 /* Copyright (C) 2010 Wildfire Games. 42 * 43 * Permission is hereby granted, free of charge, to any person obtaining 44 * a copy of this software and associated documentation files (the 45 * "Software"), to deal in the Software without restriction, including 46 * without limitation the rights to use, copy, modify, merge, publish, 47 * distribute, sublicense, and/or sell copies of the Software, and to 48 * permit persons to whom the Software is furnished to do so, subject to 49 * the following conditions: 50 * 51 * The above copyright notice and this permission notice shall be included 52 * in all copies or substantial portions of the Software. 53 * 54 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 55 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 56 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 57 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 58 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 59 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 60 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 61 */ 62 63 struct DIR { 64 HANDLE hFind; 65 66 WIN32_FIND_DATA findData; // indeterminate if hFind == INVALID_HANDLE_VALUE 67 68 // readdir will return the address of this member. 69 // (must be stored in DIR to allow multiple independent 70 // opendir/readdir sequences). 71 dirent ent; 72 73 // used by readdir to skip the first FindNextFile. 74 size_t numCalls = 0; 75 }; 76 77 static bool IsValidDirectory(const char* path) { 78 const DWORD fileAttributes = GetFileAttributes(path); 79 80 // path not found 81 if (fileAttributes == INVALID_FILE_ATTRIBUTES) return false; 82 83 // not a directory 84 if ((fileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) return false; 85 86 return true; 87 } 88 89 DIR* opendir(const char* path) { 90 if (!IsValidDirectory(path)) { 91 errno = ENOENT; 92 return nullptr; 93 } 94 95 std::unique_ptr<DIR> d(new DIR); 96 97 // NB: "c:\\path" only returns information about that directory; 98 // trailing slashes aren't allowed. append "\\*" to retrieve its entries. 99 std::string searchPath(path); 100 if (searchPath.back() != '/' && searchPath.back() != '\\') { 101 searchPath += '\\'; 102 } 103 searchPath += '*'; 104 105 // (we don't defer FindFirstFile until readdir because callers 106 // expect us to return 0 if directory reading will/did fail.) 107 d->hFind = FindFirstFile(searchPath.c_str(), &d->findData); 108 if (d->hFind != INVALID_HANDLE_VALUE) return d.release(); 109 if (GetLastError() == ERROR_NO_MORE_FILES) return d.release(); // empty 110 111 JXL_NOTIFY_ERROR("Failed to open directory %s", searchPath.c_str()); 112 return nullptr; 113 } 114 115 int closedir(DIR* dir) { 116 delete dir; 117 return 0; 118 } 119 120 dirent* readdir(DIR* d) { 121 // "empty" case from opendir 122 if (d->hFind == INVALID_HANDLE_VALUE) return nullptr; 123 124 // until end of directory or a valid entry was found: 125 for (;;) { 126 if (d->numCalls++ != 0) // (skip first call to FindNextFile - see opendir) 127 { 128 if (!FindNextFile(d->hFind, &d->findData)) { 129 JXL_ASSERT(GetLastError() == ERROR_NO_MORE_FILES); 130 SetLastError(0); 131 return nullptr; // end of directory or error 132 } 133 } 134 135 // only return non-hidden and non-system entries 136 if ((d->findData.dwFileAttributes & 137 (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) == 0) { 138 d->ent.d_name = d->findData.cFileName; 139 return &d->ent; 140 } 141 } 142 } 143 144 #endif // #if defined(_WIN32) || defined(_WIN64)