/// @brief Responds to an Open command MavlinkFTP::ErrorCode MavlinkFTP::_workOpen(PayloadHeader* payload, int oflag) { int session_index = _find_unused_session(); if (session_index < 0) { warnx("FTP: Open failed - out of sessions\n"); return kErrNoSessionsAvailable; } char *filename = _data_as_cstring(payload); uint32_t fileSize = 0; struct stat st; if (stat(filename, &st) != 0) { // fail only if requested open for read if (oflag & O_RDONLY) return kErrFailErrno; else st.st_size = 0; } fileSize = st.st_size; int fd = ::open(filename, oflag); if (fd < 0) { return kErrFailErrno; } _session_fds[session_index] = fd; payload->session = session_index; payload->size = sizeof(uint32_t); *((uint32_t*)payload->data) = fileSize; return kErrNone; }
/// @brief Responds to a CalcFileCRC32 command MavlinkFTP::ErrorCode MavlinkFTP::_workCalcFileCRC32(PayloadHeader* payload) { char file_buf[256]; uint32_t checksum = 0; ssize_t bytes_read; strncpy(file_buf, _data_as_cstring(payload), kMaxDataLength); int fd = ::open(file_buf, O_RDONLY); if (fd < 0) { return kErrFailErrno; } do { bytes_read = ::read(fd, file_buf, sizeof(file_buf)); if (bytes_read < 0) { int r_errno = errno; ::close(fd); errno = r_errno; return kErrFailErrno; } checksum = crc32part((uint8_t*)file_buf, bytes_read, checksum); } while (bytes_read == sizeof(file_buf)); ::close(fd); payload->size = sizeof(uint32_t); *((uint32_t*)payload->data) = checksum; return kErrNone; }
/// @brief Responds to a Rename command MavlinkFTP::ErrorCode MavlinkFTP::_workRename(PayloadHeader* payload) { char oldpath[kMaxDataLength]; char newpath[kMaxDataLength]; char *ptr = _data_as_cstring(payload); size_t oldpath_sz = strlen(ptr); if (oldpath_sz == payload->size) { // no newpath errno = EINVAL; return kErrFailErrno; } strncpy(oldpath, ptr, kMaxDataLength); strncpy(newpath, ptr + oldpath_sz + 1, kMaxDataLength); if (rename(oldpath, newpath) == 0) { payload->size = 0; return kErrNone; } else { return kErrFailErrno; } }
/// @brief Responds to a CalcFileCRC32 command MavlinkFTP::ErrorCode MavlinkFTP::_workCalcFileCRC32(PayloadHeader *payload) { uint32_t checksum = 0; ssize_t bytes_read; strncpy(_work_buffer2, _root_dir, _work_buffer2_len); strncpy(_work_buffer2 + _root_dir_len, _data_as_cstring(payload), _work_buffer2_len - _root_dir_len); // ensure termination _work_buffer2[_work_buffer2_len - 1] = '\0'; int fd = ::open(_work_buffer2, O_RDONLY); if (fd < 0) { return kErrFailErrno; } do { bytes_read = ::read(fd, _work_buffer2, _work_buffer2_len); if (bytes_read < 0) { int r_errno = errno; ::close(fd); errno = r_errno; return kErrFailErrno; } checksum = crc32part((uint8_t *)_work_buffer2, bytes_read, checksum); } while (bytes_read == _work_buffer2_len); ::close(fd); payload->size = sizeof(uint32_t); std::memcpy(payload->data, &checksum, payload->size); return kErrNone; }
/// @brief Responds to a Rename command MavlinkFTP::ErrorCode MavlinkFTP::_workRename(PayloadHeader *payload) { char *ptr = _data_as_cstring(payload); size_t oldpath_sz = strlen(ptr); if (oldpath_sz == payload->size) { // no newpath errno = EINVAL; return kErrFailErrno; } strncpy(_work_buffer1, _root_dir, _work_buffer1_len); strncpy(_work_buffer1 + _root_dir_len, ptr, _work_buffer1_len - _root_dir_len); _work_buffer1[_work_buffer1_len - 1] = '\0'; // ensure termination strncpy(_work_buffer2, _root_dir, _work_buffer2_len); strncpy(_work_buffer2 + _root_dir_len, ptr + oldpath_sz + 1, _work_buffer2_len - _root_dir_len); _work_buffer2[_work_buffer2_len - 1] = '\0'; // ensure termination if (rename(_work_buffer1, _work_buffer2) == 0) { payload->size = 0; return kErrNone; } else { return kErrFailErrno; } }
/// @brief Responds to a CreateDirectory command MavlinkFTP::ErrorCode MavlinkFTP::_workCreateDirectory(PayloadHeader* payload) { char dir[kMaxDataLength]; strncpy(dir, _data_as_cstring(payload), kMaxDataLength); if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) == 0) { payload->size = 0; return kErrNone; } else { return kErrFailErrno; } }
/// @brief Responds to a RemoveFile command MavlinkFTP::ErrorCode MavlinkFTP::_workRemoveFile(PayloadHeader* payload) { char file[kMaxDataLength]; strncpy(file, _data_as_cstring(payload), kMaxDataLength); if (unlink(file) == 0) { payload->size = 0; return kErrNone; } else { return kErrFailErrno; } }
/// @brief Responds to a CreateDirectory command MavlinkFTP::ErrorCode MavlinkFTP::_workCreateDirectory(PayloadHeader *payload) { strncpy(_work_buffer1, _root_dir, _work_buffer1_len); strncpy(_work_buffer1 + _root_dir_len, _data_as_cstring(payload), _work_buffer1_len - _root_dir_len); // ensure termination _work_buffer1[_work_buffer1_len - 1] = '\0'; if (mkdir(_work_buffer1, S_IRWXU | S_IRWXG | S_IRWXO) == 0) { payload->size = 0; return kErrNone; } else { return kErrFailErrno; } }
/// @brief Responds to an Open command MavlinkFTP::ErrorCode MavlinkFTP::_workOpen(PayloadHeader *payload, int oflag) { if (_session_info.fd >= 0) { warnx("FTP: Open failed - out of sessions\n"); return kErrNoSessionsAvailable; } char *filename = _data_as_cstring(payload); #ifdef MAVLINK_FTP_DEBUG warnx("FTP: open '%s'", filename); #endif uint32_t fileSize = 0; struct stat st; if (stat(filename, &st) != 0) { // fail only if requested open for read if (oflag & O_RDONLY) { return kErrFailErrno; } else { st.st_size = 0; } } fileSize = st.st_size; // Set mode to 666 incase oflag has O_CREAT int fd = ::open(filename, oflag, PX4_O_MODE_666); if (fd < 0) { return kErrFailErrno; } _session_info.fd = fd; _session_info.file_size = fileSize; _session_info.stream_download = false; payload->session = 0; payload->size = sizeof(uint32_t); std::memcpy(payload->data, &fileSize, payload->size); return kErrNone; }
/// @brief Responds to an Open command MavlinkFTP::ErrorCode MavlinkFTP::_workOpen(PayloadHeader* payload, bool create) { int session_index = _find_unused_session(); if (session_index < 0) { warnx("FTP: Open failed - out of sessions\n"); return kErrNoSessionsAvailable; } char *filename = _data_as_cstring(payload); uint32_t fileSize = 0; if (!create) { struct stat st; if (stat(filename, &st) != 0) { return kErrFailErrno; } fileSize = st.st_size; } int oflag = create ? (O_CREAT | O_EXCL | O_APPEND) : O_RDONLY; int fd = ::open(filename, oflag); if (fd < 0) { return kErrFailErrno; } _session_fds[session_index] = fd; payload->session = session_index; if (create) { payload->size = 0; } else { payload->size = sizeof(uint32_t); *((uint32_t*)payload->data) = fileSize; } return kErrNone; }
/// @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) if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) { errno = EROFS; return kErrFailErrno; } if (payload->offset == (unsigned)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 > (unsigned)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 List command MavlinkFTP::ErrorCode MavlinkFTP::_workList(PayloadHeader* payload) { char dirPath[kMaxDataLength]; strncpy(dirPath, _data_as_cstring(payload), kMaxDataLength); DIR *dp = opendir(dirPath); if (dp == nullptr) { warnx("FTP: can't open path '%s'", dirPath); return kErrFailErrno; } #ifdef MAVLINK_FTP_DEBUG warnx("FTP: list %s offset %d", dirPath, payload->offset); #endif ErrorCode errorCode = kErrNone; struct dirent entry, *result = nullptr; unsigned offset = 0; // move to the requested offset seekdir(dp, payload->offset); for (;;) { // read the directory entry if (readdir_r(dp, &entry, &result)) { warnx("FTP: list %s readdir_r failure\n", dirPath); errorCode = kErrFailErrno; break; } // no more entries? if (result == nullptr) { if (payload->offset != 0 && offset == 0) { // User is requesting subsequent dir entries but there were none. This means the user asked // to seek past EOF. errorCode = kErrEOF; } // Otherwise we are just at the last directory entry, so we leave the errorCode at kErrorNone to signal that break; } uint32_t fileSize = 0; char buf[256]; char direntType; // Determine the directory entry type switch (entry.d_type) { case DTYPE_FILE: // For files we get the file size as well direntType = kDirentFile; snprintf(buf, sizeof(buf), "%s/%s", dirPath, entry.d_name); struct stat st; if (stat(buf, &st) == 0) { fileSize = st.st_size; } break; case DTYPE_DIRECTORY: if (strcmp(entry.d_name, ".") == 0 || strcmp(entry.d_name, "..") == 0) { // Don't bother sending these back direntType = kDirentSkip; } else { direntType = kDirentDir; } break; default: // We only send back file and diretory entries, skip everything else direntType = kDirentSkip; } if (direntType == kDirentSkip) { // Skip send only dirent identifier buf[0] = '\0'; } else if (direntType == kDirentFile) { // Files send filename and file length snprintf(buf, sizeof(buf), "%s\t%d", entry.d_name, fileSize); } else { // Everything else just sends name strncpy(buf, entry.d_name, sizeof(buf)); buf[sizeof(buf)-1] = 0; } size_t nameLen = strlen(buf); // Do we have room for the name, the one char directory identifier and the null terminator? if ((offset + nameLen + 2) > kMaxDataLength) { break; } // Move the data into the buffer payload->data[offset++] = direntType; strcpy((char *)&payload->data[offset], buf); #ifdef MAVLINK_FTP_DEBUG printf("FTP: list %s %s\n", dirPath, (char *)&payload->data[offset-1]); #endif offset += nameLen + 1; } closedir(dp); payload->size = offset; return errorCode; }
/// @brief Responds to a TruncateFile command MavlinkFTP::ErrorCode MavlinkFTP::_workTruncateFile(PayloadHeader *payload) { strncpy(_work_buffer1, _root_dir, _work_buffer1_len); strncpy(_work_buffer1 + _root_dir_len, _data_as_cstring(payload), _work_buffer1_len - _root_dir_len); // ensure termination _work_buffer1[_work_buffer1_len - 1] = '\0'; payload->size = 0; #ifdef __PX4_NUTTX // emulate truncate(_work_buffer1, payload->offset) by // copying to temp and overwrite with O_TRUNC flag (NuttX does not support truncate()). const char temp_file[] = PX4_ROOTFSDIR"/fs/microsd/.trunc.tmp"; struct stat st; if (stat(_work_buffer1, &st) != 0) { return kErrFailErrno; } if (!S_ISREG(st.st_mode)) { errno = EISDIR; return kErrFailErrno; } // check perms allow us to write (not romfs) if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) { errno = EROFS; return kErrFailErrno; } if (payload->offset == (unsigned)st.st_size) { // nothing to do return kErrNone; } else if (payload->offset == 0) { // 1: truncate all data int fd = ::open(_work_buffer1, O_TRUNC | O_WRONLY); if (fd < 0) { return kErrFailErrno; } ::close(fd); return kErrNone; } else if (payload->offset > (unsigned)st.st_size) { // 2: extend file int fd = ::open(_work_buffer1, 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(_work_buffer1, temp_file, payload->offset) != 0) { return kErrFailErrno; } if (_copy_file(temp_file, _work_buffer1, payload->offset) != 0) { return kErrFailErrno; } if (::unlink(temp_file) != 0) { return kErrFailErrno; } return kErrNone; } #else int ret = truncate(_work_buffer1, payload->offset); if (ret == 0) { return kErrNone; } return kErrFailErrno; #endif /* __PX4_NUTTX */ }
/// @brief Responds to a List command MavlinkFTP::ErrorCode MavlinkFTP::_workList(PayloadHeader *payload, bool list_hidden) { strncpy(_work_buffer1, _root_dir, _work_buffer1_len); strncpy(_work_buffer1 + _root_dir_len, _data_as_cstring(payload), _work_buffer1_len - _root_dir_len); // ensure termination _work_buffer1[_work_buffer1_len - 1] = '\0'; ErrorCode errorCode = kErrNone; unsigned offset = 0; DIR *dp = opendir(_work_buffer1); if (dp == nullptr) { #ifdef MAVLINK_FTP_UNIT_TEST warnx("File open failed"); #else _mavlink->send_statustext_critical("FTP: can't open path (file system corrupted?)"); _mavlink->send_statustext_critical(_work_buffer1); #endif // this is not an FTP error, abort directory by simulating eof return kErrEOF; } #ifdef MAVLINK_FTP_DEBUG warnx("FTP: list %s offset %d", _work_buffer1, payload->offset); #endif struct dirent *result = nullptr; // move to the requested offset int requested_offset = payload->offset; while (requested_offset-- > 0 && readdir(dp)); for (;;) { errno = 0; result = readdir(dp); // read the directory entry if (result == nullptr) { if (errno) { #ifdef MAVLINK_FTP_UNIT_TEST warnx("readdir failed"); #else _mavlink->send_statustext_critical("FTP: list readdir failure"); _mavlink->send_statustext_critical(_work_buffer1); #endif payload->data[offset++] = kDirentSkip; *((char *)&payload->data[offset]) = '\0'; offset++; payload->size = offset; closedir(dp); return errorCode; } // no more entries? if (payload->offset != 0 && offset == 0) { // User is requesting subsequent dir entries but there were none. This means the user asked // to seek past EOF. errorCode = kErrEOF; } // Otherwise we are just at the last directory entry, so we leave the errorCode at kErrorNone to signal that break; } uint32_t fileSize = 0; char direntType; // Determine the directory entry type switch (result->d_type) { #ifdef __PX4_NUTTX case DTYPE_FILE: { #else case DT_REG: { #endif // For files we get the file size as well direntType = kDirentFile; int ret = snprintf(_work_buffer2, _work_buffer2_len, "%s/%s", _work_buffer1, result->d_name); bool buf_is_ok = ((ret > 0) && (ret < _work_buffer2_len)); if (buf_is_ok) { struct stat st; if (stat(_work_buffer2, &st) == 0) { fileSize = st.st_size; } } break; } #ifdef __PX4_NUTTX case DTYPE_DIRECTORY: #else case DT_DIR: #endif if ((!list_hidden && (strncmp(result->d_name, ".", 1) == 0)) || strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0) { // Don't bother sending these back direntType = kDirentSkip; } else { direntType = kDirentDir; } break; default: // We only send back file and diretory entries, skip everything else direntType = kDirentSkip; } if (direntType == kDirentSkip) { // Skip send only dirent identifier _work_buffer2[0] = '\0'; } else if (direntType == kDirentFile) { // Files send filename and file length int ret = snprintf(_work_buffer2, _work_buffer2_len, "%s\t%d", result->d_name, fileSize); bool buf_is_ok = ((ret > 0) && (ret < _work_buffer2_len)); if (!buf_is_ok) { _work_buffer2[_work_buffer2_len - 1] = '\0'; } } else { // Everything else just sends name strncpy(_work_buffer2, result->d_name, _work_buffer2_len); _work_buffer2[_work_buffer2_len - 1] = '\0'; } size_t nameLen = strlen(_work_buffer2); // Do we have room for the name, the one char directory identifier and the null terminator? if ((offset + nameLen + 2) > kMaxDataLength) { break; } // Move the data into the buffer payload->data[offset++] = direntType; strcpy((char *)&payload->data[offset], _work_buffer2); #ifdef MAVLINK_FTP_DEBUG printf("FTP: list %s %s\n", _work_buffer1, (char *)&payload->data[offset - 1]); #endif offset += nameLen + 1; } closedir(dp); payload->size = offset; return errorCode; } /// @brief Responds to an Open command MavlinkFTP::ErrorCode MavlinkFTP::_workOpen(PayloadHeader *payload, int oflag) { if (_session_info.fd >= 0) { PX4_ERR("FTP: Open failed - out of sessions\n"); return kErrNoSessionsAvailable; } strncpy(_work_buffer1, _root_dir, _work_buffer1_len); strncpy(_work_buffer1 + _root_dir_len, _data_as_cstring(payload), _work_buffer1_len - _root_dir_len); #ifdef MAVLINK_FTP_DEBUG warnx("FTP: open '%s'", _work_buffer1); #endif uint32_t fileSize = 0; struct stat st; if (stat(_work_buffer1, &st) != 0) { // fail only if requested open for read if (oflag & O_RDONLY) { return kErrFailErrno; } else { st.st_size = 0; } } fileSize = st.st_size; // Set mode to 666 incase oflag has O_CREAT int fd = ::open(_work_buffer1, oflag, PX4_O_MODE_666); if (fd < 0) { return kErrFailErrno; } _session_info.fd = fd; _session_info.file_size = fileSize; _session_info.stream_download = false; payload->session = 0; payload->size = sizeof(uint32_t); std::memcpy(payload->data, &fileSize, payload->size); return kErrNone; } /// @brief Responds to a Read command MavlinkFTP::ErrorCode MavlinkFTP::_workRead(PayloadHeader *payload) { if (payload->session != 0 || _session_info.fd < 0) { return kErrInvalidSession; } #ifdef MAVLINK_FTP_DEBUG warnx("FTP: read offset:%d", payload->offset); #endif // We have to test seek past EOF ourselves, lseek will allow seek past EOF if (payload->offset >= _session_info.file_size) { PX4_ERR("request past EOF"); return kErrEOF; } if (lseek(_session_info.fd, payload->offset, SEEK_SET) < 0) { PX4_ERR("seek fail"); return kErrFailErrno; } int bytes_read = ::read(_session_info.fd, &payload->data[0], kMaxDataLength); if (bytes_read < 0) { // Negative return indicates error other than eof PX4_ERR("read fail %d", bytes_read); return kErrFailErrno; } payload->size = bytes_read; return kErrNone; } /// @brief Responds to a Stream command MavlinkFTP::ErrorCode MavlinkFTP::_workBurst(PayloadHeader *payload, uint8_t target_system_id) { if (payload->session != 0 && _session_info.fd < 0) { return kErrInvalidSession; } #ifdef MAVLINK_FTP_DEBUG warnx("FTP: burst offset:%d", payload->offset); #endif // Setup for streaming sends _session_info.stream_download = true; _session_info.stream_offset = payload->offset; _session_info.stream_chunk_transmitted = 0; _session_info.stream_seq_number = payload->seq_number + 1; _session_info.stream_target_system_id = target_system_id; return kErrNone; } /// @brief Responds to a Write command MavlinkFTP::ErrorCode MavlinkFTP::_workWrite(PayloadHeader *payload) { if (payload->session != 0 && _session_info.fd < 0) { return kErrInvalidSession; } if (lseek(_session_info.fd, payload->offset, SEEK_SET) < 0) { // Unable to see to the specified location PX4_ERR("seek fail"); return kErrFailErrno; } int bytes_written = ::write(_session_info.fd, &payload->data[0], payload->size); if (bytes_written < 0) { // Negative return indicates error other than eof PX4_ERR("write fail %d", bytes_written); return kErrFailErrno; } payload->size = sizeof(uint32_t); std::memcpy(payload->data, &bytes_written, payload->size); return kErrNone; } /// @brief Responds to a RemoveFile command MavlinkFTP::ErrorCode MavlinkFTP::_workRemoveFile(PayloadHeader *payload) { strncpy(_work_buffer1, _root_dir, _work_buffer1_len); strncpy(_work_buffer1 + _root_dir_len, _data_as_cstring(payload), _work_buffer1_len - _root_dir_len); // ensure termination _work_buffer1[_work_buffer1_len - 1] = '\0'; if (unlink(_work_buffer1) == 0) { payload->size = 0; return kErrNone; } else { return kErrFailErrno; } }
/// @brief Responds to a List command MavlinkFTP::ErrorCode MavlinkFTP::_workList(PayloadHeader *payload, bool list_hidden) { char dirPath[kMaxDataLength]; strncpy(dirPath, _data_as_cstring(payload), kMaxDataLength); ErrorCode errorCode = kErrNone; unsigned offset = 0; DIR *dp = opendir(dirPath); if (dp == nullptr) { #ifdef MAVLINK_FTP_UNIT_TEST warnx("File open failed"); #else _mavlink->send_statustext_critical("FTP: can't open path (file system corrupted?)"); _mavlink->send_statustext_critical(dirPath); #endif // this is not an FTP error, abort directory by simulating eof return kErrEOF; } #ifdef MAVLINK_FTP_DEBUG warnx("FTP: list %s offset %d", dirPath, payload->offset); #endif struct dirent *result = nullptr; // move to the requested offset seekdir(dp, payload->offset); for (;;) { errno = 0; result = readdir(dp); // read the directory entry if (result == nullptr) { if (errno) { #ifdef MAVLINK_FTP_UNIT_TEST warnx("readdir failed"); #else _mavlink->send_statustext_critical("FTP: list readdir failure"); _mavlink->send_statustext_critical(dirPath); #endif payload->data[offset++] = kDirentSkip; *((char *)&payload->data[offset]) = '\0'; offset++; payload->size = offset; closedir(dp); return errorCode; } // no more entries? if (payload->offset != 0 && offset == 0) { // User is requesting subsequent dir entries but there were none. This means the user asked // to seek past EOF. errorCode = kErrEOF; } // Otherwise we are just at the last directory entry, so we leave the errorCode at kErrorNone to signal that break; } uint32_t fileSize = 0; char buf[256]; char direntType; // Determine the directory entry type switch (result->d_type) { #ifdef __PX4_NUTTX case DTYPE_FILE: #else case DT_REG: #endif // For files we get the file size as well direntType = kDirentFile; snprintf(buf, sizeof(buf), "%s/%s", dirPath, result->d_name); struct stat st; if (stat(buf, &st) == 0) { fileSize = st.st_size; } break; #ifdef __PX4_NUTTX case DTYPE_DIRECTORY: #else case DT_DIR: #endif if ((!list_hidden && (strncmp(result->d_name, ".", 1) == 0)) || strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0) { // Don't bother sending these back direntType = kDirentSkip; } else { direntType = kDirentDir; } break; default: // We only send back file and diretory entries, skip everything else direntType = kDirentSkip; } if (direntType == kDirentSkip) { // Skip send only dirent identifier buf[0] = '\0'; } else if (direntType == kDirentFile) { // Files send filename and file length snprintf(buf, sizeof(buf), "%s\t%d", result->d_name, fileSize); } else { // Everything else just sends name strncpy(buf, result->d_name, sizeof(buf)); buf[sizeof(buf) - 1] = 0; } size_t nameLen = strlen(buf); // Do we have room for the name, the one char directory identifier and the null terminator? if ((offset + nameLen + 2) > kMaxDataLength) { break; } // Move the data into the buffer payload->data[offset++] = direntType; strcpy((char *)&payload->data[offset], buf); #ifdef MAVLINK_FTP_DEBUG printf("FTP: list %s %s\n", dirPath, (char *)&payload->data[offset - 1]); #endif offset += nameLen + 1; } closedir(dp); payload->size = offset; return errorCode; }