-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
nanocoap_vfs: add nanocoap_vfs_get() #17937
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright (C) 2022 ML!PA Consulting GmbH | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @ingroup net_nanosock | ||
* @brief VFS NanoCoAP helper functions | ||
* | ||
* @{ | ||
* | ||
* @file | ||
* @brief VFS NanoCoAP helper functions | ||
* | ||
* @author Benjamin Valentin <[email protected]> | ||
*/ | ||
#ifndef NET_NANOCOAP_VFS_H | ||
#define NET_NANOCOAP_VFS_H | ||
|
||
#include "net/nanocoap_sock.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/** | ||
* @brief Downloads the resource behind @p url via blockwise | ||
* GET and stores it in the file @p dst. | ||
* | ||
* @param[in] url URL to the resource | ||
* @param[in] dst Path to the destination file | ||
* | ||
* @returns 0 on success | ||
* @returns <0 on error | ||
*/ | ||
int nanocoap_vfs_get_url(const char *url, const char *dst); | ||
|
||
/** | ||
* @brief Downloads the resource behind @p path via blockwise | ||
* GET and stores it in the file @p dst. | ||
* | ||
* @param[in] sock Connection to the server | ||
* @param[in] path Remote query path to the resource | ||
* @param[in] dst Local path to the destination file | ||
* | ||
* @returns 0 on success | ||
* @returns <0 on error | ||
*/ | ||
benpicco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
int nanocoap_vfs_get(nanocoap_sock_t *sock, const char *path, const char *dst); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whenever there is a pair like this (get vs. get_url), I wonder when to use which, if the use cases overlap or whether there are combinations that would be needed. (For example, can one use an established socket with a URL that has query components, or a Uri-Host component?) Here it's probably motivated by the duality of I'd appreciate a note on when to use which, but maybe there are no good answers until #13827 is through. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The path component (and everything that goes with it) will be parsed the same way for both in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the path argument is really more path and query? If so, that should be documented (dejavu, I think we've had this somewhere else already.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can I just call it query path? |
||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
#endif /* NET_NANOCOAP_VFS_H */ | ||
/** @} */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* | ||
* Copyright (C) 2022 ML!PA Consulting GmbH | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @ingroup net_nanocoap | ||
* @{ | ||
* | ||
* @file | ||
* @brief Nanocoap VFS helpers | ||
* | ||
* @author Benjamin Valentin <[email protected]> | ||
* | ||
* @} | ||
*/ | ||
|
||
#include <fcntl.h> | ||
#include "net/nanocoap_sock.h" | ||
#include "net/sock/util.h" | ||
#include "vfs.h" | ||
|
||
#define ENABLE_DEBUG 0 | ||
#include "debug.h" | ||
|
||
static int _2file(void *arg, size_t offset, uint8_t *buf, size_t len, int more) | ||
{ | ||
(void)more; | ||
int *fd = arg; | ||
|
||
vfs_lseek(*fd, offset, SEEK_SET); | ||
return vfs_write(*fd, buf, len); | ||
} | ||
|
||
static int _prepare_file(const char *dst, char *dst_tmp, size_t len) | ||
{ | ||
/* download to temp file, rename it later */ | ||
if (snprintf(dst_tmp, len, "%s.t", dst) > (int)len) { | ||
return -ENOBUFS; | ||
} | ||
|
||
return vfs_open(dst_tmp, O_CREAT | O_WRONLY | O_TRUNC, 0644); | ||
} | ||
|
||
static int _finalize_file(int fd, int res, const char *dst, const char *dst_tmp) | ||
{ | ||
vfs_close(fd); | ||
|
||
/* move file to it's final location */ | ||
if (res >= 0) { | ||
DEBUG("nanocoap: moving %s to %s\n", dst_tmp, dst); | ||
vfs_unlink(dst); | ||
res = vfs_rename(dst_tmp, dst); | ||
} | ||
|
||
vfs_unlink(dst_tmp); | ||
|
||
return res; | ||
} | ||
|
||
int nanocoap_vfs_get(nanocoap_sock_t *sock, const char *path, const char *dst) | ||
{ | ||
int fd, res; | ||
char dst_tmp[CONFIG_SOCK_URLPATH_MAXLEN]; | ||
|
||
DEBUG("nanocoap: downloading %s to %s\n", path, dst_tmp); | ||
|
||
fd = _prepare_file(dst, dst_tmp, sizeof(dst_tmp)); | ||
if (fd < 0) { | ||
return fd; | ||
} | ||
res = nanocoap_sock_get_blockwise(sock, path, CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT, | ||
_2file, &fd); | ||
return _finalize_file(fd, res, dst, dst_tmp); | ||
} | ||
|
||
int nanocoap_vfs_get_url(const char *url, const char *dst) | ||
{ | ||
int fd, res; | ||
char dst_tmp[CONFIG_SOCK_URLPATH_MAXLEN]; | ||
|
||
DEBUG("nanocoap: downloading %s to %s\n", url, dst_tmp); | ||
|
||
fd = _prepare_file(dst, dst_tmp, sizeof(dst_tmp)); | ||
if (fd < 0) { | ||
return fd; | ||
} | ||
res = nanocoap_get_blockwise_url(url, CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT, | ||
_2file, &fd); | ||
return _finalize_file(fd, res, dst, dst_tmp); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* | ||
* Copyright (C) 2022 ML!PA Consulting GmbH | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @ingroup sys_shell_commands | ||
* @{ | ||
* | ||
* @file | ||
* @brief NanoCoAP commands that interact with the filesystem | ||
* | ||
* @author Benjamin Valentin <[email protected]> | ||
* | ||
* @} | ||
*/ | ||
|
||
#include <errno.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <inttypes.h> | ||
|
||
#include "vfs_default.h" | ||
#include "net/nanocoap_vfs.h" | ||
#include "net/nanocoap_sock.h" | ||
|
||
struct dir_list_ctx { | ||
char *buf; | ||
char *cur; | ||
char *end; | ||
}; | ||
|
||
static bool _is_dir(const char *url) | ||
{ | ||
int len = strlen(url); | ||
return url[len - 1] == '/'; | ||
} | ||
|
||
static int _print_cb(void *arg, size_t offset, uint8_t *buf, size_t len, int more) | ||
{ | ||
(void)arg; | ||
(void)offset; | ||
|
||
write(STDOUT_FILENO, buf, len); | ||
if (!more) { | ||
puts(""); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int _print_dir_cb(void *arg, size_t offset, uint8_t *buf, size_t len, int more) | ||
{ | ||
(void)offset; | ||
(void)more; | ||
|
||
struct dir_list_ctx *ctx = arg; | ||
|
||
char *end = (char *)buf + len; | ||
for (char *c = (char *)buf; c < end; ++c) { | ||
if (ctx->cur) { | ||
if (*c == '>' || ctx->cur == ctx->end) { | ||
*ctx->cur = 0; | ||
puts(ctx->buf); | ||
ctx->cur = NULL; | ||
} else { | ||
*ctx->cur++ = *c; | ||
} | ||
} else if (*c == '<') { | ||
ctx->cur = ctx->buf; | ||
} | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int _print_dir(const char *url, char *buf, size_t len) | ||
{ | ||
struct dir_list_ctx ctx = { | ||
.buf = buf, | ||
.end = buf + len, | ||
}; | ||
return nanocoap_get_blockwise_url(url, CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT, | ||
_print_dir_cb, &ctx); | ||
} | ||
|
||
int _nanocoap_get_handler(int argc, char **argv) | ||
{ | ||
int res; | ||
char buffer[CONFIG_NANOCOAP_QS_MAX]; | ||
char *dst, *url = argv[1]; | ||
|
||
if (argc < 2) { | ||
printf("Usage: %s <url> [destination]\n", argv[0]); | ||
benpicco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
printf("Default destination: %s\n", VFS_DEFAULT_DATA); | ||
return -EINVAL; | ||
} | ||
|
||
if (_is_dir(url) && argc < 3) { | ||
res = _print_dir(url, buffer, sizeof(buffer)); | ||
if (res) { | ||
printf("Request failed: %s\n", strerror(-res)); | ||
} | ||
return res; | ||
} | ||
|
||
if (argc < 3) { | ||
dst = strrchr(url, '/'); | ||
if (dst == NULL) { | ||
printf("invalid url: '%s'\n", url); | ||
return -EINVAL; | ||
} | ||
if (snprintf(buffer, sizeof(buffer), "%s%s", | ||
VFS_DEFAULT_DATA, dst) >= (int)sizeof(buffer)) { | ||
printf("Output file path too long\n"); | ||
return -ENOBUFS; | ||
} | ||
dst = buffer; | ||
} else { | ||
dst = argv[2]; | ||
} | ||
|
||
/* alternatively write the file to stdout */ | ||
if (strcmp(dst, "-") == 0) { | ||
return nanocoap_get_blockwise_url(url, CONFIG_NANOCOAP_BLOCKSIZE_DEFAULT, | ||
_print_cb, NULL); | ||
} | ||
|
||
res = nanocoap_vfs_get_url(url, dst); | ||
if (res < 0) { | ||
printf("Download failed: %s\n", strerror(-res)); | ||
} else { | ||
printf("Saved as %s\n", dst); | ||
} | ||
return res; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.