CFE-2986: Added getdir command to cf-net, copies directory and files#6049
CFE-2986: Added getdir command to cf-net, copies directory and files#6049SimonThalvorsen wants to merge 1 commit intocfengine:masterfrom
Conversation
f7cebad to
40a6c09
Compare
larsewi
left a comment
There was a problem hiding this comment.
It would be nicer if we extended cf-net get to get both files and directories, instead of having two separate sub-commands. Please investigate how rsync does this and try to do it in a similar way here.
@larsewi on the other hand, cf-net was written mainly as a protocol testing tool, and the commands mirror their protocol command names. If the There is also some advantage to not being too dynamic with this stuff. If you make a CLI that forces the user to specify if they are copying a file or a folder, you can prevent some annoying / confusing situations. We could for example make a new subcommand, |
40a6c09 to
2bd2729
Compare
larsewi
left a comment
There was a problem hiding this comment.
Please break this up a little. Maybe a recursive solution would be more elegant given that it is a recursive problem.
cf-net/cf-net.c
Outdated
| filedata->print_stats = opts->print_stats; | ||
|
|
||
| filedata->ret = ProtocolStatGet(conn, filedata->remote_file, | ||
| filedata->local_file, 0644, filedata->print_stats); |
There was a problem hiding this comment.
Maybe you should use the remote file permissions (available from the ProtocolStat) instead?
cf-net/cf-net.c
Outdated
| char curr_dir[PATH_MAX]; | ||
| snprintf(curr_dir, sizeof(curr_dir), "%s/%s", local_dir, curr); | ||
|
|
||
| GetFileData *filedata = calloc(1, sizeof(GetFileData)); |
There was a problem hiding this comment.
This does not need to be heap allocated
cf-net/cf-net.c
Outdated
| continue; | ||
| } | ||
|
|
||
| snprintf(filedata->local_file, PATH_MAX, "%s", curr_dir); |
There was a problem hiding this comment.
Please check for truncation on all the calls to snprintf
cf-net/cf-net.c
Outdated
| return invalid_command("getdir"); | ||
| break; |
There was a problem hiding this comment.
Unreachable break after return
cf-net/cf-net.c
Outdated
| if (local_dir != NULL) | ||
| { | ||
| Log(LOG_LEVEL_INFO, | ||
| "Warning: multiple occurences of -o in command, "\ |
There was a problem hiding this comment.
| "Warning: multiple occurences of -o in command, "\ | |
| "Warning: multiple occurrences of -o in command, "\ |
2bd2729 to
e9f4cb3
Compare
| Log(LOG_LEVEL_ERR, "Failed to get remote file: %s:%s", | ||
| conn->this_server, remote_path); | ||
| return false; | ||
| } |
Check notice
Code scanning / CodeQL
Pointer argument is dereferenced without checking for NULL Note
| } | ||
|
|
||
| // Helper: Create local directory path | ||
| static bool create_local_dir(const char *local_base, const char *subdir, |
Check notice
Code scanning / CodeQL
Pointer argument is dereferenced without checking for NULL Note
e9f4cb3 to
5b55d16
Compare
larsewi
left a comment
There was a problem hiding this comment.
There should be a recursion depth limit to prevent a potential malicious or misconfigured server with symlink loops (or deeply nested dirs) to cause stack overflow.
We should probably stick to a maximum path size for the same reasons above.
cf-net/cf-net.c
Outdated
| char local_full[PATH_MAX]; | ||
| written = snprintf(local_full, sizeof(local_full), "%s/%s", local_path, item); | ||
| if (written < 0 || written >= sizeof(local_full)) { | ||
| Log(LOG_LEVEL_ERR, "Path too long for full local path: %s",local_full); |
There was a problem hiding this comment.
Here you print the truncated path and not the intended full path. This could be a bit misleading.
| if (written < 0 || written >= len) { | ||
| Log(LOG_LEVEL_ERR, "Path too long for local path: %s", temp); | ||
| free(local_dir); | ||
| return -1; |
cf-net/cf-net.c
Outdated
| free(local_dir); | ||
| return -1; | ||
| } | ||
| int written = snprintf(temp, len, "%s/%s", local_dir, basename(remote_dir)); |
There was a problem hiding this comment.
Consider using StringFormat()
cf-net/cf-net.c
Outdated
| char *remote_dir = args[0]; | ||
| if (specified_path) | ||
| { | ||
| size_t len = strlen(local_dir) + strlen(basename(remote_dir)) + 2; // / and '\0' |
There was a problem hiding this comment.
basename() may modify it's argument
| } | ||
|
|
||
| // Helper: Recursively process directory entries | ||
| static void process_dir_recursive(AgentConnection *conn, |
There was a problem hiding this comment.
The function returns void. If all files fail to download, CFNetGetDir still returns 0 (success).
There was a problem hiding this comment.
I do not see why this is an issue, failing to stat/get/mkdir will all log their respective errors. So you would rather it return -1 on any one error instead of continue?
There was a problem hiding this comment.
If you were to use it in a script, then it would be easier to check the exit value rather then parsing log messages. Does the other commands exit with 0 on failure?
| } | ||
|
|
||
| // Helper: Get a single file with permissions | ||
| static bool CFNetGetWithPerms(AgentConnection *conn, const char *remote_path, |
There was a problem hiding this comment.
File permissions are preserved via ProtocolGet, but created directories don't get the remote directory's permissions applied.
cf-net/cf-net.c
Outdated
| SeqDestroy(items); | ||
| } | ||
|
|
||
| static int CFNetGetDir( CFNetOptions *opts, const char *hostname, char **args) |
There was a problem hiding this comment.
| static int CFNetGetDir( CFNetOptions *opts, const char *hostname, char **args) | |
| static int CFNetGetDir(CFNetOptions *opts, const char *hostname, char **args) |
cf-net/cf-net.c
Outdated
| return -1; | ||
| } | ||
| int written = snprintf(temp, len, "%s/%s", local_dir, basename(remote_dir)); | ||
| if (written < 0 || written >= len) { |
There was a problem hiding this comment.
| if (written < 0 || written >= len) { | |
| if (written < 0 || written >= len) | |
| { |
cf-net/cf-net.c
Outdated
| assert(conn != NULL && remote_path != NULL && local_path != NULL); | ||
|
|
||
| struct stat perms; | ||
| if (!ProtocolStat(conn, remote_path, &perms)) { |
There was a problem hiding this comment.
Try to be consistent with the braces. CONTRIBUTING.md says to put them on a new line. Look through the rest of the code, there are more cases like this.
| if (!ProtocolStat(conn, remote_path, &perms)) { | |
| if (!ProtocolStat(conn, remote_path, &perms)) | |
| { |
cf-net/cf-net.c
Outdated
|
|
||
| if (has_output_path) { | ||
| written = snprintf(path, sizeof(path), "%s/%s/", local_base, subdir); | ||
| } else { |
There was a problem hiding this comment.
Use Allman style, not K&R style (} else {)
Ticket: CFE-2986 Changelog: Title Signed-off-by: Simon Halvorsen <simon.halvorsen@northern.tech>
5b55d16 to
d68100f
Compare
Ticket: CFE-2986
Changelog: Title