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