Skip to content
Closed
3 changes: 3 additions & 0 deletions libc/config/linux/api.td
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ def FCntlAPI : PublicAPI<"fcntl.h"> {
];
}

def FTWAPI : PublicAPI<"ftw.h"> {
}

def IntTypesAPI : PublicAPI<"inttypes.h"> {
let Types = ["imaxdiv_t"];
}
Expand Down
5 changes: 4 additions & 1 deletion libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.fcntl.open
libc.src.fcntl.openat

# ftw.h entrypoints
libc.src.ftw.ftw

# sched.h entrypoints
libc.src.sched.sched_get_priority_max
libc.src.sched.sched_get_priority_min
Expand Down Expand Up @@ -429,7 +432,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.fabs
libc.src.math.fabsf
libc.src.math.fabsl
libc.src.math.fadd
libc.src.math.fadd
libc.src.math.faddl
libc.src.math.fadd
libc.src.math.fdim
Expand Down
9 changes: 9 additions & 0 deletions libc/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ add_header_macro(
.llvm_libc_common_h
)

add_header_macro(
ftw
../libc/newhdrgen/yaml/ftw.yaml
ftw.h.def
ftw.h
DEPENDS
.llvm_libc_common_h
)

add_header_macro(
dlfcn
../libc/newhdrgen/yaml/dlfcn.yaml
Expand Down
43 changes: 43 additions & 0 deletions libc/include/ftw.h.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===-- C standard library header ftw.h -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_FTW_H
#define LLVM_LIBC_FTW_H

#include "__llvm-libc-common.h"

/* macros needed */

enum {
FTW_D,
FTW_DNR,
FTW_F,
FTW_DP,
FTW_SL,
FTW_NS,
FTW_SLN
}; // typeflag

enum {
FTW_ACTIONRETVAL,
FTW_CHDIR,
FTW_DEPTH,
FTW_MOUNT,
FTW_PHYS
}; // flags

enum {
FTW_CONTINUE,
FTW_SKIP_SIBLINGS,
FTW_SKIP_SUBTREE,
FTW_STOP
}; /* fn return */

%%public_api()

#endif // LLVM_LIBC_FTW_H
15 changes: 15 additions & 0 deletions libc/newhdrgen/yaml/ftw.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
header: fcntl.h
macros: []
types: []
enums: []
objects: []
functions:
- name: ftw
standards:
- POSIX
return_type: int
arguments:
- type: const char *
- type: int
- type: int

15 changes: 15 additions & 0 deletions libc/newhdrgen/yaml/ftw.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
header: fcntl.h
macros: []
types: []
enums: []
objects: []
functions:
- name: ftw
standards:
- POSIX
return_type: int
arguments:
- type: const char *
- type: int
- type: int

32 changes: 32 additions & 0 deletions libc/spec/posix.td
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,37 @@ def POSIX : StandardSpec<"POSIX"> {
]
>;

HeaderSpec FTW = HeaderSpec<
"ftw.h",
[], // Macros
[], // Types
[
EnumeratedNameValue<"FTW_CHDIR">,
EnumeratedNameValue<"FTW_DEPTH">,
EnumeratedNameValue<"FTW_MOUNT">,
EnumeratedNameValue<"FTW_PHYS">,
EnumeratedNameValue<"FTW_F">,
EnumeratedNameValue<"FTW_D">,
EnumeratedNameValue<"FTW_DP">,
EnumeratedNameValue<"FTW_SL">,
EnumeratedNameValue<"FTW_SLN">,
EnumeratedNameValue<"FTW_DNR">,
EnumeratedNameValue<"FTW_SLN">
], // Enumerations
[
FunctionSpec<
"ftw",
RetValSpec<IntType>,
[ArgSpec<ConstCharPtr>]
>,
FunctionSpec<
"nftw",
RetValSpec<IntType>,
[ArgSpec<ConstCharPtr>]
>
]
>;

HeaderSpec SysMMan = HeaderSpec<
"sys/mman.h",
[
Expand Down Expand Up @@ -1842,6 +1873,7 @@ def POSIX : StandardSpec<"POSIX"> {
DlFcn,
Errno,
FCntl,
FTW,
PThread,
Sched,
Signal,
Expand Down
1 change: 1 addition & 0 deletions libc/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_subdirectory(ctype)
add_subdirectory(dlfcn)
add_subdirectory(errno)
add_subdirectory(fenv)
add_subdirectory(ftw)
add_subdirectory(inttypes)
add_subdirectory(math)
add_subdirectory(stdbit)
Expand Down
14 changes: 14 additions & 0 deletions libc/src/ftw/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
add_entrypoint_object(
ftw
SRCS
ftw.cpp
HDRS
ftw.h
DEPENDS
libc.include.ftw
libc.src.__support.FPUtil.fenv_impl
libc.src.errno.errno
libc.src.fcntl.open
libc.src.unistd.close

)
178 changes: 178 additions & 0 deletions libc/src/ftw/ftw.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
//===-- Implementation of ftw function ------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/ftw/ftw.h"

#include "src/__support/common.h"
#include "src/__support/CPP/string.h"
#include "src/errno/libc_errno.h"
#include "src/fcntl/open.h"
#include "src/unistd/close.h"

#include <ftw.h>
#include <stddef.h>
#include <sys/stat.h>


namespace LIBC_NAMESPACE_DECL {
class Func {
public:
virtual int call(const char*, const struct stat*, int, struct FTW*) = 0;
virtual ~Func() = 0;
};

using nftwFn = int (*)(const char* filePath, const struct stat* statBuf,
int tFlag, struct FTW* ftwbuf);

using ftwFn = int (*)(const char* filePath, const struct stat* statBuf,
int tFlag);

class NftwFunc : public Func {
public:
NftwFunc(nftwFn fn) : fn(fn) {}
virtual int call(const char* dirPath, const struct stat* statBuf, int tFlag,
struct FTW* ftwBuf) override {
return fn(dirPath, statBuf, tFlag, ftwBuf);
}
virtual ~NftwFunc() {}

private:
const nftwFn fn;
};

class FtwFunc : public Func {
public:
FtwFunc(ftwFn fn) : fn(fn) {}
virtual int call(const char* dirPath, const struct stat* statBuf, int tFlag,
struct FTW*) override {
return fn(dirPath, statBuf, tFlag);
}
virtual ~FtwFunc() {}

private:
const ftwFn fn;
};

int doMergedFtw(const cpp::string& dirPath, Func& fn, int fdLimit, int flags,
int level) {
// fdLimit specifies the maximum number of directories that ftw()
// will hold open simultaneously. When a directory is opened, fdLimit is
// decreased and if it becomes 0 or less, we won't open any more directories.
if (fdLimit <= 0) {
return 0;
}

// Determine the type of path that is passed.
int typeFlag;
struct stat statBuf;
if (flags & FTW_PHYS) {
if (lstat(dirPath.c_str(), &statBuf) < 0) return -1;
} else {
if (stat(dirPath.c_str(), &statBuf) < 0) {
if (!lstat(dirPath.c_str(), &statBuf)) {
typeFlag = FTW_SLN; /* Symbolic link pointing to a nonexistent file. */
} else if (libc_errno != EACCES) {
/* stat failed with an errror that is not Permission denied */
return -1;
} else {
/* The probable cause for the failure is that the caller had read
* permission on the parent directory, so that the filename fpath could
* be seen, but did not have execute permission on the directory.
*/
typeFlag = FTW_NS;
}
}
}

if (S_ISDIR(statBuf.st_mode)) {
if (flags & FTW_DEPTH) {
typeFlag = FTW_DP; /* Directory, all subdirs have been visited. */
} else {
typeFlag = FTW_D; /* Directory. */
}
} else if (S_ISLNK(statBuf.st_mode)) {
if (flags & FTW_PHYS) {
typeFlag = FTW_SL; /* Symbolic link. */
} else {
typeFlag = FTW_SLN; /* Symbolic link pointing to a nonexistent file. */
}
} else {
typeFlag = FTW_F; /* Regular file. */
}

struct FTW ftwBuf;
// Find the base by finding the last slash.
size_t slash_found = dirPath.rfind("/");
if (slash_found != cpp::string::npos) {
ftwBuf.base = slash_found + 1;
}

ftwBuf.level = level;

// If the dirPath is a file, call the function on it and return.
if ((typeFlag == FTW_SL) || (typeFlag == FTW_F)) {
int returnValue = fn.call(dirPath.c_str(), &statBuf, typeFlag, &ftwBuf);
if (returnValue) {
return returnValue;
}
return 0;
}

// If FTW_DEPTH is not set, nftw() shall report any directory before reporting
// the files in that directory.
if (!(flags & FTW_DEPTH)) {
// Call the function on the directory.
int directory_fd = open(dirPath.c_str(), O_RDONLY);
if (directory_fd < 0 && libc_errno == EACCES) {
typeFlag = FTW_DNR; /* Directory can't be read. */
}
close(directory_fd);

int returnValue = fn.call(dirPath.c_str(), &statBuf, typeFlag, &ftwBuf);
if (returnValue) {
return returnValue;
}
}

for (std::error_code ec; auto const& dir_entry :
std::filesystem::directory_iterator(dirPath, ec)) {
if (ec) continue;
int returnValue =
doMergedFtw(dir_entry.path(), fn, fdLimit - 1, flags, ftwBuf.level + 1);
if (returnValue) {
return returnValue;
}
}

// If FTW_DEPTH is set, nftw() shall report all files in a directory before
// reporting the directory itself.
if (flags & FTW_DEPTH) {
// Call the function on the directory.
return fn.call(dirPath.c_str(), &statBuf, typeFlag, &ftwBuf);
}
return 0;
}

LLVM_LIBC_FUNCTION(int, nftw, (const char *dirPath,
int (*fn)(const char *filePath, const struct stat *statBuf,
int tFlag, struct FTW *ftwbuf),
int fdLimit, int flags)) {
NftwFunc wrappedFn{fn};
return doMergedFtw(dirPath, wrappedFn, fdLimit, flags, 0);
}

LLVM_LIBC_FUNCTION(int, ftw, (const char *dirPath,
int (*fn)(const char *filePath, const struct stat *statBuf,
int tFlag),
int fdLimit)) {
FtwFunc wrappedFn{fn};
return doMergedFtw(dirPath, wrappedFn, fdLimit, FTW_PHYS, 0);
}

} // namespace LIBC_NAMESPACE_DECL

20 changes: 20 additions & 0 deletions libc/src/ftw/ftw.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header of ftw ----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_FTW_FTW_H
#define LLVM_LIBC_SRC_FTW_FTW_H

#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {

int ftw(const char* dirpath, int noopenfd, int flags);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_FTW_FTW_H
1 change: 1 addition & 0 deletions libc/test/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ add_subdirectory(complex)
add_subdirectory(ctype)
add_subdirectory(errno)
add_subdirectory(fenv)
add_subdirectory(ftw)
add_subdirectory(math)
add_subdirectory(search)
add_subdirectory(stdbit)
Expand Down
Loading