upstream: Add '-p' to sftp mkdir/lmkdir to create directories as

required

The -p option causes the mkdir and lmkdir commands to create any missing
intermediate directories. If '-p' is specified, it is not considered an
error if a directory already exists.

With / OK djm@

OpenBSD-Commit-ID: 72e4d4cf2e254959af5a0885e3f3a176846f4345
This commit is contained in:
job@openbsd.org authored and Damien Miller committed 2026-09-15 15:28:00 +10:00
1 parent 327fb6ce6f
commit d991f23d45
6 files changed
+149 -14

No files matched your search

+48 -1
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: misc.c,v 1.215 2026/06/21 19:23:56 tb Exp $ */
/* $OpenBSD: misc.c,v 1.216 2026/09/07 20:24:22 job Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005-2020 Damien Miller. All rights reserved.
@@ -3227,3 +3227,50 @@ get_homedir(void)
return NULL;
}
int
mkdir_path(const char *target, mode_t mode)
{
char *dir, *odir = NULL, *next;
int fd = AT_FDCWD, fd2, subpath_len, ret = -1;
dir = odir = xstrdup(target);
if (*dir == '/' &&
(fd = open("/", O_RDONLY|O_DIRECTORY)) == -1) {
error_f("open(\"/\"): %s", strerror(errno));
return -1;
}
/* Work through the path, component-wise */
for (; dir != NULL && *dir != '\0'; dir = next) {
if ((next = strchr(dir, '/')) != NULL)
*(next++) = '\0';
if (*dir == '\0')
continue;
subpath_len = (next == NULL) ? INT_MAX : next - odir - 1;
if (mkdirat(fd, dir, mode) == 0)
debug_f("created directory %.*s", subpath_len, target);
else if (errno != EEXIST) {
error_f("mkdir(\"%.*s\"): %s",
subpath_len, target, strerror(errno));
goto out;
}
/* descend */
if ((fd2 = openat(fd, dir, O_RDONLY|O_DIRECTORY)) == -1) {
error_f("open(\"%.*s\"): %s",
subpath_len, target, strerror(errno));
goto out;
}
if (fd != AT_FDCWD)
close(fd);
fd = fd2;
}
/* success */
ret = 0;
out:
free(odir);
if (fd != AT_FDCWD)
close(fd);
return ret;
}
+2 -1
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: misc.h,v 1.116 2026/03/11 09:10:59 dtucker Exp $ */
/* $OpenBSD: misc.h,v 1.117 2026/09/07 20:24:22 job Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -113,6 +113,7 @@ int path_absolute(const char *);
int stdfd_devnull(int, int, int);
int lib_contains_symbol(const char *, const char *);
char *get_homedir(void);
int mkdir_path(const char *, mode_t);
void sock_set_v6only(int);
+34 -1
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.c,v 1.186 2026/06/29 01:53:21 djm Exp $ */
/* $OpenBSD: sftp-client.c,v 1.187 2026/09/07 20:24:22 job Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -880,6 +880,39 @@ sftp_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
return status == SSH2_FX_OK ? 0 : -1;
}
int
sftp_mkpath(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
{
char *slash, *tmp_path;
int done;
tmp_path = xstrdup(path);
slash = tmp_path;
for (;;) {
slash += strspn(slash, "/");
slash += strcspn(slash, "/");
done = (*slash == '\0');
*slash = '\0';
if (!sftp_remote_is_dir(conn, tmp_path)) {
if (sftp_mkdir(conn, tmp_path, a, print_flag) != 0) {
free(tmp_path);
return -1;
}
}
if (done)
break;
*slash = '/';
}
free(tmp_path);
return 0;
}
int
sftp_rmdir(struct sftp_conn *conn, const char *path)
{
+4 -1
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.h,v 1.41 2026/03/03 09:57:25 dtucker Exp $ */
/* $OpenBSD: sftp-client.h,v 1.42 2026/09/07 20:24:22 job Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@@ -87,6 +87,9 @@ int sftp_rm(struct sftp_conn *, const char *);
/* Create directory 'path' */
int sftp_mkdir(struct sftp_conn *, const char *, Attrib *, int);
/* Create directory 'path' and intermediate directories as required */
int sftp_mkpath(struct sftp_conn *, const char *, Attrib *, int);
/* Remove directory 'path' */
int sftp_rmdir(struct sftp_conn *, const char *);
+18 -4
View File
@@ -1,4 +1,4 @@
.\" $OpenBSD: sftp.1,v 1.144 2024/12/06 15:12:56 djm Exp $
.\" $OpenBSD: sftp.1,v 1.145 2026/09/07 20:24:22 job Exp $
.\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
.\"
@@ -22,7 +22,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: December 6 2024 $
.Dd $Mdocdate: September 7 2026 $
.Dt SFTP 1
.Os
.Sh NAME
@@ -564,9 +564,16 @@ command.
may contain
.Xr glob 7
characters and may match multiple files.
.It Ic lmkdir Ar path
.It Xo Ic lmkdir
.Op Fl p
.Ar path
.Xc
Create local directory specified by
.Ar path .
If the
.Fl p
flag is specified create intermediate directories as required.
Do not consider it an error if the argument directory already exists.
.It Xo Ic ln
.Op Fl s
.Ar oldpath
@@ -629,9 +636,16 @@ Sort the listing by last modification time.
.It Ic lumask Ar umask
Set local umask to
.Ar umask .
.It Ic mkdir Ar path
.It Xo Ic mkdir
.Op Fl p
.Ar path
.Xc
Create remote directory specified by
.Ar path .
If the
.Fl p
flag is specified create intermediate directories as required.
Do not consider it an error if the argument directory already exists.
.It Ic progress
Toggle display of progress meter.
.It Xo Ic put
+43 -6
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: sftp.c,v 1.257 2026/06/30 02:30:19 djm Exp $ */
/* $OpenBSD: sftp.c,v 1.258 2026/09/07 20:24:22 job Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -288,12 +288,12 @@ help(void)
"help Display this help text\n"
"lcd path Change local directory to 'path'\n"
"lls [ls-options [path]] Display local directory listing\n"
"lmkdir path Create local directory\n"
"lmkdir [-p] path Create local directory\n"
"ln [-s] oldpath newpath Link remote file (-s for symlink)\n"
"lpwd Print local working directory\n"
"ls [-1afhlnrSt] [path] Display remote directory listing\n"
"lumask umask Set local umask to 'umask'\n"
"mkdir path Create remote directory\n"
"mkdir [-p] path Create remote directory\n"
"progress Toggle display of progress meter\n"
"put [-afpR] local [remote] Upload file\n"
"pwd Display remote working directory\n"
@@ -417,6 +417,30 @@ parse_getput_flags(const char *cmd, char **argv, int argc,
return optind;
}
static int
parse_mkdir_flags(const char *cmd, char **argv, int argc, int *pflag)
{
extern int opterr, optind, optopt, optreset;
int ch;
optind = optreset = 1;
opterr = 0;
*pflag = 0;
while ((ch = getopt(argc, argv, "p")) != -1) {
switch (ch) {
case 'p':
*pflag = 1;
break;
default:
error("%s: Invalid flag -%c", cmd, optopt);
return -1;
}
}
return optind;
}
static int
parse_link_flags(const char *cmd, char **argv, int argc, int *sflag)
{
@@ -1455,16 +1479,21 @@ parse_args(const char **cpp, int *ignore_errors, int *disable_echo, int *aflag,
undo_glob_escape(*path1);
undo_glob_escape(*path2);
break;
case I_RM:
case I_MKDIR:
case I_RMDIR:
case I_LMKDIR:
if ((optidx = parse_mkdir_flags(cmd, argv, argc, pflag)) == -1)
return -1;
path1_mandatory = 1;
goto parse_one_path;
case I_RM:
case I_RMDIR:
path1_mandatory = 1;
/* FALLTHROUGH */
case I_CHDIR:
case I_LCHDIR:
if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
return -1;
parse_one_path:
/* Get pathname (mandatory) */
if (argc - optidx < 1) {
if (!path1_mandatory)
@@ -1639,7 +1668,10 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
attrib_clear(&a);
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = 0777;
err = sftp_mkdir(conn, path1, &a, 1);
if (pflag)
err = sftp_mkpath(conn, path1, &a, 1);
else
err = sftp_mkdir(conn, path1, &a, 1);
break;
case I_RMDIR:
path1 = sftp_make_absolute(path1, *pwd);
@@ -1708,6 +1740,11 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
}
break;
case I_LMKDIR:
if (pflag) {
if (mkdir_path(path1, 0777) != 0)
err = 1;
break;
}
if (mkdir(path1, 0777) == -1) {
error("Couldn't create local directory "
"\"%s\": %s", path1, strerror(errno));