| /* $OpenBSD: sftp-glob.c,v 1.29 2019/11/13 04:47:52 deraadt Exp $ */ |
| /* |
| * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
| * |
| * Permission to use, copy, modify, and distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| #include "includes.h" |
| |
| #include <sys/types.h> |
| #ifdef HAVE_SYS_STAT_H |
| # include <sys/stat.h> |
| #endif |
| |
| #include <dirent.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdarg.h> |
| |
| #include "xmalloc.h" |
| #include "sftp.h" |
| #include "sftp-common.h" |
| #include "sftp-client.h" |
| |
| int remote_glob(struct sftp_conn *, const char *, int, |
| int (*)(const char *, int), glob_t *); |
| |
| struct SFTP_OPENDIR { |
| SFTP_DIRENT **dir; |
| int offset; |
| }; |
| |
| static struct { |
| struct sftp_conn *conn; |
| } cur; |
| |
| static void * |
| fudge_opendir(const char *path) |
| { |
| struct SFTP_OPENDIR *r; |
| |
| r = xcalloc(1, sizeof(*r)); |
| |
| if (do_readdir(cur.conn, (char *)path, &r->dir)) { |
| free(r); |
| return(NULL); |
| } |
| |
| r->offset = 0; |
| |
| return((void *)r); |
| } |
| |
| static struct dirent * |
| fudge_readdir(struct SFTP_OPENDIR *od) |
| { |
| /* Solaris needs sizeof(dirent) + path length (see below) */ |
| static char buf[sizeof(struct dirent) + MAXPATHLEN]; |
| struct dirent *ret = (struct dirent *)buf; |
| #ifdef __GNU_LIBRARY__ |
| static int inum = 1; |
| #endif /* __GNU_LIBRARY__ */ |
| |
| if (od->dir[od->offset] == NULL) |
| return(NULL); |
| |
| memset(buf, 0, sizeof(buf)); |
| |
| /* |
| * Solaris defines dirent->d_name as a one byte array and expects |
| * you to hack around it. |
| */ |
| #ifdef BROKEN_ONE_BYTE_DIRENT_D_NAME |
| strlcpy(ret->d_name, od->dir[od->offset++]->filename, MAXPATHLEN); |
| #else |
| strlcpy(ret->d_name, od->dir[od->offset++]->filename, |
| sizeof(ret->d_name)); |
| #endif |
| #ifdef __GNU_LIBRARY__ |
| /* |
| * Idiot glibc uses extensions to struct dirent for readdir with |
| * ALTDIRFUNCs. Not that this is documented anywhere but the |
| * source... Fake an inode number to appease it. |
| */ |
| ret->d_ino = inum++; |
| if (!inum) |
| inum = 1; |
| #endif /* __GNU_LIBRARY__ */ |
| |
| return(ret); |
| } |
| |
| static void |
| fudge_closedir(struct SFTP_OPENDIR *od) |
| { |
| free_sftp_dirents(od->dir); |
| free(od); |
| } |
| |
| static int |
| fudge_lstat(const char *path, struct stat *st) |
| { |
| Attrib *a; |
| |
| if (!(a = do_lstat(cur.conn, (char *)path, 1))) |
| return(-1); |
| |
| attrib_to_stat(a, st); |
| |
| return(0); |
| } |
| |
| static int |
| fudge_stat(const char *path, struct stat *st) |
| { |
| Attrib *a; |
| |
| if (!(a = do_stat(cur.conn, (char *)path, 1))) |
| return(-1); |
| |
| attrib_to_stat(a, st); |
| |
| return(0); |
| } |
| |
| int |
| remote_glob(struct sftp_conn *conn, const char *pattern, int flags, |
| int (*errfunc)(const char *, int), glob_t *pglob) |
| { |
| pglob->gl_opendir = fudge_opendir; |
| pglob->gl_readdir = (struct dirent *(*)(void *))fudge_readdir; |
| pglob->gl_closedir = (void (*)(void *))fudge_closedir; |
| pglob->gl_lstat = fudge_lstat; |
| pglob->gl_stat = fudge_stat; |
| |
| memset(&cur, 0, sizeof(cur)); |
| cur.conn = conn; |
| |
| return(glob(pattern, flags | GLOB_ALTDIRFUNC, errfunc, pglob)); |
| } |