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 #pragma ident "%Z%%M% %I% %E% SMI" 20 21 #include "includes.h" 22 23 #include <sys/types.h> 24 #ifdef HAVE_SYS_STAT_H 25 # include <sys/stat.h> 26 #endif 27 28 #include <dirent.h> 29 #include <string.h> 30 31 #include "xmalloc.h" 32 #include "sftp.h" 33 #include "buffer.h" 34 #include "sftp-common.h" 35 #include "sftp-client.h" 36 37 int remote_glob(struct sftp_conn *, const char *, int, 38 int (*)(const char *, int), glob_t *); 39 40 struct SFTP_OPENDIR { 41 SFTP_DIRENT **dir; 42 int offset; 43 }; 44 45 static struct { 46 struct sftp_conn *conn; 47 } cur; 48 49 static void * 50 fudge_opendir(const char *path) 51 { 52 struct SFTP_OPENDIR *r; 53 54 r = xmalloc(sizeof(*r)); 55 56 if (do_readdir(cur.conn, (char *)path, &r->dir)) { 57 xfree(r); 58 return(NULL); 59 } 60 61 r->offset = 0; 62 63 return((void *)r); 64 } 65 66 static struct dirent * 67 fudge_readdir(struct SFTP_OPENDIR *od) 68 { 69 /* Solaris needs sizeof(dirent) + path length (see below) */ 70 static union { 71 char buf_chars[sizeof (struct dirent) + MAXPATHLEN]; 72 struct dirent buf_dirent; 73 } buf; 74 struct dirent *ret = &buf.buf_dirent; 75 #ifdef __GNU_LIBRARY__ 76 static int inum = 1; 77 #endif /* __GNU_LIBRARY__ */ 78 79 if (od->dir[od->offset] == NULL) 80 return(NULL); 81 82 memset(buf.buf_chars, 0, sizeof (buf.buf_chars)); 83 84 /* 85 * Solaris defines dirent->d_name as a one byte array and expects 86 * you to hack around it. 87 */ 88 #ifdef BROKEN_ONE_BYTE_DIRENT_D_NAME 89 strlcpy(ret->d_name, od->dir[od->offset++]->filename, MAXPATHLEN); 90 #else 91 strlcpy(ret->d_name, od->dir[od->offset++]->filename, 92 sizeof(ret->d_name)); 93 #endif 94 #ifdef __GNU_LIBRARY__ 95 /* 96 * Idiot glibc uses extensions to struct dirent for readdir with 97 * ALTDIRFUNCs. Not that this is documented anywhere but the 98 * source... Fake an inode number to appease it. 99 */ 100 ret->d_ino = inum++; 101 if (!inum) 102 inum = 1; 103 #endif /* __GNU_LIBRARY__ */ 104 105 return(ret); 106 } 107 108 static void 109 fudge_closedir(struct SFTP_OPENDIR *od) 110 { 111 free_sftp_dirents(od->dir); 112 xfree(od); 113 } 114 115 static int 116 fudge_lstat(const char *path, struct stat *st) 117 { 118 Attrib *a; 119 120 if (!(a = do_lstat(cur.conn, (char *)path, 0))) 121 return(-1); 122 123 attrib_to_stat(a, st); 124 125 return(0); 126 } 127 128 static int 129 fudge_stat(const char *path, struct stat *st) 130 { 131 Attrib *a; 132 133 if (!(a = do_stat(cur.conn, (char *)path, 0))) 134 return(-1); 135 136 attrib_to_stat(a, st); 137 138 return(0); 139 } 140 141 int 142 remote_glob(struct sftp_conn *conn, const char *pattern, int flags, 143 int (*errfunc)(const char *, int), glob_t *pglob) 144 { 145 pglob->gl_opendir = fudge_opendir; 146 pglob->gl_readdir = (struct dirent *(*)(void *))fudge_readdir; 147 pglob->gl_closedir = (void (*)(void *))fudge_closedir; 148 pglob->gl_lstat = fudge_lstat; 149 pglob->gl_stat = fudge_stat; 150 151 memset(&cur, 0, sizeof(cur)); 152 cur.conn = conn; 153 154 return(glob(pattern, flags | GLOB_ALTDIRFUNC, errfunc, pglob)); 155 } 156