From: Christopher Dykes Date: Fri, 1 Apr 2016 18:18:42 +0000 (-0700) Subject: Create the dirent.h portability header X-Git-Tag: 2016.07.26~381 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=ad4df4afedb3ac785d0dd91164872aa902770a98;p=folly.git Create the dirent.h portability header Summary: We don't have dirent.h on Windows, but we can emulate its behavior. Reviewed By: yfeldblum Differential Revision: D2978570 fb-gh-sync-id: af5ade0ea64ba22900440250e7125aa039a77f62 fbshipit-source-id: af5ade0ea64ba22900440250e7125aa039a77f62 --- diff --git a/folly/Makefile.am b/folly/Makefile.am index 3ea8c30a..96ff5665 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -270,6 +270,7 @@ nobase_follyinclude_HEADERS = \ portability/Asm.h \ portability/Config.h \ portability/Constexpr.h \ + portability/Dirent.h \ portability/Environment.h \ portability/GFlags.h \ portability/IOVec.h \ @@ -416,6 +417,7 @@ libfolly_la_SOURCES = \ detail/MemoryIdler.cpp \ MacAddress.cpp \ MemoryMapping.cpp \ + portability/Dirent.cpp \ portability/Environment.cpp \ portability/Malloc.cpp \ portability/String.cpp \ diff --git a/folly/portability/Dirent.cpp b/folly/portability/Dirent.cpp new file mode 100755 index 00000000..5c75a200 --- /dev/null +++ b/folly/portability/Dirent.cpp @@ -0,0 +1,134 @@ +/* + * Copyright 2016 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifdef _WIN32 +#include +#include + +#include + +struct DIR { + dirent dir{}; + HANDLE searchHandle{INVALID_HANDLE_VALUE}; + int entriesRead{0}; + char currentName[MAX_PATH * 3]; + std::string pattern; + + int close() { + return FindClose(searchHandle) ? 0 : -1; + } + + DIR* open() { + wchar_t patternBuf[MAX_PATH + 2]; + size_t len; + + if (mbstowcs_s(&len, patternBuf, MAX_PATH, pattern.c_str(), MAX_PATH - 2)) { + return nullptr; + } + + if (len && patternBuf[len - 1] != '/' && patternBuf[len - 1] != '\\') { + patternBuf[len++] = '\\'; + } + patternBuf[len++] = '*'; + patternBuf[len] = 0; + + WIN32_FIND_DATAW fdata; + HANDLE h = FindFirstFileW(patternBuf, &fdata); + if (h == INVALID_HANDLE_VALUE) { + return nullptr; + } + + searchHandle = h; + dir.d_name = currentName; + if (wcstombs(currentName, fdata.cFileName, MAX_PATH * 3) == (size_t)-1) { + return nullptr; + } + + setEntryType(fdata.dwFileAttributes); + return this; + } + + dirent* nextDir() { + if (entriesRead) { + WIN32_FIND_DATAW fdata; + if (!FindNextFileW(searchHandle, &fdata)) { + return nullptr; + } + + if (wcstombs(currentName, fdata.cFileName, MAX_PATH * 3) == (size_t)-1) { + errno = EBADF; + return nullptr; + } + setEntryType(fdata.dwFileAttributes); + } + + entriesRead++; + return &dir; + } + + private: + void setEntryType(DWORD attr) { + if (attr & FILE_ATTRIBUTE_DIRECTORY) { + dir.d_type = DT_DIR; + } else { + dir.d_type = DT_REG; + } + } +}; + +extern "C" { +int closedir(DIR* dir) { + auto ret = dir->close(); + delete dir; + return ret; +} + +DIR* opendir(const char* name) { + auto dir = new DIR(); + dir->pattern = name; + if (!dir->open()) { + delete dir; + return nullptr; + } + return dir; +} + +dirent* readdir(DIR* dir) { + return dir->nextDir(); +} + +int readdir_r(DIR* dir, dirent* buf, dirent** ent) { + if (!dir || !buf || !ent) { + return EBADF; + } + *ent = dir->nextDir(); + // Our normal readdir implementation is actually + // already reentrant, but we need to do this copy + // in case the caller expects buf to have the value. + if (*ent) { + *buf = dir->dir; + } + return 0; +} + +void rewinddir(DIR* dir) { + dir->close(); + dir->open(); +} +} +#endif diff --git a/folly/portability/Dirent.h b/folly/portability/Dirent.h new file mode 100755 index 00000000..f14e0c9d --- /dev/null +++ b/folly/portability/Dirent.h @@ -0,0 +1,41 @@ +/* + * Copyright 2016 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifndef _WIN32 +#include +#else + +#define DT_UNKNOWN 0 +#define DT_DIR 1 +#define DT_REG 2 +#define DT_LNK 3 +struct dirent { + unsigned char d_type; + char* d_name; +}; + +struct DIR; + +extern "C" { +int closedir(DIR* dir); +DIR* opendir(const char* name); +dirent* readdir(DIR* dir); +int readdir_r(DIR* dir, dirent* buf, dirent** ent); +void rewinddir(DIR* dir); +} +#endif