gulrak / filesystem

An implementation of C++17 std::filesystem for C++11 /C++14/C++17/C++20 on Windows, macOS, Linux and FreeBSD.
MIT License
1.31k stars 168 forks source link

Support QNX platform. #116

Closed thun-res closed 3 years ago

thun-res commented 3 years ago

platform: qnx700, aarch64, c++11 support (POSIX support)

"Operating system currently not supported!" And It looks like the 'struct dirent' has no 'd_type' I try to modify:

filesystem.hpp:

...
#elif defined(__QNX__)
#define GHC_OS_QNX
#else
#error "Operating system currently not supported!"
#endif
...
...
      void copyToDirEntry()
        {
            _dir_entry._symlink_status.permissions(perms::unknown);
#ifdef GHC_OS_QNX
            _dir_entry._status.type(file_type::none);
            _dir_entry._status.permissions(perms::unknown);
            _dir_entry._symlink_status.type(file_type::unknown);
#else
            switch (_entry->d_type) {
            case DT_BLK:
                _dir_entry._symlink_status.type(file_type::block);
                break;
            case DT_CHR:
                _dir_entry._symlink_status.type(file_type::character);
                break;
            case DT_DIR:
                _dir_entry._symlink_status.type(file_type::directory);
                break;
            case DT_FIFO:
                _dir_entry._symlink_status.type(file_type::fifo);
                break;
            case DT_LNK:
                _dir_entry._symlink_status.type(file_type::symlink);
                break;
            case DT_REG:
                _dir_entry._symlink_status.type(file_type::regular);
                break;
            case DT_SOCK:
                _dir_entry._symlink_status.type(file_type::socket);
                break;
            default:
                _dir_entry._symlink_status.type(file_type::unknown);
                break;
            }
            if (_entry->d_type != DT_LNK) {
                _dir_entry._status = _dir_entry._symlink_status;
            } else {
                _dir_entry._status.type(file_type::none);
                _dir_entry._status.permissions(perms::unknown);
            }
#endif
            _dir_entry._file_size = static_cast<uintmax_t>(-1);
            _dir_entry._hard_link_count = static_cast<uintmax_t>(-1);
            _dir_entry._last_write_time = 0;
        }
...

I don’t know if the changes are correct, but the compilation passed.

thanks.

gulrak commented 3 years ago

Thank you! That looks like it should work, I'll look into it.

thun-res commented 3 years ago

I tested it briefly and found it crashed(when I create dir it throw)...

gulrak commented 3 years ago

Sadly, contrary to what I expected, I couldn't get access to a QNX installation and didn't want do register and apply for a 30 days evaluation, as that wouldn't allow me to further support it after 30 days, so I currently have no way to check it myself.

thun-res commented 3 years ago

Thanks for trying my suggestion, I have solved it now.

...
#define GHC_OS_WEB
#include <wasi/api.h>
#elif defined(__QNX__)
#define GHC_OS_QNX
#else
#error "Operating system currently not supported!"
#endif
...
...
        void copyToDirEntry()
        {
            _dir_entry._symlink_status.permissions(perms::unknown);
#ifdef GHC_OS_QNX
            struct stat buffer;
            int reval = ::stat(_dir_entry._path.c_str(), &buffer);
            if (reval == 0) {
                if (S_ISDIR(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::directory);
                } else if (S_ISREG(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::regular);
                } else if (S_ISLNK(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::symlink);
                } else if (S_ISCHR(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::character);
                } else if (S_ISFIFO(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::fifo);
                } else if (S_ISBLK(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::block);
                } else if (S_ISSOCK(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::socket);
                } else {
                    _dir_entry._symlink_status.type(file_type::unknown);
                }
                _dir_entry._status = _dir_entry._symlink_status;
            } else {
                _dir_entry._status.type(file_type::none);
                _dir_entry._symlink_status.type(file_type::unknown);
            }
#else
            switch (_entry->d_type) {
            case DT_BLK:
                _dir_entry._symlink_status.type(file_type::block);
                break;
            case DT_CHR:
                _dir_entry._symlink_status.type(file_type::character);
                break;
            case DT_DIR:
                _dir_entry._symlink_status.type(file_type::directory);
                break;
            case DT_FIFO:
                _dir_entry._symlink_status.type(file_type::fifo);
                break;
            case DT_LNK:
                _dir_entry._symlink_status.type(file_type::symlink);
                break;
            case DT_REG:
                _dir_entry._symlink_status.type(file_type::regular);
                break;
            case DT_SOCK:
                _dir_entry._symlink_status.type(file_type::socket);
                break;
            default:
                _dir_entry._symlink_status.type(file_type::unknown);
                break;
            }
            if (_entry->d_type != DT_LNK) {
                _dir_entry._status = _dir_entry._symlink_status;
            } else {
                _dir_entry._status.type(file_type::none);
                _dir_entry._status.permissions(perms::unknown);
            }
#endif
            _dir_entry._file_size = static_cast<uintmax_t>(-1);
            _dir_entry._hard_link_count = static_cast<uintmax_t>(-1);
            _dir_entry._last_write_time = 0;
        }
        path _base;
        directory_options _options;
        DIR* _dir;
        struct ::dirent* _entry;
        directory_entry _dir_entry;
        std::error_code _ec;
    };
...

I have tested and it works, you can add this.

thun-res commented 3 years ago
#ifdef GHC_OS_QNX
            struct stat buffer;
            int reval = ::stat(_dir_entry._path.c_str(), &buffer);
            bool is_link = false;
            if (reval == 0) {
                if (S_ISDIR(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::directory);
                } else if (S_ISREG(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::regular);
                } else if (S_ISLNK(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::symlink);
                    is_link = true;
                } else if (S_ISCHR(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::character);
                } else if (S_ISFIFO(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::fifo);
                } else if (S_ISBLK(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::block);
                } else if (S_ISSOCK(buffer.st_mode)) {
                    _dir_entry._symlink_status.type(file_type::socket);
                } else {
                    _dir_entry._symlink_status.type(file_type::unknown);
                }
                if (is_link) {
                    _dir_entry._status.type(file_type::none);
                    _dir_entry._status.permissions(perms::unknown);
                } else {
                    _dir_entry._status = _dir_entry._symlink_status;
                }
            } else {
                _dir_entry._status.type(file_type::unknown);
                _dir_entry._symlink_status.type(file_type::unknown);
                _dir_entry._status.permissions(perms::unknown);
            }
#else
            switch (_entry->d_type) {
            case DT_BLK:
                _dir_entry._symlink_status.type(file_type::block);
                break;
            case DT_CHR:
                _dir_entry._symlink_status.type(file_type::character);
                break;
            case DT_DIR:
                _dir_entry._symlink_status.type(file_type::directory);
                break;
            case DT_FIFO:
                _dir_entry._symlink_status.type(file_type::fifo);
                break;
            case DT_LNK:
                _dir_entry._symlink_status.type(file_type::symlink);
                break;
            case DT_REG:
                _dir_entry._symlink_status.type(file_type::regular);
                break;
            case DT_SOCK:
                _dir_entry._symlink_status.type(file_type::socket);
                break;
            default:
                _dir_entry._symlink_status.type(file_type::unknown);
                break;
            }
            if (_entry->d_type != DT_LNK) {
                _dir_entry._status = _dir_entry._symlink_status;
            } else {
                _dir_entry._status.type(file_type::none);
                _dir_entry._status.permissions(perms::unknown);
            }
#endif
gulrak commented 3 years ago

Sorry for the delay! The reason I didn't simply use your solution was, that I wanted the way to support systems without dirent.d_type the same way as filesystems reporting DT_UNKNOWN as type and I had thought my default: would be handling those correctly but it didn't. As I couldn't test myself I postponed work on it a bit.

I used a macro to select no-d_type support to allow easier integration for other systems that might need it.

gulrak commented 3 years ago

This is now part of release v1.5.6

district10 commented 3 years ago

platform: qnx700, aarch64, c++14 support (POSIX support)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14")
set(CMAKE_CXX_EXTENSIONS ON)

Got error:

// using the most recent ghc_filesystem/1.5.6
filesystem.hpp:178:22: fatal error: langinfo.h: No such file or directory
district10 commented 2 years ago

2021/09/04: works totally fine on QNX. :cry: Sorry for the disruption.

GarfiledXu commented 10 months ago

latest version, compiled on android arm-64 pass complied on qnx 700 arm fail! complie output: inc/include/ghc/filesystem.hpp:164:22: fatal error: langinfo.h: No such file or directory i can't find this header : laninfo.h if i try to note this include, will ouput error info: /ghc/filesystem.hpp:2467:43: error: '::nl_langinfo' has not been declared _simple_insensitive(::nl_langin

facontidavide commented 9 months ago

Similar problem with QNX 7.1.0 (x86_64):

/home/davide/qnx710/host/linux/x86_64/usr/bin/x86_64-pc-nto-qnx7.1.0-ld: CMakeFiles/fs_dir.dir/dir.cpp.o: in function `ghc::filesystem::u8arguments::u8arguments(int&, char**&)':
dir.cpp:(.text._ZN3ghc10filesystem11u8argumentsC2ERiRPPc[_ZN3ghc10filesystem11u8argumentsC5ERiRPPc]+0x66): undefined reference to `nl_langinfo(int)'
collect2: error: ld returned 1 exit status
examples/CMakeFiles/fs_dir.dir/build.make:96: recipe for target 'examples/fs_dir' failed
gulrak commented 9 months ago

This is better kept at #169 as comments at an old issue get lost fast, but as written there, I need help or PRs to fix that.

There is no free QNX dev environment to test and debug this myself, at least I couldn't find a legal one, and I'm not willing to buy a license I don't need for myself, so QNX support sadly is not an official feature but one backed by help of others, I can't check it by CI and I can't do it myself.

district10 commented 9 months ago

I worked on QNX years ago (and ghc_filesystem worked). This patch may be useful: https://gist.github.com/district10/9937754bdcdd5321a56430f491088de9

Specially, add these to your CMakeLists.txt may resolve your problem: (I still have no idea why. It's tricky.)

add_definitions(-D_QNX_SOURCE)
add_definitions(-D_XOPEN_SOURCE=500)

Or this:

if (CMAKE_SYSTEM_NAME STREQUAL "QNX")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++")
    set(CMAKE_CXX_EXTENSIONS ON)
endif()

You may read -stdlib=XXX, -std=xxx here: https://www.qnx.com/developers/docs/7.0.0/#com.qnx.doc.neutrino.utilities/topic/q/qcc.html