diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h index be960fbc2542..24b40cbce827 100644 --- a/core/io/file_access_buffered_fa.h +++ b/core/io/file_access_buffered_fa.h @@ -143,6 +143,14 @@ public: return f._get_modified_time(p_file); } + virtual uint32_t _get_unix_permissions(const String &p_file) { + return f._get_unix_permissions(p_file); + } + + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { + return f._set_unix_permissions(p_file, p_permissions); + } + FileAccessBufferedFA(){ }; diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index b268d5c710ab..6c4310a5729c 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -373,6 +373,19 @@ uint64_t FileAccessCompressed::_get_modified_time(const String &p_file) { return 0; } +uint32_t FileAccessCompressed::_get_unix_permissions(const String &p_file) { + if (f) + return f->_get_unix_permissions(p_file); + return 0; +} + +Error FileAccessCompressed::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + if (f) { + return f->_set_unix_permissions(p_file, p_permissions); + } + return FAILED; +} + FileAccessCompressed::FileAccessCompressed() : cmode(Compression::MODE_ZSTD), writing(false), diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index f408b1bc29d2..773fed6a3a43 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -91,6 +91,8 @@ public: virtual bool file_exists(const String &p_name); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file); + virtual uint32_t _get_unix_permissions(const String &p_file); + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); FileAccessCompressed(); virtual ~FileAccessCompressed(); diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index 6ad68dd74d90..3cf690896154 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -301,6 +301,16 @@ uint64_t FileAccessEncrypted::_get_modified_time(const String &p_file) { return 0; } +uint32_t FileAccessEncrypted::_get_unix_permissions(const String &p_file) { + + return 0; +} + +Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + + return FAILED; +} + FileAccessEncrypted::FileAccessEncrypted() { file = NULL; diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index e77d62a9f4dd..d779a150ac88 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -79,6 +79,8 @@ public: virtual bool file_exists(const String &p_name); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file); + virtual uint32_t _get_unix_permissions(const String &p_file); + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); FileAccessEncrypted(); ~FileAccessEncrypted(); diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index 73952133c112..4db7811aaaee 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -70,6 +70,8 @@ public: virtual bool file_exists(const String &p_name); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file) { return 0; } + virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } FileAccessMemory(); }; diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 501a21a50dde..722e62c54ee4 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -497,6 +497,16 @@ uint64_t FileAccessNetwork::_get_modified_time(const String &p_file) { return exists_modtime; } +uint32_t FileAccessNetwork::_get_unix_permissions(const String &p_file) { + //could be implemented, not sure if worth it + return 0; +} + +Error FileAccessNetwork::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + + return FAILED; +} + void FileAccessNetwork::configure() { GLOBAL_DEF("network/remote_fs/page_size", 65536); diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h index 5bbf7588c747..073b75a37b8d 100644 --- a/core/io/file_access_network.h +++ b/core/io/file_access_network.h @@ -159,6 +159,8 @@ public: virtual bool file_exists(const String &p_path); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file); + virtual uint32_t _get_unix_permissions(const String &p_file); + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); static void configure(); diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index a90672ce2636..a21dd7d22d92 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -142,6 +142,8 @@ class FileAccessPack : public FileAccess { FileAccess *f; virtual Error _open(const String &p_path, int p_mode_flags); virtual uint64_t _get_modified_time(const String &p_file) { return 0; } + virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } public: virtual void close(); diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index fc8f85c07ba9..217176c0aff5 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -112,6 +112,8 @@ public: virtual bool file_exists(const String &p_name); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file) { return 0; } // todo + virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } FileAccessZip(const String &p_path, const PackedData::PackedFile &p_file); ~FileAccessZip(); diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index 2c1c655175b3..d81c30f33a28 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -330,7 +330,7 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { if (err == OK && p_chmod_flags != -1) { fdst->close(); - err = fdst->_chmod(p_to, p_chmod_flags); + err = FileAccess::set_unix_permissions(p_to, p_chmod_flags); // If running on a platform with no chmod support (i.e., Windows), don't fail if (err == ERR_UNAVAILABLE) err = OK; diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index 4be136427842..079f51bada21 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -507,6 +507,29 @@ uint64_t FileAccess::get_modified_time(const String &p_file) { return mt; } +uint32_t FileAccess::get_unix_permissions(const String &p_file) { + + if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && PackedData::get_singleton()->has_path(p_file)) + return 0; + + FileAccess *fa = create_for_path(p_file); + ERR_FAIL_COND_V(!fa, 0); + + uint32_t mt = fa->_get_unix_permissions(p_file); + memdelete(fa); + return mt; +} + +Error FileAccess::set_unix_permissions(const String &p_file, uint32_t p_permissions) { + + FileAccess *fa = create_for_path(p_file); + ERR_FAIL_COND_V(!fa, ERR_CANT_CREATE); + + Error err = fa->_set_unix_permissions(p_file, p_permissions); + memdelete(fa); + return err; +} + void FileAccess::store_string(const String &p_string) { if (p_string.length() == 0) diff --git a/core/os/file_access.h b/core/os/file_access.h index 9df2a5cade3c..4930eae35a5f 100644 --- a/core/os/file_access.h +++ b/core/os/file_access.h @@ -56,6 +56,9 @@ public: bool endian_swap; bool real_is_double; + virtual uint32_t _get_unix_permissions(const String &p_file) = 0; + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0; + protected: String fix_path(const String &p_path) const; virtual Error _open(const String &p_path, int p_mode_flags) = 0; ///< open a file @@ -148,14 +151,14 @@ public: virtual Error reopen(const String &p_path, int p_mode_flags); ///< does not change the AccessType - virtual Error _chmod(const String &p_path, int p_mod) { return ERR_UNAVAILABLE; } - static FileAccess *create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files. static FileAccess *create_for_path(const String &p_path); static FileAccess *open(const String &p_path, int p_mode_flags, Error *r_error = NULL); /// Create a file access (for the current platform) this is the only portable way of accessing files. static CreateFunc get_create_func(AccessType p_access); static bool exists(const String &p_name); ///< return true if a file exists static uint64_t get_modified_time(const String &p_file); + static uint32_t get_unix_permissions(const String &p_file); + static Error set_unix_permissions(const String &p_file, uint32_t p_permissions); static void set_backup_save(bool p_enable) { backup_save = p_enable; }; static bool is_backup_save_enabled() { return backup_save; }; diff --git a/core/os/os.h b/core/os/os.h index 12012fba802b..4ae8a354e57e 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -45,6 +45,8 @@ @author Juan Linietsky */ +class Mutex; + class OS { static OS *singleton; @@ -260,7 +262,7 @@ public: virtual int get_low_processor_usage_mode_sleep_usec() const; virtual String get_executable_path() const; - virtual Error execute(const String &p_path, const List &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false) = 0; + virtual Error execute(const String &p_path, const List &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL) = 0; virtual Error kill(const ProcessID &p_pid) = 0; virtual int get_process_id() const; diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 6e045817bc6d..a285b3b65f29 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -293,8 +293,25 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) { }; } -Error FileAccessUnix::_chmod(const String &p_path, int p_mod) { - int err = chmod(p_path.utf8().get_data(), p_mod); +uint32_t FileAccessUnix::_get_unix_permissions(const String &p_file) { + + String file = fix_path(p_file); + struct stat flags; + int err = stat(file.utf8().get_data(), &flags); + + if (!err) { + return flags.st_mode & 0x7FF; //only permissions + } else { + ERR_EXPLAIN("Failed to get unix permissions for: " + p_file); + ERR_FAIL_V(0); + }; +} + +Error FileAccessUnix::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + + String file = fix_path(p_file); + + int err = chmod(file.utf8().get_data(), p_permissions); if (!err) { return OK; } diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 6405589b4d00..2a369048a485 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -85,8 +85,8 @@ public: virtual bool file_exists(const String &p_path); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file); - - virtual Error _chmod(const String &p_path, int p_mod); + virtual uint32_t _get_unix_permissions(const String &p_file); + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); FileAccessUnix(); virtual ~FileAccessUnix(); diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 0d7d56aff43e..25cdc8d8a021 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -276,7 +276,7 @@ uint64_t OS_Unix::get_ticks_usec() const { return longtime; } -Error OS_Unix::execute(const String &p_path, const List &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) { +Error OS_Unix::execute(const String &p_path, const List &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) { #ifdef __EMSCRIPTEN__ // Don't compile this code at all to avoid undefined references. @@ -303,11 +303,17 @@ Error OS_Unix::execute(const String &p_path, const List &p_arguments, bo ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); char buf[65535]; + while (fgets(buf, 65535, f)) { + if (p_pipe_mutex) { + p_pipe_mutex->lock(); + } (*r_pipe) += buf; + if (p_pipe_mutex) { + p_pipe_mutex->unlock(); + } } - int rv = pclose(f); if (r_exitcode) *r_exitcode = rv; @@ -320,6 +326,13 @@ Error OS_Unix::execute(const String &p_path, const List &p_arguments, bo if (pid == 0) { // is child + + if (!p_blocking) { + // For non blocking calls, create a new session-ID so parent won't wait for it. + // This ensures the process won't go zombie at end. + setsid(); + } + Vector cs; cs.push_back(p_path.utf8()); for (int i = 0; i < p_arguments.size(); i++) @@ -342,6 +355,7 @@ Error OS_Unix::execute(const String &p_path, const List &p_arguments, bo waitpid(pid, &status, 0); if (r_exitcode) *r_exitcode = WEXITSTATUS(status); + } else { if (r_child_id) diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 09ab4aa1d812..6a05877a8ce9 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -89,7 +89,7 @@ public: virtual void delay_usec(uint32_t p_usec) const; virtual uint64_t get_ticks_usec() const; - virtual Error execute(const String &p_path, const List &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false); + virtual Error execute(const String &p_path, const List &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL); virtual Error kill(const ProcessID &p_pid); virtual int get_process_id() const; diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index c4c5e0d709f8..c13300d09fb7 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -339,6 +339,16 @@ uint64_t FileAccessWindows::_get_modified_time(const String &p_file) { } } +uint32_t FileAccessWindows::_get_unix_permissions(const String &p_file) { + ERR_PRINT("Windows does not support unix permissions"); + return 0; +} + +Error FileAccessWindows::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + ERR_PRINT("Windows does not support unix permissions"); + return FAILED; +} + FileAccessWindows::FileAccessWindows() : f(NULL), flags(0), diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index 35b1f0b2d86e..2848ed527913 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -80,6 +80,8 @@ public: virtual bool file_exists(const String &p_name); ///< return true if a file exists uint64_t _get_modified_time(const String &p_file); + virtual uint32_t _get_unix_permissions(const String &p_file); + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); FileAccessWindows(); virtual ~FileAccessWindows(); diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index f8d46ea5d2cc..b8e78627ecfa 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -70,6 +70,8 @@ public: virtual bool file_exists(const String &p_path); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file) { return 0; } + virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } //static void make_default(); diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h index 4f02fea81d54..9429100d655b 100644 --- a/platform/android/file_access_jandroid.h +++ b/platform/android/file_access_jandroid.h @@ -74,6 +74,8 @@ public: static void setup(jobject p_io); virtual uint64_t _get_modified_time(const String &p_file) { return 0; } + virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } FileAccessJAndroid(); ~FileAccessJAndroid(); diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 5e94bc457b94..1a63d6ff75e9 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -568,7 +568,7 @@ Error EditorExportPlatformOSX::export_project(const Ref &p_p f->close(); if (is_execute) { // Chmod with 0755 if the file is executable - f->_chmod(file, 0755); + FileAccess::set_unix_permissions(file, 0755); } memdelete(f); } else {