Skip to content

CFE-2986: Added getdir command to cf-net, copies directory and files#6049

Open
SimonThalvorsen wants to merge 1 commit intocfengine:masterfrom
SimonThalvorsen:CFE-2986
Open

CFE-2986: Added getdir command to cf-net, copies directory and files#6049
SimonThalvorsen wants to merge 1 commit intocfengine:masterfrom
SimonThalvorsen:CFE-2986

Conversation

@SimonThalvorsen
Copy link
Contributor

Ticket: CFE-2986
Changelog: Title

@SimonThalvorsen SimonThalvorsen requested a review from larsewi March 2, 2026 10:02
@larsewi larsewi changed the title Added getdir command to cf-net, copies directory and files CFE-2986: Added getdir command to cf-net, copies directory and files Mar 2, 2026
Copy link
Contributor

@larsewi larsewi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@olehermanse
Copy link
Member

olehermanse commented Mar 4, 2026

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 GET protocol command in CFEngine network protocol can only GET a file, it might be a bit confusing that cf-net get is something very different.

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, copy;

$ cf-net copy --file promises.cf
Copying file 1.2.3.4:/var/cfengine/masterfiles/promises.cf -> ./promises.cf
$ cf-net copy --file services/
Error: 'services/' does not look like a file, did you mean --directory?
$ cf-net copy --file services/.
Error: 'services/.' does not look like a file, did you mean --directory?
$ cf-net copy --directory services/
Copying directory 1.2.3.4:/var/cfengine/masterfiles/services/ -> ./services/
$ cf-net copy services/
Copying directory 1.2.3.4:/var/cfengine/masterfiles/services/ -> ./services/
$ cf-net copy services
Warning: Ambiguous if 'services' is a file or a directory - consider adding --file or --directory.
Copying directory 1.2.3.4:/var/cfengine/masterfiles/services/ -> ./services/

Copy link
Contributor

@larsewi larsewi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please break this up a little. Maybe a recursive solution would be more elegant given that it is a recursive problem.

char *local_dir = NULL;

int argc = 0;
while (args[argc] != NULL)

Check warning

Code scanning / CodeQL

Poorly documented large function Warning

Poorly documented function: fewer than 2% comments for a function of 115 lines.
@SimonThalvorsen SimonThalvorsen requested a review from larsewi March 9, 2026 14:42
Copy link
Contributor

@larsewi larsewi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@SimonThalvorsen SimonThalvorsen force-pushed the CFE-2986 branch 2 times, most recently from d68100f to 047b068 Compare March 12, 2026 14:29
@SimonThalvorsen SimonThalvorsen requested a review from larsewi March 12, 2026 14:37
Copy link
Contributor

@larsewi larsewi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to check return values of functions. It's OK to do best effort. I.e., we encounter an error but continue if it's safe. But in this case we need to cache the error so that we can later exit with failure. For some errors, like if we fail to create a directory, it does not make sense to try to fetch the files that should be in that directory afterwards.

@SimonThalvorsen SimonThalvorsen force-pushed the CFE-2986 branch 2 times, most recently from 62eb2df to c2b59c7 Compare March 13, 2026 15:49
Copy link
Contributor

@larsewi larsewi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's starting to look good. Just a few more nitpicks. Almost there!

{
char temp[PATH_MAX];

int written = snprintf(temp, sizeof(temp), "%s/%s", local_dir, base);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use after free. Base points to tmp, and tmp was free'd on line 1229. Above you should probably copy the string to a local buffer char tmp[PATH_MAX];. Then call basename on the stack allocated buffer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

base uses xstrdup on the basename of tmp, so it does not point into the same buffer

Ticket: CFE-2986
Changelog: Title

Signed-off-by: Simon Halvorsen <simon.halvorsen@northern.tech>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants