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 (at) 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 36 int sftp_glob(struct sftp_conn *, const char *, int, 37 int (*)(const char *, int), glob_t *); 38 39 struct SFTP_OPENDIR { 40 SFTP_DIRENT **dir; 41 int offset; 42 }; 43 44 static struct { 45 struct sftp_conn *conn; 46 } cur; 47 48 static void * 49 fudge_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 65 static struct dirent * 66 fudge_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 80 static void 81 fudge_closedir(struct SFTP_OPENDIR *od) 82 { 83 sftp_free_dirents(od->dir); 84 free(od); 85 } 86 87 static int 88 fudge_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 100 static int 101 fudge_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 113 int 114 sftp_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