1/* $NetBSD: sftp-glob.c,v 1.15 2023/10/25 20:19:57 christos Exp $ */ 2/* $OpenBSD: sftp-glob.c,v 1.33 2023/09/10 23:12:32 djm Exp $ */ 3 4/* 5 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20#include "includes.h" 21__RCSID("$NetBSD: sftp-glob.c,v 1.15 2023/10/25 20:19:57 christos Exp $"); 22#include <sys/types.h> 23#include <sys/stat.h> 24 25#include <dirent.h> 26#include <glob.h> 27#include <stdlib.h> 28#include <string.h> 29#include <stdarg.h> 30 31#include "xmalloc.h" 32#include "sftp.h" 33#include "sftp-common.h" 34#include "sftp-client.h" 35 36int sftp_glob(struct sftp_conn *, const char *, int, 37 int (*)(const char *, int), glob_t *); 38 39struct SFTP_OPENDIR { 40 SFTP_DIRENT **dir; 41 int offset; 42}; 43 44static struct { 45 struct sftp_conn *conn; 46} cur; 47 48static void * 49fudge_opendir(const char *path) 50{ 51 struct SFTP_OPENDIR *r; 52 53 r = xcalloc(1, sizeof(*r)); 54 55 if (sftp_readdir(cur.conn, __UNCONST(path), &r->dir)) { 56 free(r); 57 return(NULL); 58 } 59 60 r->offset = 0; 61 62 return((void *)r); 63} 64 65static struct dirent * 66fudge_readdir(struct SFTP_OPENDIR *od) 67{ 68 static struct dirent ret; 69 70 if (od->dir[od->offset] == NULL) 71 return(NULL); 72 73 memset(&ret, 0, sizeof(ret)); 74 strlcpy(ret.d_name, od->dir[od->offset++]->filename, 75 sizeof(ret.d_name)); 76 77 return(&ret); 78} 79 80static void 81fudge_closedir(struct SFTP_OPENDIR *od) 82{ 83 sftp_free_dirents(od->dir); 84 free(od); 85} 86 87static int 88fudge_lstat(const char *path, struct stat *st) 89{ 90 Attrib a; 91 92 if (sftp_lstat(cur.conn, path, 1, &a) != 0) 93 return -1; 94 95 attrib_to_stat(&a, st); 96 97 return 0; 98} 99 100static int 101fudge_stat(const char *path, struct stat *st) 102{ 103 Attrib a; 104 105 if (sftp_stat(cur.conn, path, 1, &a) != 0) 106 return -1; 107 108 attrib_to_stat(&a, st); 109 110 return(0); 111} 112 113int 114sftp_glob(struct sftp_conn *conn, const char *pattern, int flags, 115 int (*errfunc)(const char *, int), glob_t *pglob) 116{ 117 int r; 118 size_t l; 119 char *s; 120 struct stat sb; 121 122 pglob->gl_opendir = fudge_opendir; 123 pglob->gl_readdir = (struct dirent *(*)(void *))fudge_readdir; 124 pglob->gl_closedir = (void (*)(void *))fudge_closedir; 125 pglob->gl_lstat = fudge_lstat; 126 pglob->gl_stat = fudge_stat; 127 128 memset(&cur, 0, sizeof(cur)); 129 cur.conn = conn; 130 131 if ((r = glob(pattern, flags | GLOB_ALTDIRFUNC|GLOB_LIMIT, errfunc, pglob)) != 0) 132 return r; 133 /* 134 * When both GLOB_NOCHECK and GLOB_MARK are active, a single gl_pathv 135 * entry has been returned and that entry has not already been marked, 136 * then check whether it needs a '/' appended as a directory mark. 137 * 138 * This ensures that a NOCHECK result is annotated as a directory. 139 * The glob(3) spec doesn't promise to mark NOCHECK entries, but doing 140 * it simplifies our callers (sftp/scp) considerably. 141 * 142 * XXX doesn't try to handle gl_offs. 143 */ 144 if ((flags & (GLOB_NOCHECK|GLOB_MARK)) == (GLOB_NOCHECK|GLOB_MARK) && 145 pglob->gl_matchc == 0 && pglob->gl_offs == 0 && 146 pglob->gl_pathc == 1 && (s = pglob->gl_pathv[0]) != NULL && 147 (l = strlen(s)) > 0 && s[l-1] != '/') { 148 if (fudge_stat(s, &sb) == 0 && S_ISDIR(sb.st_mode)) { 149 /* NOCHECK on a directory; annotate */ 150 if ((s = realloc(s, l + 2)) != NULL) { 151 memcpy(s + l, "/", 2); 152 pglob->gl_pathv[0] = s; 153 } 154 } 155 } 156 return 0; 157} 158