Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1625759
Add dirent for XPlatform
GauthamBanasandra May 17, 2022
ac14466
Do not return ref type in variant
GauthamBanasandra May 19, 2022
af99d8e
Add C API for dirent
GauthamBanasandra May 19, 2022
f0154ca
Fix compilation issue
GauthamBanasandra May 21, 2022
433cbca
Add unit test for dirent
GauthamBanasandra May 21, 2022
3c907b4
Fix compilation issue
GauthamBanasandra May 22, 2022
14a024f
Add unit test for dirent C API
GauthamBanasandra May 22, 2022
43f5956
Fix unit test failure
GauthamBanasandra May 22, 2022
cc17069
Fix memory leak
GauthamBanasandra May 22, 2022
c6396c2
Throw exception instead of assertion
GauthamBanasandra May 22, 2022
3773c8f
Clear d_name buffer for reuse
GauthamBanasandra May 22, 2022
b75e312
Return absolute paths
GauthamBanasandra May 22, 2022
a8a17c0
Add dirent example
GauthamBanasandra May 26, 2022
d48336b
Remove extern since it's not needed
GauthamBanasandra May 27, 2022
deb38e6
Add USE_X_PLATFORM_DIRENT def
GauthamBanasandra May 28, 2022
c6de53f
Use XPlatform dirent appropriately
GauthamBanasandra May 28, 2022
c1ffa2a
Declare listdir as a project
GauthamBanasandra May 28, 2022
e65788a
Add extern and other fixes
GauthamBanasandra May 29, 2022
3f516f1
Add extern "C" only for Windows
GauthamBanasandra Jun 3, 2022
adaff0c
Remove whitespace
GauthamBanasandra Jun 3, 2022
9785856
Remove const
GauthamBanasandra Jun 3, 2022
09cf9a5
Add documentation
GauthamBanasandra Jun 4, 2022
a39772d
Remove dirent example
GauthamBanasandra Jun 4, 2022
33292fa
Implement non-Windows approach first
GauthamBanasandra Jun 6, 2022
8cc389d
Do not wrap impl with extern "C"
GauthamBanasandra Jun 7, 2022
946251e
Modularize dirent.h header file
GauthamBanasandra Jun 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ add_library(native_mini_dfs
../libhdfs/jni_helper.c
${OS_DIR}/mutexes.c
${OS_DIR}/thread_local_storage.c
$<TARGET_OBJECTS:x_platform_obj>
$<TARGET_OBJECTS:x_platform_obj_c_api>
)

