--- a/src/eric7/RemoteServer/EricServerFileSystemRequestHandler.py Fri Feb 02 14:55:14 2024 +0100 +++ b/src/eric7/RemoteServer/EricServerFileSystemRequestHandler.py Mon Feb 05 11:15:47 2024 +0100 @@ -7,6 +7,8 @@ Module implementing the file system request handler of the eric-ide server. """ +import base64 +import contextlib import os import stat import time @@ -35,6 +37,12 @@ "Rmdir": self.__rmdir, "Replace": self.__replace, "Remove": self.__remove, + "Stat": self.__stat, + "Exists": self.__exists, + "Access": self.__access, + + "ReadFile": self.__readFile, + "WriteFile": self.__writeFile, } def handleRequest(self, request, params, reqestUuid): @@ -131,6 +139,60 @@ "separator": os.sep, } + def __stat(self, params): + """ + Private method to get the status of a file. + + @param params dictionary containing the request data + @type dict + @return dictionary containing the reply data + @rtype dict + """ + filename = params["filename"] + statItems = params["st_names"] + + try: + result = os.stat(filename) + resultDict = {st: getattr(result, st) for st in statItems} + return {"ok": True, "result": resultDict} + except OSError as err: + return { + "ok": False, + "error": str(err), + } + + def __exists(self, params): + """ + Private method to check if a file or directory of the given name exists. + + @param params dictionary containing the request data + @type dict + @return dictionary containing the reply data + @rtype dict + """ + return {"exists": os.path.exists(params["name"])} + + def __access(self, params): + """ + Private method to test, if the eric-ide server has the given access rights + to a file or directory.. + + @param params dictionary containing the request data + @type dict + @return dictionary containing the reply data + @rtype dict + """ + mode = os.F_OK + for modeStr in params["modes"]: + if modeStr == "read": + mode |= os.R_OK + elif modeStr == "write": + mode |= os.W_OK + elif modeStr == "execute": + mode |= os.X_OK + + return {"ok": os.access(params["name"], mode)} + def __mkdir(self, params): """ Private method to create a new directory. @@ -195,7 +257,7 @@ def __remove(self, params): """ - Private method to delete a directory. + Private method to delete a file. @param params dictionary containing the request data @type dict @@ -212,3 +274,72 @@ "ok": False, "error": str(err), } + + def __readFile(self, params): + """ + Private method to read the contents of a file. + + @param params dictionary containing the request data + @type dict + @return dictionary containing the reply data + @rtype dict + """ + filename = params["filename"] + + if params["create"] and not os.path.exists(filename): + with open(filename, "wb"): + pass + + try: + with open(filename, "rb") as f: + data = f.read() + return { + "ok": True, + "filedata": str(base64.b85encode(data), encoding="ascii") + } + except OSError as err: + return { + "ok": False, + "error": str(err), + } + + def __writeFile(self, params): + """ + Private method to write data into a file. + + @param params dictionary containing the request data + @type dict + @return dictionary containing the reply data + @rtype dict + """ + filename = params["filename"] + data = base64.b85decode(bytes(params["filedata"], encoding="ascii")) + + # 1. create backup file if asked for + if params["with_backup"]: + if os.path.islink(filename): + filename = os.path.realpath(filename) + backupFilename = "{0}~".format(filename) + try: + permissions = os.stat(filename).st_mode + perms_valid = True + except OSError: + # if there was an error, ignore it + perms_valid = False + with contextlib.suppress(OSError): + os.remove(backupFilename) + with contextlib.suppress(OSError): + os.rename(filename, backupFilename) + + # 2. write the data to the file and reset the permissions + try: + with open(filename, "wb") as f: + f.write(data) + if params["with_backup"] and perms_valid: + os.chmod(filename, permissions) + return {"ok": True} + except OSError as err: + return { + "ok": False, + "error": str(err), + }