From 4cfeb32aa836bc315aa74cf5fb38e0330407f79d Mon Sep 17 00:00:00 2001 From: Uwe Seimet <Uwe.Seimet@seimet.de> Date: Wed, 15 Sep 2021 17:35:48 +0200 Subject: [PATCH] Added support for copying image files --- src/raspberrypi/rascsi.cpp | 63 +++++++++++++++++++++++++- src/raspberrypi/rascsi_interface.proto | 7 ++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/raspberrypi/rascsi.cpp b/src/raspberrypi/rascsi.cpp index 1a5bd334..f7a41189 100644 --- a/src/raspberrypi/rascsi.cpp +++ b/src/raspberrypi/rascsi.cpp @@ -31,6 +31,7 @@ #include "spdlog/spdlog.h" #include "spdlog/sinks/stdout_color_sinks.h" #include <spdlog/async.h> +#include <sys/sendfile.h> #include <string> #include <sstream> #include <iostream> @@ -811,11 +812,11 @@ bool RenameImage(int fd, const PbCommand& command) string src = command.params().Get(0); if (src.find('/') != string::npos) { - return ReturnStatus(fd, false, "The image filename '" + src + "' must not contain a path"); + return ReturnStatus(fd, false, "The current filename '" + src + "' must not contain a path"); } string dst = command.params().Get(1); if (dst.find('/') != string::npos) { - return ReturnStatus(fd, false, "The image filename '" + dst + "' must not contain a path"); + return ReturnStatus(fd, false, "The new filename '" + dst + "' must not contain a path"); } src = default_image_folder + "/" + src; @@ -835,6 +836,61 @@ bool RenameImage(int fd, const PbCommand& command) return ReturnStatus(fd); } +bool CopyImage(int fd, const PbCommand& command) +{ + if (command.params().size() < 2 || command.params().Get(0).empty() || command.params().Get(1).empty()) { + return ReturnStatus(fd, false, "Can't copy image file: Missing filename"); + } + + string src = command.params().Get(0); + if (src.find('/') != string::npos) { + return ReturnStatus(fd, false, "The current filename '" + src + "' must not contain a path"); + } + string dst = command.params().Get(1); + if (dst.find('/') != string::npos) { + return ReturnStatus(fd, false, "The new filename '" + dst + "' must not contain a path"); + } + + src = default_image_folder + "/" + src; + dst = default_image_folder + "/" + dst; + + struct stat st; + if (!stat(dst.c_str(), &st)) { + return ReturnStatus(fd, false, "Image file '" + dst + "' already exists"); + } + + int fd_src = open(src.c_str(), O_RDONLY, 0); + if (fd_src == -1) { + return ReturnStatus(fd, false, "Can't open source image file '" + src + "': " + string(strerror(errno))); + } + + struct stat st_src; + if (fstat(fd_src, &st_src) == -1) { + return ReturnStatus(fd, false, "Can't read source image file '" + src + "': " + string(strerror(errno))); + } + + int fd_dst = open(dst.c_str(), O_WRONLY | O_CREAT, st_src.st_mode); + if (fd_dst == -1) { + close (fd_dst); + + return ReturnStatus(fd, false, "Can't open destination image file '" + dst + "': " + string(strerror(errno))); + } + + if (sendfile(fd_dst, fd_src, 0, st_src.st_size) == -1) { + close(fd_dst); + close(fd_src); + + return ReturnStatus(fd, false, "Can't copy image file '" + src + "' to '" + dst + "': " + string(strerror(errno))); + } + + close(fd_dst); + close(fd_src); + + LOGINFO("%s", string("Copied image file '" + src + "' to '" + dst + "'").c_str()); + + return ReturnStatus(fd); +} + void DetachAll() { Device *map[devices.size()]; @@ -1293,6 +1349,9 @@ bool ProcessCmd(const int fd, const PbCommand& command) case RENAME_IMAGE: return RenameImage(fd, command); + case COPY_IMAGE: + return CopyImage(fd, command); + default: // This is a device-specific command handled below break; diff --git a/src/raspberrypi/rascsi_interface.proto b/src/raspberrypi/rascsi_interface.proto index 6aa23a82..4b16e92b 100644 --- a/src/raspberrypi/rascsi_interface.proto +++ b/src/raspberrypi/rascsi_interface.proto @@ -68,9 +68,12 @@ enum PbOperation { // Delete an image file. PbCommand.params(0) contains the filename. // The filename is relative to the default image folder and must not contain a slash. DELETE_IMAGE = 16; - // Rename an image file. PbCommand.params(0) contains the old filename, PbCommand.params(1) the new name. - // The filename is relative to the default image folder and must not contain a slash. + // Rename an image file. PbCommand.params(0) contains the current filename, PbCommand.params(1) the new name. + // The filenames are relative to the default image folder and must not contain a slash. RENAME_IMAGE = 17; + // Copy an image file. PbCommand.params(0) contains the source filename, PbCommand.params(1) the destination name. + // The filenames are relative to the default image folder and must not contain a slash. + COPY_IMAGE = 18; } // The properties supported by a device