Browse Source

Add symlink API to the DirAccess (on macOS and Linux).

bruvzg 4 years ago
parent
commit
6aa8f7d85b

+ 4 - 0
core/io/file_access_pack.h

@@ -235,6 +235,10 @@ public:
 	virtual Error rename(String p_from, String p_to);
 	virtual Error remove(String p_name);
 
+	virtual bool is_link(String p_file) { return false; }
+	virtual String read_link(String p_file) { return p_file; }
+	virtual Error create_link(String p_source, String p_target) { return FAILED; }
+
 	uint64_t get_space_left();
 
 	virtual String get_filesystem_type() const;

+ 7 - 5
core/os/dir_access.cpp

@@ -334,7 +334,7 @@ public:
 	}
 };
 
-Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags) {
+Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links) {
 	List<String> dirs;
 
 	String curdir = get_current_dir();
@@ -342,7 +342,9 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag
 	String n = get_next();
 	while (n != String()) {
 		if (n != "." && n != "..") {
-			if (current_is_dir()) {
+			if (p_copy_links && is_link(get_current_dir().plus_file(n))) {
+				create_link(read_link(get_current_dir().plus_file(n)), p_to + n);
+			} else if (current_is_dir()) {
 				dirs.push_back(n);
 			} else {
 				const String &rel_path = n;
@@ -374,7 +376,7 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag
 		Error err = change_dir(E->get());
 		ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot change current directory to '" + E->get() + "'.");
 
-		err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags);
+		err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags, p_copy_links);
 		if (err) {
 			change_dir("..");
 			ERR_FAIL_V_MSG(err, "Failed to copy recursively.");
@@ -386,7 +388,7 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag
 	return OK;
 }
 
-Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags) {
+Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags, bool p_copy_links) {
 	ERR_FAIL_COND_V_MSG(!dir_exists(p_from), ERR_FILE_NOT_FOUND, "Source directory doesn't exist.");
 
 	DirAccess *target_da = DirAccess::create_for_path(p_to);
@@ -405,7 +407,7 @@ Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags) {
 	}
 
 	DirChanger dir_changer(this, p_from);
-	Error err = _copy_dir(target_da, p_to, p_chmod_flags);
+	Error err = _copy_dir(target_da, p_to, p_chmod_flags, p_copy_links);
 	memdelete(target_da);
 
 	return err;

+ 6 - 2
core/os/dir_access.h

@@ -50,7 +50,7 @@ private:
 	AccessType _access_type;
 	static CreateFunc create_func[ACCESS_MAX]; ///< set this to instance a filesystem object
 
-	Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags);
+	Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links);
 
 protected:
 	String _get_root_path() const;
@@ -89,11 +89,15 @@ public:
 	static bool exists(String p_dir);
 	virtual uint64_t get_space_left() = 0;
 
-	Error copy_dir(String p_from, String p_to, int p_chmod_flags = -1);
+	Error copy_dir(String p_from, String p_to, int p_chmod_flags = -1, bool p_copy_links = false);
 	virtual Error copy(String p_from, String p_to, int p_chmod_flags = -1);
 	virtual Error rename(String p_from, String p_to) = 0;
 	virtual Error remove(String p_name) = 0;
 
+	virtual bool is_link(String p_file) = 0;
+	virtual String read_link(String p_file) = 0;
+	virtual Error create_link(String p_source, String p_target) = 0;
+
 	// Meant for editor code when we want to quickly remove a file without custom
 	// handling (e.g. removing a cache file).
 	static void remove_file_or_error(String p_path) {

+ 43 - 0
drivers/unix/dir_access_unix.cpp

@@ -382,6 +382,49 @@ Error DirAccessUnix::remove(String p_path) {
 	}
 }
 
+bool DirAccessUnix::is_link(String p_file) {
+	if (p_file.is_rel_path())
+		p_file = get_current_dir().plus_file(p_file);
+
+	p_file = fix_path(p_file);
+
+	struct stat flags;
+	if ((lstat(p_file.utf8().get_data(), &flags) != 0))
+		return FAILED;
+
+	return S_ISLNK(flags.st_mode);
+}
+
+String DirAccessUnix::read_link(String p_file) {
+	if (p_file.is_rel_path())
+		p_file = get_current_dir().plus_file(p_file);
+
+	p_file = fix_path(p_file);
+
+	char buf[256];
+	memset(buf, 0, 256);
+	ssize_t len = readlink(p_file.utf8().get_data(), buf, sizeof(buf));
+	String link;
+	if (len > 0) {
+		link.parse_utf8(buf, len);
+	}
+	return link;
+}
+
+Error DirAccessUnix::create_link(String p_source, String p_target) {
+	if (p_target.is_rel_path())
+		p_target = get_current_dir().plus_file(p_target);
+
+	p_source = fix_path(p_source);
+	p_target = fix_path(p_target);
+
+	if (symlink(p_source.utf8().get_data(), p_target.utf8().get_data()) == 0) {
+		return OK;
+	} else {
+		return FAILED;
+	}
+}
+
 uint64_t DirAccessUnix::get_space_left() {
 #ifndef NO_STATVFS
 	struct statvfs vfs;

+ 4 - 0
drivers/unix/dir_access_unix.h

@@ -77,6 +77,10 @@ public:
 	virtual Error rename(String p_path, String p_new_path);
 	virtual Error remove(String p_path);
 
+	virtual bool is_link(String p_file);
+	virtual String read_link(String p_file);
+	virtual Error create_link(String p_source, String p_target);
+
 	virtual uint64_t get_space_left();
 
 	virtual String get_filesystem_type() const;

+ 5 - 0
drivers/windows/dir_access_windows.h

@@ -79,6 +79,11 @@ public:
 	virtual Error rename(String p_path, String p_new_path);
 	virtual Error remove(String p_path);
 
+	virtual bool is_link(String p_file) { return false; };
+	virtual String read_link(String p_file) { return p_file; };
+	virtual Error create_link(String p_source, String p_target) { return FAILED; };
+
+	//virtual FileType get_file_type() const;
 	uint64_t get_space_left();
 
 	virtual String get_filesystem_type() const;

+ 4 - 0
platform/android/dir_access_jandroid.h

@@ -74,6 +74,10 @@ public:
 	virtual Error rename(String p_from, String p_to);
 	virtual Error remove(String p_name);
 
+	virtual bool is_link(String p_file) { return false; }
+	virtual String read_link(String p_file) { return p_file; }
+	virtual Error create_link(String p_source, String p_target) { return FAILED; }
+
 	virtual String get_filesystem_type() const;
 
 	uint64_t get_space_left();