Browse Source

FTP: Add truncate command.

Unfortunately NuttX not provides truncate(),
had to be emulated by copying with O_TRUNC flag.
sbg
Vladimir Ermakov 11 years ago
parent
commit
f55d20a133
  1. 126
      src/modules/mavlink/mavlink_ftp.cpp
  2. 3
      src/modules/mavlink/mavlink_ftp.h

126
src/modules/mavlink/mavlink_ftp.cpp

@ -204,6 +204,10 @@ MavlinkFTP::_process_request(Request *req) @@ -204,6 +204,10 @@ MavlinkFTP::_process_request(Request *req)
errorCode = _workRemoveFile(payload);
break;
case kCmdTruncateFile:
errorCode = _workTruncateFile(payload);
break;
case kCmdCreateDirectory:
errorCode = _workCreateDirectory(payload);
break;
@ -517,6 +521,82 @@ MavlinkFTP::_workRemoveFile(PayloadHeader* payload) @@ -517,6 +521,82 @@ MavlinkFTP::_workRemoveFile(PayloadHeader* payload)
}
}
/// @brief Responds to a TruncateFile command
MavlinkFTP::ErrorCode
MavlinkFTP::_workTruncateFile(PayloadHeader* payload)
{
char file[kMaxDataLength];
const char temp_file[] = "/fs/microsd/.trunc.tmp";
strncpy(file, _data_as_cstring(payload), kMaxDataLength);
payload->size = 0;
// emulate truncate(file, payload->offset) by
// copying to temp and overwrite with O_TRUNC flag.
struct stat st;
if (stat(file, &st) != 0) {
return kErrFailErrno;
}
if (!S_ISREG(st.st_mode)) {
errno = EISDIR;
return kErrFailErrno;
}
// check perms allow us to write (not romfs)
int mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
if (!(mode & ~(S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH))) {
errno = EROFS;
return kErrFailErrno;
}
if (payload->offset == st.st_size) {
// nothing to do
return kErrNone;
}
else if (payload->offset == 0) {
// 1: truncate all data
int fd = ::open(file, O_TRUNC | O_WRONLY);
if (fd < 0) {
return kErrFailErrno;
}
::close(fd);
return kErrNone;
}
else if (payload->offset > st.st_size) {
// 2: extend file
int fd = ::open(file, O_WRONLY);
if (fd < 0) {
return kErrFailErrno;
}
if (lseek(fd, payload->offset - 1, SEEK_SET) != 0) {
::close(fd);
return kErrFailErrno;
}
bool ok = 1 == ::write(fd, "", 1);
::close(fd);
return (ok)? kErrNone : kErrFailErrno;
}
else {
// 3: truncate
if (_copy_file(file, temp_file, payload->offset) != 0) {
return kErrFailErrno;
}
if (_copy_file(temp_file, file, payload->offset) != 0) {
return kErrFailErrno;
}
if (::unlink(temp_file) != 0) {
return kErrFailErrno;
}
return kErrNone;
}
}
/// @brief Responds to a Terminate command
MavlinkFTP::ErrorCode
MavlinkFTP::_workTerminate(PayloadHeader* payload)
@ -652,3 +732,49 @@ MavlinkFTP::_return_request(Request *req) @@ -652,3 +732,49 @@ MavlinkFTP::_return_request(Request *req)
_unlock_request_queue();
}
/// @brief Copy file (with limited space)
int
MavlinkFTP::_copy_file(const char *src_path, const char *dst_path, ssize_t length)
{
char buff[512];
int src_fd = -1, dst_fd = -1;
src_fd = ::open(src_path, O_RDONLY);
if (src_fd < 0) {
return -1;
}
dst_fd = ::open(dst_path, O_CREAT | O_TRUNC | O_WRONLY);
if (dst_fd < 0) {
::close(src_fd);
return -1;
}
while (length > 0) {
ssize_t bytes_read, bytes_written;
size_t blen = (length > sizeof(buff))? sizeof(buff) : length;
bytes_read = ::read(src_fd, buff, blen);
if (bytes_read == 0) {
// EOF
break;
}
else if (bytes_read < 0) {
warnx("cp: read");
break;
}
bytes_written = ::write(dst_fd, buff, bytes_read);
if (bytes_written != bytes_read) {
warnx("cp: short write");
break;
}
length -= bytes_written;
}
::close(src_fd);
::close(dst_fd);
return (length > 0)? -1 : 0;
}

3
src/modules/mavlink/mavlink_ftp.h

@ -97,6 +97,7 @@ public: @@ -97,6 +97,7 @@ public:
kCmdCreateDirectory, ///< Creates directory at <path>
kCmdRemoveDirectory, ///< Removes Directory at <path>, must be empty
kCmdOpenFileWO, ///< Opens file at <path> for writing, returns <session>
kCmdTruncateFile, ///< Truncate file at <path> to <offset> length
kRspAck = 128, ///< Ack response
kRspNak ///< Nak response
@ -139,6 +140,7 @@ private: @@ -139,6 +140,7 @@ private:
static void _worker_trampoline(void *arg);
void _process_request(Request *req);
void _reply(Request *req);
int _copy_file(const char *src_path, const char *dst_path, ssize_t length);
ErrorCode _workList(PayloadHeader *payload);
ErrorCode _workOpen(PayloadHeader *payload, int oflag);
@ -149,6 +151,7 @@ private: @@ -149,6 +151,7 @@ private:
ErrorCode _workRemoveDirectory(PayloadHeader *payload);
ErrorCode _workCreateDirectory(PayloadHeader *payload);
ErrorCode _workRemoveFile(PayloadHeader *payload);
ErrorCode _workTruncateFile(PayloadHeader *payload);
static const unsigned kRequestQueueSize = 2; ///< Max number of queued requests
Request _request_bufs[kRequestQueueSize]; ///< Request buffers which hold work

Loading…
Cancel
Save