1 /* 2 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* $OpenBSD: sftp-glob.c,v 1.22 2006/08/03 03:34:42 deraadt Exp $ */ 18 19 #include "includes.h" 20 21 #include <sys/types.h> 22 #ifdef HAVE_SYS_STAT_H 23 # include <sys/stat.h> 24 #endif 25 26 #include <dirent.h> 27 #include <string.h> 28 29 #include "xmalloc.h" 30 #include "sftp.h" 31 #include "buffer.h" 32 #include "sftp-common.h" 33 #include "sftp-client.h" 34 35 int remote_glob(struct sftp_conn *, const char *, int, 36 int (*)(const char *, int), glob_t *); 37 38 struct SFTP_OPENDIR { 39 SFTP_DIRENT **dir; 40 int offset; 41 }; 42 43 static struct { 44 struct sftp_conn *conn; 45 } cur; 46 47 static void * 48 fudge_opendir(const char *path) 49 { 50 struct SFTP_OPENDIR *r; 51 52 r = xmalloc(sizeof(*r)); 53 54 if (do_readdir(cur.conn, (char *)path, &r->dir)) { 55 xfree(r); 56 return(NULL); 57 } 58 59 r->offset = 0; 60 61 return((void *)r); 62 } 63 64 static struct dirent * 65 fudge_readdir(struct SFTP_OPENDIR *od) 66 { 67 /* Solaris needs sizeof(dirent) + path length (see below) */ 68 static union { 69 char buf_chars[sizeof (struct dirent) + MAXPATHLEN]; 70 struct dirent buf_dirent; 71 } buf; 72 struct dirent *ret = &buf.buf_dirent; 73 #ifdef __GNU_LIBRARY__ 74 static int inum = 1; 75 #endif /* __GNU_LIBRARY__ */ 76 77 if (od->dir[od->offset] == NULL) 78 return(NULL); 79 80 memset(buf.buf_chars, 0, sizeof (buf.buf_chars)); 81 82 /* 83 * Solaris defines dirent->d_name as a one byte array and expects 84 * you to hack around it. 85 */ 86 #ifdef BROKEN_ONE_BYTE_DIRENT_D_NAME 87 strlcpy(ret->d_name, od->dir[od->offset++]->filename, MAXPATHLEN); 88 #else 89 strlcpy(ret->d_name, od->dir[od->offset++]->filename, 90 sizeof(ret->d_name)); 91 #endif 92 #ifdef __GNU_LIBRARY__ 93 /* 94 * Idiot glibc uses extensions to struct dirent for readdir with 95 * ALTDIRFUNCs. Not that this is documented anywhere but the 96 * source... Fake an inode number to appease it. 97 */ 98 ret->d_ino = inum++; 99 if (!inum) 100 inum = 1; 101 #endif /* __GNU_LIBRARY__ */ 102 103 return(ret); 104 } 105 106 static void 107 fudge_closedir(struct SFTP_OPENDIR *od) 108 { 109 free_sftp_dirents(od->dir); 110 xfree(od); 111 } 112 113 static int 114 fudge_lstat(const char *path, struct stat *st) 115 { 116 Attrib *a; 117 118 if (!(a = do_lstat(cur.conn, (char *)path, 0))) 119 return(-1); 120 121 attrib_to_stat(a, st); 122 123 return(0); 124 } 125 126 static int 127 fudge_stat(const char *path, struct stat *st) 128 { 129 Attrib *a; 130 131 if (!(a = do_stat(cur.conn, (char *)path, 0))) 132 return(-1); 133 134 attrib_to_stat(a, st); 135 136 return(0); 137 } 138 139 int 140 remote_glob(struct sftp_conn *conn, const char *pattern, int flags, 141 int (*errfunc)(const char *, int), glob_t *pglob) 142 { 143 pglob->gl_opendir = fudge_opendir; 144 pglob->gl_readdir = (struct dirent *(*)(void *))fudge_readdir; 145 pglob->gl_closedir = (void (*)(void *))fudge_closedir; 146 pglob->gl_lstat = fudge_lstat; 147 pglob->gl_stat = fudge_stat; 148 149 memset(&cur, 0, sizeof(cur)); 150 cur.conn = conn; 151 152 return(glob(pattern, flags|GLOB_LIMIT|GLOB_ALTDIRFUNC, errfunc, pglob)); 153 }