mirror of
https://github.com/openssh/openssh-portable.git
synced 2026-11-06 05:16:43 +00:00
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:
1 parent
327fb6ce6f
commit
d991f23d45
6 files changed
+148
-13
No files matched your search
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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 *);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,6 +1668,9 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
|
||||
attrib_clear(&a);
|
||||
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
|
||||
a.perm = 0777;
|
||||
if (pflag)
|
||||
err = sftp_mkpath(conn, path1, &a, 1);
|
||||
else
|
||||
err = sftp_mkdir(conn, path1, &a, 1);
|
||||
break;
|
||||
case I_RMDIR:
|
||||
@@ -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));
|
||||
|
||||
Reference in new issue
Block a user