add_executable(test_native_mini_dfs test_native_mini_dfs.c)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ hadoop_add_dual_library(hdfs
jclasses.c
${OS_DIR}/mutexes.c
${OS_DIR}/thread_local_storage.c
$<TARGET_OBJECTS:x_platform_obj>
$<TARGET_OBJECTS:x_platform_obj_c_api>
)
if(NEED_LINK_DL)
set(LIB_DL dl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
#include "platform.h"
#include "os/mutexes.h"
#include "os/thread_local_storage.h"
#include "x-platform/c-api/dirent.h"
#include "x-platform/types.h"

#include <errno.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ else()
set(SYSCALL_SRC syscall_linux.cc)
endif()

add_library(x_platform_obj OBJECT ${SYSCALL_SRC} utils.cc)
add_library(x_platform_obj_c_api OBJECT $<TARGET_OBJECTS:x_platform_obj> c-api/syscall.cc)
add_library(x_platform_obj OBJECT ${SYSCALL_SRC} utils.cc dirent.cc)
add_library(x_platform_obj_c_api OBJECT $<TARGET_OBJECTS:x_platform_obj> c-api/syscall.cc c-api/dirent.cc)
target_compile_definitions(x_platform_obj_c_api PRIVATE USE_X_PLATFORM_DIRENT)
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <algorithm>
#include <cerrno>
#include <iostream>
#include <iterator>
#include <system_error>
#include <variant>

#include "x-platform/c-api/dirent.h"
#include "x-platform/dirent.h"

#if defined(WIN32) && defined(__cplusplus)
extern "C" {
#endif

DIR *opendir(const char *dir_path) {
const auto dir = new DIR;
dir->x_platform_dirent_ptr = new XPlatform::Dirent(dir_path);
return dir;
}

struct dirent *readdir(DIR *dir) {
/*
* We will use a static variable to hold the dirent, so that we align with the
* readdir's implementation in dirent.h header file in Linux.
*/
static struct dirent static_dir_entry;

// Get the XPlatform::Dirent instance and move the iterator.
const auto x_platform_dirent =
static_cast<XPlatform::Dirent *>(dir->x_platform_dirent_ptr);
const auto dir_entry = x_platform_dirent->NextFile();

// End of iteration.
if (std::holds_alternative<std::monostate>(dir_entry)) {
return nullptr;
}

// Error in iteration.
if (std::holds_alternative<std::error_code>(dir_entry)) {
const auto err = std::get<std::error_code>(dir_entry);
errno = err.value();

#ifdef X_PLATFORM_C_API_DIRENT_DEBUG
std::cerr << "Error in listing directory: " << err.message() << std::endl;
#endif

return nullptr;
}

// Return the current child file/folder's name.
if (std::holds_alternative<std::filesystem::directory_entry>(dir_entry)) {
const auto entry = std::get<std::filesystem::directory_entry>(dir_entry);
const auto filename = entry.path().filename().string();

// The file name's length shouldn't exceed 256.
if (filename.length() >= 256) {
errno = 1;
return nullptr;
}

std::fill(std::begin(static_dir_entry.d_name),
std::end(static_dir_entry.d_name), '\0');
std::copy(filename.begin(), filename.end(),
std::begin(static_dir_entry.d_name));
}
return &static_dir_entry;
}

int closedir(DIR *dir) {
const auto x_platform_dirent =
static_cast<XPlatform::Dirent *>(dir->x_platform_dirent_ptr);
delete x_platform_dirent;
delete dir;

// We can't use the void return type for closedir since we want to align the
// closedir method's signature in dirent.h header file in Linux.
return 0;
}

#if defined(WIN32) && defined(__cplusplus)
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

#ifndef NATIVE_LIBHDFSPP_LIB_CROSS_PLATFORM_C_API_DIRENT_H
#define NATIVE_LIBHDFSPP_LIB_CROSS_PLATFORM_C_API_DIRENT_H

/*
* We will use XPlatform's dirent on Windows or when the macro
* USE_X_PLATFORM_DIRENT is defined.
*/
#if defined(WIN32) || defined(USE_X_PLATFORM_DIRENT)

/*
* We will use extern "C" only on Windows.
*/
#if defined(WIN32) && defined(__cplusplus)
extern "C" {
#endif

/**
* DIR struct holds the pointer to XPlatform::Dirent instance. Since this will
* be used in C, we can't hold the pointer to XPlatform::Dirent. We're working
* around this by using a void pointer and casting it to XPlatform::Dirent when
* needed in C++.
*/
typedef struct DIR {
void *x_platform_dirent_ptr;
} DIR;

/**
* dirent struct contains the name of the file/folder while iterating through
* the directory's children.
*/
struct dirent {
char d_name[256];
};

/**
* Opens a directory for iteration. Internally, it instantiates DIR struct for
* the given path. closedir must be called on the returned pointer to DIR struct
* when done.
*
* @param dir_path The path to the directory to iterate through.
* @return A pointer to the DIR struct.
*/
DIR *opendir(const char *dir_path);

/**
* For iterating through the children of the directory pointed to by the DIR
* struct pointer.
*
* @param dir The pointer to the DIR struct.
* @return A pointer to dirent struct containing the name of the current child
* file/folder.
*/
struct dirent *readdir(DIR *dir);

/**
* De-allocates the XPlatform::Dirent instance pointed to by the DIR pointer.
*
* @param dir The pointer to DIR struct to close.
* @return 0 if successful.
*/
int closedir(DIR *dir);

#if defined(WIN32) && defined(__cplusplus)
}
#endif

#else
/*
* For non-Windows environments, we use the dirent.h header itself.
*/
#include <dirent.h>

#endif

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <filesystem>
#include <system_error>
#include <variant>

#include "dirent.h"

std::variant<std::monostate, std::filesystem::directory_entry, std::error_code>
XPlatform::Dirent::NextFile() {
if (dir_it_err_) {
return dir_it_err_;
}

if (dir_it_ == std::filesystem::end(dir_it_)) {
return std::monostate();
}

const std::filesystem::directory_entry dir_entry = *dir_it_;
dir_it_ = dir_it_.increment(dir_it_err_);
return dir_entry;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

#ifndef NATIVE_LIBHDFSPP_LIB_CROSS_PLATFORM_DIRENT
#define NATIVE_LIBHDFSPP_LIB_CROSS_PLATFORM_DIRENT

#include <filesystem>
#include <string>
#include <system_error>
#include <variant>

namespace XPlatform {
/**
* {@class XPlatform::Dirent} provides the functionality to perform a one-time
* iteration per {@link XPlatform::Dirent} through the child files or folders
* under a given path.
*/
class Dirent {
public:
Dirent(const std::string &path)
: dir_it_{std::filesystem::path{path}, dir_it_err_} {}

// Abiding to the Rule of 5
Dirent(const Dirent &) = default;
Dirent(Dirent &&) = default;
Dirent &operator=(const Dirent &) = default;
Dirent &operator=(Dirent &&) = default;
~Dirent() = default;

/**
* Advances the iterator {@link XPlatform::Dirent#dir_it_} to the next file in
* the given path.
*
* @return An {@link std::variant} comprising of any one of the following
* types:
* 1. {@link std::monostate} which indicates the end of iteration of all the
* files in the given path.
* 2. {@link std::filesystem::directory_entry} which is the directory entry of
* the current file.
* 3. {@link std::error_code} which corresponds to the error in retrieving the
* file.
*/
std::variant<std::monostate, std::filesystem::directory_entry,
std::error_code>
NextFile();

private:
/**
* Indicates the error corresponding to the most recent invocation of
* directory iteration by {@link XPlatform::Dirent#dir_it_}.
*/
std::error_code dir_it_err_{};

/**
* The iterator used for iterating through the files or folders under the
* given path.
*/
std::filesystem::directory_iterator dir_it_;
};
} // namespace XPlatform

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,15 @@ add_executable(x_platform_types_test types_test.cc)
target_include_directories(x_platform_types_test PRIVATE ${LIBHDFSPP_LIB_DIR})
target_link_libraries(x_platform_types_test gtest_main)
add_test(x_platform_types_test x_platform_types_test)

add_library(x_platform_dirent_test_obj OBJECT $<TARGET_OBJECTS:x_platform_obj> dirent_test.cc)
add_executable(x_platform_dirent_test $<TARGET_OBJECTS:x_platform_dirent_test_obj> $<TARGET_OBJECTS:x_platform_obj>)
target_include_directories(x_platform_dirent_test PRIVATE ${LIBHDFSPP_LIB_DIR})
target_link_libraries(x_platform_dirent_test PRIVATE gtest_main)
add_test(x_platform_dirent_test x_platform_dirent_test)

add_executable(x_platform_dirent_c_test $<TARGET_OBJECTS:x_platform_dirent_test_obj> $<TARGET_OBJECTS:x_platform_obj> $<TARGET_OBJECTS:x_platform_obj_c_api> c-api/dirent_test.cc)
target_compile_definitions(x_platform_dirent_c_test PRIVATE USE_X_PLATFORM_DIRENT)
target_include_directories(x_platform_dirent_c_test PRIVATE ${LIBHDFSPP_LIB_DIR} ../)
target_link_libraries(x_platform_dirent_c_test PRIVATE gtest_main)
add_test(x_platform_dirent_c_test x_platform_dirent_c_test)
Loading