diff options
author | Derrell Lipman <derrell@samba.org> | 2005-03-29 00:42:51 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 10:56:22 -0500 |
commit | fbc611f431db443c23486f768ca5e2bc4db95c24 (patch) | |
tree | eda7acba80812fe7fce924e9bbdbfa9dc971942d /examples/libsmbclient/smbwrapper | |
parent | fa787af52093e14de4a472d2ccb50b9ec66b10d1 (diff) | |
download | samba-fbc611f431db443c23486f768ca5e2bc4db95c24.tar.gz samba-fbc611f431db443c23486f768ca5e2bc4db95c24.tar.bz2 samba-fbc611f431db443c23486f768ca5e2bc4db95c24.zip |
r6108: Added smbsh/smbwrapper for Linux to example/libsmbclient tree; provided more complete libsmbclient testbrowse utility
(This used to be commit 15736b97c837a16d9c009b8bff18b31429ccbe83)
Diffstat (limited to 'examples/libsmbclient/smbwrapper')
-rw-r--r-- | examples/libsmbclient/smbwrapper/Makefile | 35 | ||||
-rw-r--r-- | examples/libsmbclient/smbwrapper/README | 40 | ||||
-rw-r--r-- | examples/libsmbclient/smbwrapper/opendir_smbsh.c | 47 | ||||
-rw-r--r-- | examples/libsmbclient/smbwrapper/select.c | 124 | ||||
-rw-r--r-- | examples/libsmbclient/smbwrapper/smbsh.c | 160 | ||||
-rw-r--r-- | examples/libsmbclient/smbwrapper/smbw.c | 910 | ||||
-rw-r--r-- | examples/libsmbclient/smbwrapper/smbw.h | 163 | ||||
-rw-r--r-- | examples/libsmbclient/smbwrapper/smbw_dir.c | 355 | ||||
-rw-r--r-- | examples/libsmbclient/smbwrapper/smbw_stat.c | 146 | ||||
-rw-r--r-- | examples/libsmbclient/smbwrapper/wrapper.c | 1729 | ||||
-rw-r--r-- | examples/libsmbclient/smbwrapper/wrapper.h | 209 |
11 files changed, 3918 insertions, 0 deletions
diff --git a/examples/libsmbclient/smbwrapper/Makefile b/examples/libsmbclient/smbwrapper/Makefile new file mode 100644 index 0000000000..099c204986 --- /dev/null +++ b/examples/libsmbclient/smbwrapper/Makefile @@ -0,0 +1,35 @@ +LIBS = -lsmbclient -ldl +DEFS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE + +CFLAGS = -I$(SAMBA_INCL) $(EXTLIB_INCL) + +LDFLAGS = -L/usr/lib + +SMBINCLUDE = -I../../../source/include +CFLAGS= -fpic -g -O0 $(DEFS) $(SMBINCLUDE) + +BIN = . + +SMBWRAPPER_OBJS = smbw.o smbw_dir.o smbw_stat.o wrapper.o select.o +SMBSH_OBJS = smbsh.o + +all: $(BIN)/smbwrapper.so $(BIN)/smbsh + +$(BIN)/smbwrapper.so: $(SMBWRAPPER_OBJS) + $(CC) -g \ + -Wl,-init=smbw_initialize \ + -shared \ + --export-all-symbols \ + -o $(BIN)/smbwrapper.so \ + $(SMBWRAPPER_OBJS) \ + $(LIBS) \ + -Wl,-soname=`basename $@` + +$(BIN)/smbsh: $(SMBSH_OBJS) + $(CC) -g -o $(BIN)/smbsh $(SMBSH_OBJS) $(LIBS) + +opendir_smbsh: opendir_smbsh.o + $(CC) -g -o opendir_smbsh opendir_smbsh.o $(LIBS) $(DMALLOC) + +clean: + rm -f *.o *~ opendir_smbsh smbsh smbwrapper.so diff --git a/examples/libsmbclient/smbwrapper/README b/examples/libsmbclient/smbwrapper/README new file mode 100644 index 0000000000..7b71ec06ba --- /dev/null +++ b/examples/libsmbclient/smbwrapper/README @@ -0,0 +1,40 @@ +To create "smbsh" on Linux, just type "make". + +If you execute "smbsh" in *this* directory (so that it can find the required +shared library), you'll find yourself in a new shell. You can then issue +commands referencing the "/smb" pseudo-filesystem: + + ls /smb + ls /smb/WORKGROUP_OR_DOMAIN + ls /smb/SERVER + ls /smb/SERVER/SHARE + ls /smb/SERVER/SHARE/PATH + +Note that WORKGROUP_OR_DOMAIN is *not* used other than at that level. This is +consistent with the smb:// URI definition. + +Usage: + smbsh [-L <path to find smbwrapper.so>] + [-p <library to load before smbwrapper.so>] + [-a <library to load after smbwrapper.so>] + [-d <debug value for libsmbclient>] + [-n] (do not ask for username/password) + [-W <workgroup>] + [-U <username%password] + [command] + +So to list the contents of \\MYDESK\C$ where a username (adventure) and password +(xyzzy) are required, and with smbwrapper.so installed in /usr/share/samba, you +could try: + + smbsh -L /usr/share/samba -U adventure%xyzzy ls '/smb/MYDESK/C$' + +(It's a good idea to get in the habit of surrounding windows paths in single +quotes, since they often contain spaces and other characters that'll give you +headaches when not escaped.) + +This smbsh seems to work quite well on Linux 2.4 and 2.6. The biggest problem it +has is in tracking your current working directory. I haven't had the time to +track that down and fix it. + +Derrell Lipman diff --git a/examples/libsmbclient/smbwrapper/opendir_smbsh.c b/examples/libsmbclient/smbwrapper/opendir_smbsh.c new file mode 100644 index 0000000000..275b95f8ea --- /dev/null +++ b/examples/libsmbclient/smbwrapper/opendir_smbsh.c @@ -0,0 +1,47 @@ +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <libsmbclient.h> + +int +main(int argc, char * argv[]) +{ + char * p; + char buf[1024]; + DIR * dir; + struct dirent * dirent; + + setbuf(stdout, NULL); + + for (fputs("path: ", stdout), p = fgets(buf, sizeof(buf), stdin); + p != NULL && *p != '\n' && *p != '\0'; + fputs("path: ", stdout), p = fgets(buf, sizeof(buf), stdin)) + { + if ((p = strchr(buf, '\n')) != NULL) + { + *p = '\0'; + } + + printf("Opening (%s)...\n", buf); + + if ((dir = opendir(buf)) == NULL) + { + printf("Could not open directory [%s]: \n", + buf, strerror(errno)); + continue; + } + + while ((dirent = readdir(dir)) != NULL) + { + printf("%-30s", dirent->d_name); + printf("%-30s", dirent->d_name + strlen(dirent->d_name) + 1); + printf("\n"); + } + + closedir(dir); + } + + exit(0); +} diff --git a/examples/libsmbclient/smbwrapper/select.c b/examples/libsmbclient/smbwrapper/select.c new file mode 100644 index 0000000000..aa90169ee7 --- /dev/null +++ b/examples/libsmbclient/smbwrapper/select.c @@ -0,0 +1,124 @@ +/* + Unix SMB/Netbios implementation. + Version 3.0 + Samba select/poll implementation + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Derrell Lipman 2003-2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * WHY THIS FILE? + * + * This file implements the two functions in the select() family, as required + * by samba. The samba native functions, though, implement a pipe to help + * alleviate a deadlock problem, but which creates problems of its own (the + * timeout stops working correctly). Those functions also require that all + * signal handlers call a function which writes to the pipe -- a task which is + * difficult to do in the smbwrapper environment. + */ + + +#include <sys/select.h> +#include <errno.h> +#include <stdio.h> + +int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval) +{ + int ret; + fd_set *readfds2, readfds_buf; + + /* If readfds is NULL we need to provide our own set. */ + if (readfds) { + readfds2 = readfds; + } else { + readfds2 = &readfds_buf; + FD_ZERO(readfds2); + } + + errno = 0; + ret = select(maxfd,readfds2,writefds,errorfds,tval); + + if (ret <= 0) { + FD_ZERO(readfds2); + if (writefds) + FD_ZERO(writefds); + if (errorfds) + FD_ZERO(errorfds); + } + + return ret; +} + +/******************************************************************* + Similar to sys_select() but catch EINTR and continue. + This is what sys_select() used to do in Samba. +********************************************************************/ + +int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval) +{ + int ret; + fd_set *readfds2, readfds_buf, *writefds2, writefds_buf, *errorfds2, errorfds_buf; + struct timeval tval2, *ptval, end_time, now_time; + extern void GetTimeOfDay(struct timeval *tval); + + readfds2 = (readfds ? &readfds_buf : NULL); + writefds2 = (writefds ? &writefds_buf : NULL); + errorfds2 = (errorfds ? &errorfds_buf : NULL); + if (tval) { + GetTimeOfDay(&end_time); + end_time.tv_sec += tval->tv_sec; + end_time.tv_usec += tval->tv_usec; + end_time.tv_sec += end_time.tv_usec / 1000000; + end_time.tv_usec %= 1000000; + ptval = &tval2; + } else { + ptval = NULL; + } + + do { + if (readfds) + readfds_buf = *readfds; + if (writefds) + writefds_buf = *writefds; + if (errorfds) + errorfds_buf = *errorfds; + if (tval) { + GetTimeOfDay(&now_time); + tval2.tv_sec = end_time.tv_sec - now_time.tv_sec; + tval2.tv_usec = end_time.tv_usec - now_time.tv_usec; + if ((signed long) tval2.tv_usec < 0) { + tval2.tv_usec += 1000000; + tval2.tv_sec--; + } + if ((signed long) tval2.tv_sec < 0) { + ret = 0; + break; /* time has already elapsed */ + } + } + + ret = sys_select(maxfd, readfds2, writefds2, errorfds2, ptval); + } while (ret == -1 && errno == EINTR); + + if (readfds) + *readfds = readfds_buf; + if (writefds) + *writefds = writefds_buf; + if (errorfds) + *errorfds = errorfds_buf; + + return ret; +} diff --git a/examples/libsmbclient/smbwrapper/smbsh.c b/examples/libsmbclient/smbwrapper/smbsh.c new file mode 100644 index 0000000000..7b33de766f --- /dev/null +++ b/examples/libsmbclient/smbwrapper/smbsh.c @@ -0,0 +1,160 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + SMB wrapper functions - frontend + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Derrell Lipman 2003-2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <string.h> +#include <libsmbclient.h> + +#ifndef FALSE +# define FALSE (0) +# define TRUE (! FALSE) +#endif + +static void smbsh_usage(void) +{ + printf("smbsh [options] [command [args] ...]\n\n"); + printf(" -p prepend library name\n"); + printf(" -a append library name\n"); + printf(" -n"); + printf(" -W workgroup\n"); + printf(" -U username\n"); + printf(" -P prefix\n"); + printf(" -R resolve order\n"); + printf(" -d debug level\n"); + printf(" -l logfile\n"); + printf(" -L libdir\n"); + exit(0); +} + +int main(int argc, char *argv[]) +{ + char *p, *u; + char *libd = "."; + char line[PATH_MAX], pre[PATH_MAX], post[PATH_MAX]; + int opt; + int no_ask = 0; + struct stat statbuf; + extern char *optarg; + extern int optind; + + *pre = *post = '\0'; + + while ((opt = getopt(argc, argv, "p:a:d:nL:W:U:h")) != -1) { + switch (opt) { + case 'p': /* prepend library before smbwrapper.so */ + if (*pre != '\0') + strncat(pre, " ", PATH_MAX - strlen(pre)); + strncat(pre, optarg, PATH_MAX - strlen(pre)); + break; + + case 'a': /* append library after smbwrapper.so */ + strncat(post, " ", PATH_MAX - strlen(post)); + strncat(post, optarg, PATH_MAX - strlen(post)); + break; + + case 'd': + setenv("DEBUG", optarg, TRUE); + break; + + case 'n': /* don't ask for username/password */ + no_ask++; + break; + + case 'L': + libd = optarg; + break; + + case 'W': + setenv("WORKGROUP", optarg, TRUE); + break; + + case 'U': + p = strchr(optarg,'%'); + if (p) { + *p=0; + setenv("PASSWORD", p+1, TRUE); + } + setenv("USER", optarg, TRUE); + break; + + case 'h': + default: + smbsh_usage(); + } + } + + + if (! no_ask) { + if (!getenv("USER")) { + printf("Username: "); + u = fgets(line, sizeof(line)-1, stdin); + setenv("USER", u, TRUE); + } + + if (!getenv("PASSWORD")) { + p = getpass("Password: "); + setenv("PASSWORD", p, TRUE); + } + } + + strncpy(line, pre, PATH_MAX - strlen(line)); + strncat(line, " ", PATH_MAX - strlen(line)); + strncat(line, libd, PATH_MAX - strlen(line)); + strncat(line, "/smbwrapper.so", PATH_MAX - strlen(line)); + strncat(line, post, PATH_MAX - strlen(line)); + setenv("LD_PRELOAD", line, TRUE); + setenv("LD_BIND_NOW", "true", TRUE); + + snprintf(line,sizeof(line)-1,"%s/smbwrapper.32.so", libd); + + if (stat(line, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) { + snprintf(line,sizeof(line)-1,"%s/smbwrapper.32.so:DEFAULT", libd); + setenv("_RLD_LIST", line, TRUE); + snprintf(line,sizeof(line)-1,"%s/smbwrapper.so:DEFAULT", libd); + setenv("_RLDN32_LIST", line, TRUE); + } else { + snprintf(line,sizeof(line)-1,"%s/smbwrapper.so:DEFAULT", libd); + setenv("_RLD_LIST", line, TRUE); + } + + if (optind < argc) { + execvp(argv[optind], &argv[optind]); + } else { + char *shellpath = getenv("SHELL"); + + setenv("PS1", "smbsh$ ", TRUE); + + if(shellpath) { + execl(shellpath,"smbsh", NULL); + } else { + setenv("SHELL", "/bin/sh", TRUE); + execl("/bin/sh", "smbsh", NULL); + } + } + printf("launch failed!\n"); + return 1; +} diff --git a/examples/libsmbclient/smbwrapper/smbw.c b/examples/libsmbclient/smbwrapper/smbw.c new file mode 100644 index 0000000000..d2f1c18695 --- /dev/null +++ b/examples/libsmbclient/smbwrapper/smbw.c @@ -0,0 +1,910 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + SMB wrapper functions + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Derrell Lipman 2003-2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdarg.h> +#include <assert.h> +#include "smbw.h" + +int smbw_fd_map[__FD_SETSIZE]; +int smbw_ref_count[__FD_SETSIZE]; +char smbw_cwd[PATH_MAX]; +char smbw_prefix[] = SMBW_PREFIX; + +/* needs to be here because of dumb include files on some systems */ +int creat_bits = O_WRONLY|O_CREAT|O_TRUNC; + +int smbw_initialized = 0; + +static int debug_level = 0; + +static SMBCCTX *smbw_ctx; + +extern int smbw_debug; + + +int smbw_ref(int client_fd, Ref_Count_Type type, ...) +{ + va_list ap; + + /* client id values begin at SMBC_BASE_FC. */ + client_fd -= SMBC_BASE_FD; + + va_start(ap, type); + switch(type) + { + case SMBW_RCT_Increment: + return ++smbw_ref_count[client_fd]; + + case SMBW_RCT_Decrement: + return --smbw_ref_count[client_fd]; + + case SMBW_RCT_Get: + return smbw_ref_count[client_fd]; + + case SMBW_RCT_Set: + return (smbw_ref_count[client_fd] = va_arg(ap, int)); + } + va_end(ap); + + /* never gets here */ + return -1; +} + + +/* + * Return a username and password given a server and share name + * + * Returns 0 upon success; + * non-zero otherwise, and errno is set to indicate the error. + */ +static void get_envvar_auth_data(const char *srv, + const char *shr, + char *wg, int wglen, + char *un, int unlen, + char *pw, int pwlen) +{ + char *u; + char *p; + char *w; + + /* Fall back to environment variables */ + + w = getenv("WORKGROUP"); + if (w == NULL) w = ""; + + u = getenv("USER"); + if (u == NULL) u = ""; + + p = getenv("PASSWORD"); + if (p == NULL) p = ""; + + strncpy(wg, w, wglen); + strncpy(un, u, unlen); + strncpy(pw, p, pwlen); +} + +static smbc_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data; + +/***************************************************** +set the get auth data function +******************************************************/ +void smbw_set_auth_data_fn(smbc_get_auth_data_fn fn) +{ + get_auth_data_fn = fn; +} + + +/***************************************************** +ensure that all connections are terminated upon exit +******************************************************/ +static void do_shutdown(void) +{ + if (smbw_ctx != NULL) { + smbc_free_context(smbw_ctx, 1); + } +} + + +/***************************************************** +initialise structures +*******************************************************/ +static void do_init(int is_real_startup) +{ + int i; + char *p; + + smbw_initialized = 1; /* this must be first to avoid recursion! */ + + smbw_ctx = NULL; /* don't free context until it's established */ + + /* initially, no file descriptors are mapped */ + for (i = 0; i < __FD_SETSIZE; i++) { + smbw_fd_map[i] = -1; + smbw_ref_count[i] = 0; + } + + /* See if we've been told to start in a particular directory */ + if ((p=getenv("SMBW_DIR")) != NULL) { + strncpy(smbw_cwd, p, PATH_MAX); + + /* we don't want the old directory to be busy */ + (* smbw_libc.chdir)("/"); + + } else { + *smbw_cwd = '\0'; + } + + if ((p=getenv("DEBUG"))) { + debug_level = atoi(p); + } + + if ((smbw_ctx = smbc_new_context()) == NULL) { + exit(1); + } + + smbw_ctx->debug = debug_level; + smbw_ctx->callbacks.auth_fn = get_auth_data_fn; + smbw_ctx->options.browse_max_lmb_count = 0; + smbw_ctx->options.urlencode_readdir_entries = 1; + smbw_ctx->options.one_share_per_server = 1; +// smbw_cache_functions(smbw_ctx); + + if (smbc_init_context(smbw_ctx) == NULL) { + exit(1); + } + + smbc_set_context(smbw_ctx); + + /* if not real startup, exit handler has already been established */ + if (is_real_startup) { + atexit(do_shutdown); + } +} + +/***************************************************** +initialise structures, real start up vs a fork() +*******************************************************/ +void smbw_init(void) +{ + do_init(1); +} + + +/***************************************************** +determine if a file descriptor is a smb one +*******************************************************/ +int smbw_fd(int smbw_fd) +{ + SMBW_INIT(); + + return (smbw_fd >= 0 && + smbw_fd < __FD_SETSIZE && + smbw_fd_map[smbw_fd] >= SMBC_BASE_FD); /* minimum smbc_ fd */ +} + + +/***************************************************** +determine if a path is a smb one +*******************************************************/ +int smbw_path(const char *name) +{ + int len; + int ret; + int saved_errno; + + saved_errno = errno; + + SMBW_INIT(); + + len = strlen(smbw_prefix); + + ret = ((strncmp(name, smbw_prefix, len) == 0 && + (name[len] == '\0' || name[len] == '/')) || + (*name != '/' && *smbw_cwd != '\0')); + + errno = saved_errno; + return ret; +} + + +/***************************************************** +remove redundent stuff from a filename +*******************************************************/ +void smbw_clean_fname(char *name) +{ + char *p, *p2; + int l; + int modified = 1; + + if (!name) return; + + DEBUG(10, ("Clean [%s]...\n", name)); + + while (modified) { + modified = 0; + + if ((p=strstr(name,"/./"))) { + modified = 1; + while (*p) { + p[0] = p[2]; + p++; + } + DEBUG(10, ("\tclean 1 (/./) produced [%s]\n", name)); + } + + if ((p=strstr(name,"//"))) { + modified = 1; + while (*p) { + p[0] = p[1]; + p++; + } + DEBUG(10, ("\tclean 2 (//) produced [%s]\n", name)); + } + + if (strcmp(name,"/../")==0) { + modified = 1; + name[1] = 0; + DEBUG(10,("\tclean 3 (^/../$) produced [%s]\n", name)); + } + + if ((p=strstr(name,"/../"))) { + modified = 1; + for (p2 = (p > name ? p-1 : p); p2 > name; p2--) { + if (p2[0] == '/') break; + } + if (p2 > name) p2++; + while (*p2) { + p2[0] = p[3]; + p2++; + p++; + } + DEBUG(10, ("\tclean 4 (/../) produced [%s]\n", name)); + } + + if (strcmp(name,"/..")==0) { + modified = 1; + name[1] = 0; + DEBUG(10, ("\tclean 5 (^/..$) produced [%s]\n", name)); + } + + l = strlen(name); + p = l>=3?(name+l-3):name; + if (strcmp(p,"/..")==0) { + modified = 1; + for (p2=p-1;p2>name;p2--) { + if (p2[0] == '/') break; + } + if (p2==name) { + p[0] = '/'; + p[1] = 0; + } else { + p2[0] = 0; + } + DEBUG(10, ("\tclean 6 (/..) produced [%s]\n", name)); + } + + l = strlen(name); + p = l>=2?(name+l-2):name; + if (strcmp(p,"/.")==0) { + modified = 1; + if (p == name) { + p[1] = 0; + } else { + p[0] = 0; + } + DEBUG(10, ("\tclean 7 (/.) produced [%s]\n", name)); + } + + if (strncmp(p=name,"./",2) == 0) { + modified = 1; + do { + p[0] = p[2]; + } while (*p++); + DEBUG(10, ("\tclean 8 (^./) produced [%s]\n", name)); + } + + l = strlen(p=name); + if (l > 1 && p[l-1] == '/') { + modified = 1; + p[l-1] = 0; + DEBUG(10, ("\tclean 9 (/) produced [%s]\n", name)); + } + } +} + +void smbw_fix_path(const char *src, char *dest) +{ + const char *p; + int len = strlen(smbw_prefix); + + if (*src == '/') { + for (p = src + len; *p == '/'; p++) + ; + snprintf(dest, PATH_MAX, "smb://%s", p); + } else { + snprintf(dest, PATH_MAX, "%s/%s", smbw_cwd, src); + } + + smbw_clean_fname(dest + 5); + + DEBUG(10, ("smbw_fix_path(%s) returning [%s]\n", src, dest)); +} + + + +/***************************************************** +a wrapper for open() +*******************************************************/ +int smbw_open(const char *fname, int flags, mode_t mode) +{ + int client_fd; + int smbw_fd; + char path[PATH_MAX]; + + SMBW_INIT(); + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_fd = (smbw_libc.open)(SMBW_DUMMY, O_WRONLY, 0200); + if (smbw_fd == -1) { + errno = EMFILE; + return -1; + } + + smbw_fix_path(fname, path); + if (flags == creat_bits) { + client_fd = smbc_creat(path, mode); + } else { + client_fd = smbc_open(path, flags, mode); + } + + if (client_fd < 0) { + (* smbw_libc.close)(smbw_fd); + return -1; + } + + smbw_fd_map[smbw_fd] = client_fd; + smbw_ref(client_fd, SMBW_RCT_Increment); + return smbw_fd; +} + + +/***************************************************** +a wrapper for pread() + +there should really be an smbc_pread() to avoid the two +lseek()s required in this kludge. +*******************************************************/ +ssize_t smbw_pread(int smbw_fd, void *buf, size_t count, SMBW_OFF_T ofs) +{ + int client_fd; + ssize_t ret; + int saved_errno; + SMBW_OFF_T old_ofs; + + client_fd = smbw_fd_map[smbw_fd]; + + if ((old_ofs = smbc_lseek(client_fd, 0, SEEK_CUR)) < 0 || + smbc_lseek(client_fd, ofs, SEEK_SET) < 0) { + return -1; + } + + if ((ret = smbc_read(client_fd, buf, count)) < 0) { + saved_errno = errno; + (void) smbc_lseek(client_fd, old_ofs, SEEK_SET); + errno = saved_errno; + return -1; + } + + return ret; +} + +/***************************************************** +a wrapper for read() +*******************************************************/ +ssize_t smbw_read(int smbw_fd, void *buf, size_t count) +{ + int client_fd; + + client_fd = smbw_fd_map[smbw_fd]; + + return smbc_read(client_fd, buf, count); +} + + + +/***************************************************** +a wrapper for write() +*******************************************************/ +ssize_t smbw_write(int smbw_fd, void *buf, size_t count) +{ + int client_fd; + + client_fd = smbw_fd_map[smbw_fd]; + + return smbc_write(client_fd, buf, count); +} + +/***************************************************** +a wrapper for pwrite() +*******************************************************/ +ssize_t smbw_pwrite(int smbw_fd, void *buf, size_t count, SMBW_OFF_T ofs) +{ + int saved_errno; + int client_fd; + ssize_t ret; + SMBW_OFF_T old_ofs; + + client_fd = smbw_fd_map[smbw_fd]; + + if ((old_ofs = smbc_lseek(client_fd, 0, SEEK_CUR)) < 0 || + smbc_lseek(client_fd, ofs, SEEK_SET) < 0) { + return -1; + } + + if ((ret = smbc_write(client_fd, buf, count)) < 0) { + saved_errno = errno; + (void) smbc_lseek(client_fd, old_ofs, SEEK_SET); + errno = saved_errno; + return -1; + } + + return ret; +} + +/***************************************************** +a wrapper for close() +*******************************************************/ +int smbw_close(int smbw_fd) +{ + int client_fd; + + client_fd = smbw_fd_map[smbw_fd]; + + if (smbw_ref(client_fd, SMBW_RCT_Decrement) > 0) { + return 0; + } + + (* smbw_libc.close)(smbw_fd); + smbw_fd_map[smbw_fd] = -1; + return smbc_close(client_fd); +} + + +/***************************************************** +a wrapper for fcntl() +*******************************************************/ +int smbw_fcntl(int smbw_fd, int cmd, long arg) +{ + return 0; +} + + +/***************************************************** +a wrapper for access() +*******************************************************/ +int smbw_access(const char *name, int mode) +{ + struct SMBW_stat st; + + SMBW_INIT(); + + if (smbw_stat(name, &st)) return -1; + + if (((mode & R_OK) && !(st.s_mode & S_IRUSR)) || + ((mode & W_OK) && !(st.s_mode & S_IWUSR)) || + ((mode & X_OK) && !(st.s_mode & S_IXUSR))) { + errno = EACCES; + return -1; + } + + return 0; +} + +/***************************************************** +a wrapper for readlink() - needed for correct errno setting +*******************************************************/ +int smbw_readlink(const char *fname, char *buf, size_t bufsize) +{ + struct SMBW_stat st; + int ret; + + SMBW_INIT(); + + ret = smbw_stat(fname, &st); + if (ret != 0) { + return -1; + } + + /* it exists - say it isn't a link */ + errno = EINVAL; + return -1; +} + + +/***************************************************** +a wrapper for unlink() +*******************************************************/ +int smbw_unlink(const char *fname) +{ + char path[PATH_MAX]; + + SMBW_INIT(); + + smbw_fix_path(fname, path); + return smbc_unlink(path); +} + + +/***************************************************** +a wrapper for rename() +*******************************************************/ +int smbw_rename(const char *oldname, const char *newname) +{ + char path_old[PATH_MAX]; + char path_new[PATH_MAX]; + + SMBW_INIT(); + + smbw_fix_path(oldname, path_old); + smbw_fix_path(newname, path_new); + return smbc_rename(path_old, path_new); +} + + +/***************************************************** +a wrapper for utimes +*******************************************************/ +int smbw_utimes(const char *fname, void *buf) +{ + char path[PATH_MAX]; + + smbw_fix_path(fname, path); + return smbc_utimes(path, buf); +} + + +/***************************************************** +a wrapper for utime +*******************************************************/ +int smbw_utime(const char *fname, void *buf) +{ + char path[PATH_MAX]; + + smbw_fix_path(fname, path); + return smbc_utime(path, buf); +} + +/***************************************************** +a wrapper for chown() +*******************************************************/ +int smbw_chown(const char *fname, uid_t owner, gid_t group) +{ + /* always indiciate that this is not supported. */ + errno = ENOTSUP; + return -1; +} + +/***************************************************** +a wrapper for chmod() +*******************************************************/ +int smbw_chmod(const char *fname, mode_t newmode) +{ + char path[PATH_MAX]; + + smbw_fix_path(fname, path); + return smbc_chmod(path, newmode); +} + + +/***************************************************** +a wrapper for lseek() +*******************************************************/ +SMBW_OFF_T smbw_lseek(int smbw_fd, + SMBW_OFF_T offset, + int whence) +{ + int client_fd; + SMBW_OFF_T ret; + + client_fd = smbw_fd_map[smbw_fd]; + + ret = smbc_lseek(client_fd, offset, whence); + if (smbw_debug) + { + printf("smbw_lseek(%d/%d, 0x%llx) returned 0x%llx\n", + smbw_fd, client_fd, + (unsigned long long) offset, + (unsigned long long) ret); + } + return ret; +} + +/***************************************************** +a wrapper for dup() +*******************************************************/ +int smbw_dup(int smbw_fd) +{ + int fd2; + + fd2 = (smbw_libc.dup)(smbw_fd); + if (fd2 == -1) { + return -1; + } + + smbw_fd_map[fd2] = smbw_fd_map[smbw_fd]; + smbw_ref(smbw_fd_map[smbw_fd], SMBW_RCT_Increment); + return fd2; +} + + +/***************************************************** +a wrapper for dup2() +*******************************************************/ +int smbw_dup2(int smbw_fd, int fd2) +{ + if ((* smbw_libc.dup2)(smbw_fd, fd2) != fd2) { + return -1; + } + + smbw_fd_map[fd2] = smbw_fd_map[smbw_fd]; + smbw_ref(smbw_fd_map[smbw_fd], SMBW_RCT_Increment); + return fd2; +} + + +/***************************************************** +when we fork we have to close all connections and files +in the child +*******************************************************/ +int smbw_fork(void) +{ + int i; + pid_t child_pid; + int p[2]; + char c = 0; + + SMBW_INIT(); + + if (pipe(p)) return (* smbw_libc.fork)(); + + child_pid = (* smbw_libc.fork)(); + + if (child_pid) { + /* block the parent for a moment until the sockets are + closed */ + (* smbw_libc.close)(p[1]); + (* smbw_libc.read)(p[0], &c, 1); + (* smbw_libc.close)(p[0]); + return child_pid; + } + + (* smbw_libc.close)(p[0]); + + /* close all server connections and locally-opened files */ + for (i = 0; i < __FD_SETSIZE; i++) { + if (smbw_fd_map[i] > 0 && + smbw_ref(smbw_fd_map[i], SMBW_RCT_Get) > 0) { + + smbc_close(smbw_fd_map[i]); + smbw_ref(smbw_fd_map[i], SMBW_RCT_Set, 0); + (* smbw_libc.close)(i); + } + + smbw_fd_map[i] = -1; + } + + /* unblock the parent */ + write(p[1], &c, 1); + (* smbw_libc.close)(p[1]); + + /* specify directory to start in, if it's simulated smb */ + if (*smbw_cwd != '\0') { + setenv("SMBW_DIR", smbw_cwd, 1); + } else { + unsetenv("SMBW_DIR"); + } + + /* Re-initialize this library for the child */ + do_init(0); + + /* and continue in the child */ + return 0; +} + +int smbw_setxattr(const char *fname, + const char *name, + const void *value, + size_t size, + int flags) +{ + char path[PATH_MAX]; + + if (strcmp(name, "system.posix_acl_access") == 0) + { + name = "system.*"; + } + + smbw_fix_path(fname, path); + return smbc_setxattr(path, name, value, size, flags); +} + +int smbw_lsetxattr(const char *fname, + const char *name, + const void *value, + size_t size, + int flags) +{ + char path[PATH_MAX]; + + if (strcmp(name, "system.posix_acl_access") == 0) + { + name = "system.*"; + } + + smbw_fix_path(fname, path); + return smbc_lsetxattr(path, name, value, size, flags); +} + +int smbw_fsetxattr(int smbw_fd, + const char *name, + const void *value, + size_t size, + int flags) +{ + int client_fd; + + if (strcmp(name, "system.posix_acl_access") == 0) + { + name = "system.*"; + } + + client_fd = smbw_fd_map[smbw_fd]; + return smbc_fsetxattr(client_fd, name, value, size, flags); +} + +int smbw_getxattr(const char *fname, + const char *name, + const void *value, + size_t size) +{ + char path[PATH_MAX]; + + if (strcmp(name, "system.posix_acl_access") == 0) + { + name = "system.*"; + } + + smbw_fix_path(fname, path); + + return smbc_getxattr(path, name, value, size); +} + +int smbw_lgetxattr(const char *fname, + const char *name, + const void *value, + size_t size) +{ + char path[PATH_MAX]; + + if (strcmp(name, "system.posix_acl_access") == 0) + { + name = "system.*"; + } + + smbw_fix_path(fname, path); + return smbc_lgetxattr(path, name, value, size); +} + +int smbw_fgetxattr(int smbw_fd, + const char *name, + const void *value, + size_t size) +{ + int client_fd; + + if (strcmp(name, "system.posix_acl_access") == 0) + { + name = "system.*"; + } + + client_fd = smbw_fd_map[smbw_fd]; + return smbc_fgetxattr(client_fd, name, value, size); +} + +int smbw_removexattr(const char *fname, + const char *name) +{ + char path[PATH_MAX]; + + if (strcmp(name, "system.posix_acl_access") == 0) + { + name = "system.*"; + } + + smbw_fix_path(fname, path); + return smbc_removexattr(path, name); +} + +int smbw_lremovexattr(const char *fname, + const char *name) +{ + char path[PATH_MAX]; + + if (strcmp(name, "system.posix_acl_access") == 0) + { + name = "system.*"; + } + + smbw_fix_path(fname, path); + return smbc_lremovexattr(path, name); +} + +int smbw_fremovexattr(int smbw_fd, + const char *name) +{ + int client_fd; + + if (strcmp(name, "system.posix_acl_access") == 0) + { + name = "system.*"; + } + + client_fd = smbw_fd_map[smbw_fd]; + return smbc_fremovexattr(client_fd, name); +} + +int smbw_listxattr(const char *fname, + char *list, + size_t size) +{ + char path[PATH_MAX]; + + smbw_fix_path(fname, path); + return smbc_listxattr(path, list, size); +} + +int smbw_llistxattr(const char *fname, + char *list, + size_t size) +{ + char path[PATH_MAX]; + + smbw_fix_path(fname, path); + return smbc_llistxattr(path, list, size); +} + +int smbw_flistxattr(int smbw_fd, + char *list, + size_t size) +{ + int client_fd; + + client_fd = smbw_fd_map[smbw_fd]; + return smbc_flistxattr(client_fd, list, size); +} diff --git a/examples/libsmbclient/smbwrapper/smbw.h b/examples/libsmbclient/smbwrapper/smbw.h new file mode 100644 index 0000000000..717b5c2f1c --- /dev/null +++ b/examples/libsmbclient/smbwrapper/smbw.h @@ -0,0 +1,163 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + SMB wrapper functions - definitions + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Derrell Lipman 2003-2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _SMBW_H +#define _SMBW_H + +#include <sys/types.h> +#include <errno.h> +#include <malloc.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "config.h" /* must come before libsmbclient.h */ +#include "libsmbclient.h" +#include "wrapper.h" + +#undef DEBUG +#define DEBUG(level, s) do { if (level <= debug_level) printf s; } while (0) + + +#define SMBW_PREFIX "/smb" +#define SMBW_DUMMY "/dev/null" + +extern int smbw_initialized; +#define SMBW_INIT() do { if (! smbw_initialized) smbw_init(); } while (0) + +#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) +# define SMBW_OFF_T off64_t +#else +# define SMBW_OFF_T off_t +#endif + + +/* The following definitions come from smbwrapper/smbw.c */ + +typedef enum { + SMBW_RCT_Increment, + SMBW_RCT_Decrement, + SMBW_RCT_Get, + SMBW_RCT_Set +} Ref_Count_Type; + +int smbw_ref(int client_fd, Ref_Count_Type type, ...); +void smbw_init(void); +int smbw_fd(int fd); +int smbw_path(const char *path); +void smbw_clean_fname(char *name); +void smbw_fix_path(const char *src, char *dest); +void smbw_set_auth_data_fn(smbc_get_auth_data_fn fn); +int smbw_open(const char *fname, int flags, mode_t mode); +ssize_t smbw_pread(int fd, void *buf, size_t count, SMBW_OFF_T ofs); +ssize_t smbw_read(int fd, void *buf, size_t count); +ssize_t smbw_write(int fd, void *buf, size_t count); +ssize_t smbw_pwrite(int fd, void *buf, size_t count, SMBW_OFF_T ofs); +int smbw_close(int fd); +int smbw_fcntl(int fd, int cmd, long arg); +int smbw_access(const char *name, int mode); +int smbw_readlink(const char *path, char *buf, size_t bufsize); +int smbw_unlink(const char *fname); +int smbw_rename(const char *oldname, const char *newname); +int smbw_utime(const char *fname, void *buf); +int smbw_utimes(const char *fname, void *buf); +int smbw_chown(const char *fname, uid_t owner, gid_t group); +int smbw_chmod(const char *fname, mode_t newmode); +SMBW_OFF_T smbw_lseek(int smbw_fd, SMBW_OFF_T offset, int whence); +int smbw_dup(int fd); +int smbw_dup2(int fd, int fd2); +int smbw_fork(void); + +/* The following definitions come from smbwrapper/smbw_dir.c */ + +int smbw_dirp(DIR * dirp); +int smbw_dir_open(const char *fname); +int smbw_dir_fstat(int fd, SMBW_stat *st); +int smbw_dir_close(int fd); +int smbw_getdents(unsigned int fd, SMBW_dirent *dirp, int count); +int smbw_chdir(const char *name); +int smbw_mkdir(const char *fname, mode_t mode); +int smbw_rmdir(const char *fname); +char *smbw_getcwd(char *buf, size_t size); +int smbw_fchdir(int fd); +DIR *smbw_opendir(const char *fname); +SMBW_dirent *smbw_readdir(DIR *dirp); +int smbw_readdir_r(DIR *dirp, + struct SMBW_dirent *__restrict entry, + struct SMBW_dirent **__restrict result); +int smbw_closedir(DIR *dirp); +void smbw_seekdir(DIR *dirp, long long offset); +long long smbw_telldir(DIR *dirp); +int smbw_setxattr(const char *fname, + const char *name, + const void *value, + size_t size, + int flags); +int smbw_lsetxattr(const char *fname, + const char *name, + const void *value, + size_t size, + int flags); +int smbw_fsetxattr(int smbw_fd, + const char *name, + const void *value, + size_t size, + int flags); +int smbw_getxattr(const char *fname, + const char *name, + const void *value, + size_t size); +int smbw_lgetxattr(const char *fname, + const char *name, + const void *value, + size_t size); +int smbw_fgetxattr(int smbw_fd, + const char *name, + const void *value, + size_t size); +int smbw_removexattr(const char *fname, + const char *name); +int smbw_lremovexattr(const char *fname, + const char *name); +int smbw_fremovexattr(int smbw_fd, + const char *name); +int smbw_listxattr(const char *fname, + char *list, + size_t size); +int smbw_llistxattr(const char *fname, + char *list, + size_t size); +int smbw_flistxattr(int smbw_fd, + char *list, + size_t size); + +/* The following definitions come from smbwrapper/smbw_stat.c */ + +int smbw_fstat(int fd, SMBW_stat *st); +int smbw_stat(const char *fname, SMBW_stat *st); + +/* The following definitions come from smbwrapper/cache.c */ +int +smbw_cache_functions(SMBCCTX * context); + + +#endif /* _SMBW_H */ diff --git a/examples/libsmbclient/smbwrapper/smbw_dir.c b/examples/libsmbclient/smbwrapper/smbw_dir.c new file mode 100644 index 0000000000..f3ec03e5a8 --- /dev/null +++ b/examples/libsmbclient/smbwrapper/smbw_dir.c @@ -0,0 +1,355 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + SMB wrapper directory functions + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Derrell Lipman 2003-2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "smbw.h" + +/***************************************************** +determine if a directory handle is a smb one +*******************************************************/ +int smbw_dirp(DIR * dirp) +{ + return ((char *) dirp >= (char *) smbw_fd_map && + (char *) dirp < (char *) &smbw_fd_map[__FD_SETSIZE] && + *(int *) dirp != -1); +} + + +/***************************************************** +a wrapper for getdents() +*******************************************************/ +int smbw_getdents(unsigned int fd_smbw, + struct SMBW_dirent *dirent_external, + int count) +{ + int remaining; + int fd_client = smbw_fd_map[fd_smbw]; + struct smbc_dirent *dirent_internal; + + + for (remaining = count; + remaining > sizeof(struct SMBW_dirent); + dirent_external++) { + + /* + * We do these one at a time because there's otherwise no way + * to limit how many smbc_getdents() will return for us, and + * if it returns too many, it also doesn't give us offsets to + * be able to seek back to where we need to be. In practice, + * this one-at-a-time retrieval isn't a problem because the + * time-consuming network transaction is all done at + * smbc_opendir() time. + */ + dirent_internal = smbc_readdir(fd_client); + if (dirent_internal == NULL) { + break; + } + + remaining -= sizeof(struct SMBW_dirent); + + dirent_external->d_ino = -1; /* not supported */ + dirent_external->d_off = smbc_telldir(fd_client); + dirent_external->d_reclen = sizeof(struct SMBW_dirent); + dirent_external->d_type = dirent_internal->smbc_type; + + strncpy(dirent_external->d_name, + dirent_internal->name, + sizeof(dirent_external->d_name) - 1); + strncpy(dirent_external->d_comment, + dirent_internal->comment, + sizeof(dirent_external->d_comment) - 1); + } + + return(count - remaining); +} + + +/***************************************************** +a wrapper for chdir() +*******************************************************/ +int smbw_chdir(const char *name) +{ + int simulate; + struct stat statbuf; + char path[PATH_MAX]; + char *p; + + SMBW_INIT(); + + if (!name) { + errno = EINVAL; + return -1; + } + + if (! smbw_path((char *) name)) { + if ((* smbw_libc.chdir)(name) == 0) { + *smbw_cwd = '\0'; + return 0; + } + + return -1; + } + + smbw_fix_path(name, path); + + /* ensure it exists */ + p = path + 6; /* look just past smb:// */ + simulate = (strchr(p, '/') == NULL); + + /* special case for full-network scan, workgroups, and servers */ + if (! simulate) { + + if (smbc_stat(path, &statbuf) < 0) { + return -1; + } + + /* ensure it's a directory */ + if (! S_ISDIR(statbuf.st_mode)) { + errno = ENOTDIR; + return -1; + } + } + + strncpy(smbw_cwd, path, PATH_MAX); + + /* we don't want the old directory to be busy */ + (* smbw_libc.chdir)("/"); + + return 0; +} + + +/***************************************************** +a wrapper for mkdir() +*******************************************************/ +int smbw_mkdir(const char *fname, mode_t mode) +{ + char path[PATH_MAX]; + + if (!fname) { + errno = EINVAL; + return -1; + } + + SMBW_INIT(); + + smbw_fix_path(fname, path); + return smbc_mkdir(path, mode); +} + +/***************************************************** +a wrapper for rmdir() +*******************************************************/ +int smbw_rmdir(const char *fname) +{ + char path[PATH_MAX]; + + if (!fname) { + errno = EINVAL; + return -1; + } + + SMBW_INIT(); + + smbw_fix_path(fname, path); + return smbc_rmdir(path); +} + + +/***************************************************** +a wrapper for getcwd() +*******************************************************/ +char *smbw_getcwd(char *buf, size_t size) +{ + SMBW_INIT(); + + if (*smbw_cwd == '\0') { + return (* smbw_libc.getcwd)(buf, size); + } + + if (buf == NULL) { + if (size == 0) { + size = strlen(smbw_cwd) + 1; + } + buf = malloc(size); + if (buf == NULL) { + errno = ENOMEM; + return NULL; + } + } + + strncpy(buf, smbw_cwd, size); + buf[size-1] = '\0'; + return buf; +} + +/***************************************************** +a wrapper for fchdir() +*******************************************************/ +int smbw_fchdir(int fd_smbw) +{ + int ret; + + SMBW_INIT(); + + if (! smbw_fd(fd_smbw)) { + ret = (* smbw_libc.fchdir)(fd_smbw); + (void) (* smbw_libc.getcwd)(smbw_cwd, PATH_MAX); + return ret; + } + + errno = EACCES; + return -1; +} + +/***************************************************** +open a directory on the server +*******************************************************/ +DIR *smbw_opendir(const char *fname) +{ + int fd_client; + int fd_smbw; + char path[PATH_MAX]; + DIR * dirp; + + SMBW_INIT(); + + if (!fname) { + errno = EINVAL; + return NULL; + } + + fd_smbw = (smbw_libc.open)(SMBW_DUMMY, O_WRONLY, 0200); + if (fd_smbw == -1) { + errno = EMFILE; + return NULL; + } + + smbw_fix_path(fname, path); + fd_client = smbc_opendir(path); + + if (fd_client < 0) { + (* smbw_libc.close)(fd_smbw); + return NULL; + } + + smbw_fd_map[fd_smbw] = fd_client; + smbw_ref(fd_client, SMBW_RCT_Increment); + dirp = (DIR *) &smbw_fd_map[fd_smbw]; + return dirp; +} + +/***************************************************** +read one entry from a directory +*******************************************************/ +struct SMBW_dirent *smbw_readdir(DIR *dirp) +{ + int fd_smbw; + int fd_client; + struct smbc_dirent *dirent_internal; + static struct SMBW_dirent dirent_external; + + fd_smbw = (int *) dirp - smbw_fd_map; + fd_client = smbw_fd_map[fd_smbw]; + + if ((dirent_internal = smbc_readdir(fd_client)) == NULL) { + return NULL; + } + + dirent_external.d_ino = -1; /* not supported */ + dirent_external.d_off = smbc_telldir(fd_client); + dirent_external.d_reclen = sizeof(struct SMBW_dirent); + dirent_external.d_type = dirent_internal->smbc_type; + strncpy(dirent_external.d_name, + dirent_internal->name, + sizeof(dirent_external.d_name) - 1); + strncpy(dirent_external.d_comment, + dirent_internal->comment, + sizeof(dirent_external.d_comment) - 1); + + return &dirent_external; +} + +/***************************************************** +read one entry from a directory in a reentrant fashion +ha! samba is not re-entrant, and neither is the +libsmbclient library +*******************************************************/ +int smbw_readdir_r(DIR *dirp, + struct SMBW_dirent *__restrict entry, + struct SMBW_dirent **__restrict result) +{ + SMBW_dirent *dirent; + + dirent = smbw_readdir(dirp); + + if (dirent != NULL) { + *entry = *dirent; + if (result != NULL) { + *result = entry; + } + return 0; + } + + if (result != NULL) { + *result = NULL; + } + return EBADF; +} + + +/***************************************************** +close a DIR* +*******************************************************/ +int smbw_closedir(DIR *dirp) +{ + int fd_smbw = (int *) dirp - smbw_fd_map; + int fd_client = smbw_fd_map[fd_smbw]; + + (* smbw_libc.close)(fd_smbw); + if (smbw_ref(fd_client, SMBW_RCT_Decrement) > 0) { + return 0; + } + smbw_fd_map[fd_smbw] = -1; + return smbc_closedir(fd_client); +} + +/***************************************************** +seek in a directory +*******************************************************/ +void smbw_seekdir(DIR *dirp, long long offset) +{ + int fd_smbw = (int *) dirp - smbw_fd_map; + int fd_client = smbw_fd_map[fd_smbw]; + + smbc_lseekdir(fd_client, offset); +} + +/***************************************************** +current loc in a directory +*******************************************************/ +long long smbw_telldir(DIR *dirp) +{ + int fd_smbw = (int *) dirp - smbw_fd_map; + int fd_client = smbw_fd_map[fd_smbw]; + + return (long long) smbc_telldir(fd_client); +} diff --git a/examples/libsmbclient/smbwrapper/smbw_stat.c b/examples/libsmbclient/smbwrapper/smbw_stat.c new file mode 100644 index 0000000000..70b3064d22 --- /dev/null +++ b/examples/libsmbclient/smbwrapper/smbw_stat.c @@ -0,0 +1,146 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + SMB wrapper stat functions + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Derrell Lipman 2003-2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "smbw.h" + +static int timezone_diff = -1; + +#define TM_YEAR_BASE 1900 + +/******************************************************************* +yield the difference between *A and *B, in seconds, ignoring leap seconds +********************************************************************/ +static int tm_diff(struct tm *a, struct tm *b) +{ + int ay = a->tm_year + (TM_YEAR_BASE - 1); + int by = b->tm_year + (TM_YEAR_BASE - 1); + int intervening_leap_days = + (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400); + int years = ay - by; + int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday); + int hours = 24*days + (a->tm_hour - b->tm_hour); + int minutes = 60*hours + (a->tm_min - b->tm_min); + int seconds = 60*minutes + (a->tm_sec - b->tm_sec); + + return seconds; +} + +/******************************************************************* + return the UTC offset in seconds west of UTC, or 0 if it cannot be determined + ******************************************************************/ +static int TimeZone(time_t t) +{ + struct tm *tm = gmtime(&t); + struct tm tm_utc; + if (!tm) + return 0; + tm_utc = *tm; + tm = localtime(&t); + if (!tm) + return 0; + return tm_diff(&tm_utc,tm); + +} + + +static void copy_stat(struct SMBW_stat *external, struct stat *internal) +{ + if (timezone_diff < 0) + { + timezone_diff = TimeZone(time(NULL)); + } + + external->s_dev = internal->st_dev; + external->s_ino = internal->st_ino; + external->s_mode = internal->st_mode; + external->s_nlink = internal->st_nlink; + external->s_uid = internal->st_uid; + external->s_gid = internal->st_gid; + external->s_rdev = internal->st_rdev; + external->s_size = internal->st_size; + external->s_blksize = internal->st_blksize; + external->s_blocks = internal->st_blocks; + external->s_atime = internal->st_atime + timezone_diff; + external->s_mtime = internal->st_mtime + timezone_diff; + external->s_ctime = internal->st_ctime + timezone_diff; +} + + +/***************************************************** +a wrapper for fstat() +*******************************************************/ +int smbw_fstat(int fd_smbw, struct SMBW_stat *st) +{ + int fd_client = smbw_fd_map[fd_smbw]; + struct stat statbuf; + + if (smbc_fstat(fd_client, &statbuf) < 0) { + return -1; + } + + copy_stat(st, &statbuf); + + return 0; +} + + +/***************************************************** +a wrapper for stat() +*******************************************************/ +int smbw_stat(const char *fname, struct SMBW_stat *st) +{ + int simulate; + char *p; + char path[PATH_MAX]; + struct stat statbuf; + + SMBW_INIT(); + + smbw_fix_path(fname, path); + + p = path + 6; /* look just past smb:// */ + simulate = (strchr(p, '/') == NULL); + + /* special case for full-network scan, workgroups, and servers */ + if (simulate) { + statbuf.st_dev = 0; + statbuf.st_ino = 0; + statbuf.st_mode = 0040777; + statbuf.st_nlink = 1; + statbuf.st_uid = 0; + statbuf.st_gid = 0; + statbuf.st_rdev = 0; + statbuf.st_size = 0; + statbuf.st_blksize = 1024; + statbuf.st_blocks = 1; + statbuf.st_atime = 0; /* beginning of epoch */ + statbuf.st_mtime = 0; /* beginning of epoch */ + statbuf.st_ctime = 0; /* beginning of epoch */ + + } else if (smbc_stat(path, &statbuf) < 0) { + return -1; + } + + copy_stat(st, &statbuf); + + return 0; +} diff --git a/examples/libsmbclient/smbwrapper/wrapper.c b/examples/libsmbclient/smbwrapper/wrapper.c new file mode 100644 index 0000000000..71d6f203ad --- /dev/null +++ b/examples/libsmbclient/smbwrapper/wrapper.c @@ -0,0 +1,1729 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + SMB wrapper functions + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Derrell Lipman 2002-2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * This is a rewrite of the original wrapped.c file, using libdl to obtain + * pointers into the C library rather than attempting to find undocumented + * functions in the C library to call for native file access. The problem + * with the original implementation's paradigm is that samba manipulates + * defines such that it gets the sizes of structures that it wants + * (e.g. mapping 32-bit functions to 64-bit functions with their associated + * 64-bit structure fields), but programs run under smbsh or using + * smbwrapper.so were not necessarily compiled with the same flags. As an + * example of the problem, a program calling stat() passes a pointer to a + * "struct stat" but the fields in that structure are different in samba than + * they are in the calling program if the calling program was not compiled to + * force stat() to be mapped to stat64(). + * + * In this version, we provide an interface to each of the native functions, + * not just the ones that samba is compiled to map to. We obtain the function + * pointers from the C library using dlsym(), and for native file operations, + * directly call the same function that the calling application was + * requesting. Since the size of the calling application's structures vary + * depending on what function was called, we use our own internal structures + * for passing information to/from the SMB equivalent functions, and map them + * back to the native structures before returning the result to the caller. + * + * This implementation was completed 25 December 2002. + * Derrell Lipman + */ + +/* We do not want auto munging of 32->64 bit names in this file (only) */ +#undef _FILE_OFFSET_BITS +#undef _GNU_SOURCE + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <utime.h> +#include <stdio.h> +#include <dirent.h> +#include <signal.h> +#include <stdarg.h> +#include <dlfcn.h> +#include <errno.h> +#include "libsmbclient.h" +#include "wrapper.h" + +/* + * Debug bits: + * 0x0 = none + * 0x1 = display symbol definitions not found in C library + * 0x2 = show wrapper functions being called + * 0x4 = log to file SMBW_DEBUG_FILE instead of stderr + */ +#define SMBW_DEBUG 0x0 +#define SMBW_DEBUG_FILE "/tmp/smbw.log" + +int smbw_debug = 0; + +#if SMBW_DEBUG & 0x2 +static int debugFd = 2; +#endif + +#ifndef ENOTSUP +#define ENOTSUP EOPNOTSUPP +#endif + +/* + * None of the methods of having the initialization function called + * automatically upon shared library startup are effective in all situations. + * We provide the "-init" parameter to the linker which is effective most of + * the time, but fails for applications that provide their own shared + * libraries with _init() functions (e.g. ps). We can't use "-z initfirst" + * because the environment isn't yet set up at that point, so we can't find + * our shared memory identifier (see shared.c). We therefore must resort to + * this tried-and-true method of keeping an "initialized" flag. We check it + * prior to calling the initialize() function to save a function call (a slow + * operation on x86). + */ +#if SMBW_DEBUG & 0x2 +# define check_init(buf) \ + do { \ + int saved_errno = errno; \ + if (! initialized) initialize(); \ + (* smbw_libc.write)(debugFd, "["buf"]", sizeof(buf)+1); \ + errno = saved_errno; \ + } while (0); +#else +# define check_init(buf) \ + do { \ + if (! initialized) smbw_initialize(); \ + } while (0); +#endif + +static void initialize(void); + +static int initialized = 0; + +SMBW_libc_pointers smbw_libc; + +/* + * A public entry point used by the "-init" option to the linker. + */ +void smbw_initialize(void) +{ + initialize(); +} + +static void initialize(void) +{ + void *lib = NULL; + int saved_errno; +#if SMBW_DEBUG & 0x1 + char *error; +#endif + + saved_errno = errno; + + if (initialized) { + errno = saved_errno; + return; + } + initialized = 1; + + if ((lib = dlopen("/lib/libc.so.6", RTLD_NOW | RTLD_GLOBAL)) == NULL) { + exit(1); + } + +#if SMBW_DEBUG & 0x1 +# define GETSYM(symname, symstring) \ + if ((smbw_libc.symname = dlsym(lib, symstring)) == NULL) { \ + if (smbw_libc.write != NULL && \ + (error = dlerror()) != NULL) { \ + (* smbw_libc.write)(1, error, strlen(error)); \ + (* smbw_libc.write)(1, "\n", 1); \ + } \ + } +#else +# define GETSYM(symname, symstring) \ + smbw_libc.symname = dlsym(lib, symstring); +#endif + + /* + * Get pointers to each of the symbols we'll need, from the C library + * + * Some of these symbols may not be found in the C library. That's + * fine. We declare all of them here, and if the C library supports + * them, they may be called so we have the wrappers for them. If the + * C library doesn't support them, then the wrapper function will + * never be called, and the null pointer will never be dereferenced. + */ + do { + GETSYM(write, "write"); /* first, to allow debugging */ + GETSYM(open, "open"); + GETSYM(_open, "_open"); + GETSYM(__open, "__open"); + GETSYM(open64, "open64"); + GETSYM(_open64, "_open64"); + GETSYM(__open64, "__open64"); + GETSYM(pread, "pread"); + GETSYM(pread64, "pread64"); + GETSYM(pwrite, "pwrite"); + GETSYM(pwrite64, "pwrite64"); + GETSYM(close, "close"); + GETSYM(__close, "__close"); + GETSYM(_close, "_close"); + GETSYM(fcntl, "fcntl"); + GETSYM(__fcntl, "__fcntl"); + GETSYM(_fcntl, "_fcntl"); + GETSYM(getdents, "getdents"); + GETSYM(__getdents, "__getdents"); + GETSYM(_getdents, "_getdents"); + GETSYM(getdents64, "getdents64"); + GETSYM(lseek, "lseek"); + GETSYM(__lseek, "__lseek"); + GETSYM(_lseek, "_lseek"); + GETSYM(lseek64, "lseek64"); + GETSYM(__lseek64, "__lseek64"); + GETSYM(_lseek64, "_lseek64"); + GETSYM(read, "read"); + GETSYM(__read, "__read"); + GETSYM(_read, "_read"); + GETSYM(__write, "__write"); + GETSYM(_write, "_write"); + GETSYM(access, "access"); + GETSYM(chmod, "chmod"); + GETSYM(fchmod, "fchmod"); + GETSYM(chown, "chown"); + GETSYM(fchown, "fchown"); + GETSYM(__xstat, "__xstat"); + GETSYM(getcwd, "getcwd"); + GETSYM(mkdir, "mkdir"); + GETSYM(__fxstat, "__fxstat"); + GETSYM(__lxstat, "__lxstat"); + GETSYM(stat, "stat"); + GETSYM(lstat, "lstat"); + GETSYM(fstat, "fstat"); + GETSYM(unlink, "unlink"); + GETSYM(utime, "utime"); + GETSYM(utimes, "utimes"); + GETSYM(readlink, "readlink"); + GETSYM(rename, "rename"); + GETSYM(rmdir, "rmdir"); + GETSYM(symlink, "symlink"); + GETSYM(dup, "dup"); + GETSYM(dup2, "dup2"); + GETSYM(opendir, "opendir"); + GETSYM(readdir, "readdir"); + GETSYM(closedir, "closedir"); + GETSYM(telldir, "telldir"); + GETSYM(seekdir, "seekdir"); + GETSYM(creat, "creat"); + GETSYM(creat64, "creat64"); + GETSYM(__xstat64, "__xstat64"); + GETSYM(stat64, "stat64"); + GETSYM(__fxstat64, "__fxstat64"); + GETSYM(fstat64, "fstat64"); + GETSYM(__lxstat64, "__lxstat64"); + GETSYM(lstat64, "lstat64"); + GETSYM(_llseek, "_llseek"); + GETSYM(readdir64, "readdir64"); + GETSYM(readdir_r, "readdir_r"); + GETSYM(readdir64_r, "readdir64_r"); + GETSYM(setxattr, "setxattr"); + GETSYM(lsetxattr, "lsetxattr"); + GETSYM(fsetxattr, "fsetxattr"); + GETSYM(getxattr, "getxattr"); + GETSYM(lgetxattr, "lgetxattr"); + GETSYM(fgetxattr, "fgetxattr"); + GETSYM(removexattr, "removexattr"); + GETSYM(lremovexattr, "lremovexattr"); + GETSYM(fremovexattr, "fremovexattr"); + GETSYM(listxattr, "listxattr"); + GETSYM(llistxattr, "llistxattr"); + GETSYM(flistxattr, "flistxattr"); + GETSYM(chdir, "chdir"); + GETSYM(fchdir, "fchdir"); + GETSYM(fork, "fork"); + GETSYM(select, "select"); + GETSYM(_select, "_select"); + GETSYM(__select, "__select"); + } while (0); + + dlclose(lib); + + if ((lib = dlopen("/lib/libc.so.6", RTLD_NOW | RTLD_GLOBAL)) == NULL) { + exit(1); + } + +#if SMBW_DEBUG & 4 + { + if ((debugFd = + open(SMBW_DEBUG_FILE, O_WRONLY | O_CREAT | O_APPEND)) < 0) + { +# define SMBW_MESSAGE "Could not create " SMBW_DEBUG_FILE "\n" + (* smbw_libc.write)(1, SMBW_MESSAGE, sizeof(SMBW_MESSAGE)); +# undef SMBW_MESSAGE + exit(1); + } + } +#endif + + errno = saved_errno; +} + +/** + ** Static Functions + **/ + +static void stat_convert(struct SMBW_stat *src, struct stat *dest) +{ + memset(dest, '\0', sizeof(*dest)); + dest->st_size = src->s_size; + dest->st_mode = src->s_mode; + dest->st_ino = src->s_ino; + dest->st_dev = src->s_dev; + dest->st_rdev = src->s_rdev; + dest->st_nlink = src->s_nlink; + dest->st_uid = src->s_uid; + dest->st_gid = src->s_gid; + dest->st_atime = src->s_atime; + dest->st_mtime = src->s_mtime; + dest->st_ctime = src->s_ctime; + dest->st_blksize = src->s_blksize; + dest->st_blocks = src->s_blocks; +} + +static void stat64_convert(struct SMBW_stat *src, struct stat64 *dest) +{ + memset(dest, '\0', sizeof(*dest)); + dest->st_size = src->s_size; + dest->st_mode = src->s_mode; + dest->st_ino = src->s_ino; + dest->st_dev = src->s_dev; + dest->st_rdev = src->s_rdev; + dest->st_nlink = src->s_nlink; + dest->st_uid = src->s_uid; + dest->st_gid = src->s_gid; + dest->st_atime = src->s_atime; + dest->st_mtime = src->s_mtime; + dest->st_ctime = src->s_ctime; + dest->st_blksize = src->s_blksize; + dest->st_blocks = src->s_blocks; +} + +static void dirent_convert(struct SMBW_dirent *src, struct dirent *dest) +{ + char *p; + + memset(dest, '\0', sizeof(*dest)); + dest->d_ino = src->d_ino; + dest->d_off = src->d_off; + + switch(src->d_type) + { + case SMBC_WORKGROUP: + case SMBC_SERVER: + case SMBC_FILE_SHARE: + case SMBC_DIR: + dest->d_type = DT_DIR; + break; + + case SMBC_FILE: + dest->d_type = DT_REG; + break; + + case SMBC_PRINTER_SHARE: + dest->d_type = DT_CHR; + break; + + case SMBC_COMMS_SHARE: + dest->d_type = DT_SOCK; + break; + + case SMBC_IPC_SHARE: + dest->d_type = DT_FIFO; + break; + + case SMBC_LINK: + dest->d_type = DT_LNK; + break; + } + + dest->d_reclen = src->d_reclen; + strncpy(dest->d_name, src->d_name, sizeof(dest->d_name)); + p = dest->d_name + strlen(dest->d_name) + 1; + strncpy(p, src->d_comment, sizeof(dest->d_name) - (p - dest->d_name)); +} + +static void dirent64_convert(struct SMBW_dirent *src, struct dirent64 *dest) +{ + char *p; + + memset(dest, '\0', sizeof(*dest)); + dest->d_ino = src->d_ino; + dest->d_off = src->d_off; + + switch(src->d_type) + { + case SMBC_WORKGROUP: + case SMBC_SERVER: + case SMBC_FILE_SHARE: + case SMBC_DIR: + dest->d_type = DT_DIR; + break; + + case SMBC_FILE: + dest->d_type = DT_REG; + break; + + case SMBC_PRINTER_SHARE: + dest->d_type = DT_CHR; + break; + + case SMBC_COMMS_SHARE: + dest->d_type = DT_SOCK; + break; + + case SMBC_IPC_SHARE: + dest->d_type = DT_FIFO; + break; + + case SMBC_LINK: + dest->d_type = DT_LNK; + break; + } + + dest->d_reclen = src->d_reclen; + strncpy(dest->d_name, src->d_name, sizeof(dest->d_name)); + p = dest->d_name + strlen(dest->d_name) + 1; + strncpy(p, src->d_comment, sizeof(dest->d_name) - (p - dest->d_name)); +} + +static int openx(char *name, int flags, mode_t mode, int (* f)(char *, int, mode_t)) +{ + if (smbw_path(name)) { + return smbw_open(name, flags, mode); + } + + return (* f)(name, flags, mode); +} + +static int closex(int fd, int (* f)(int fd)) +{ + if (smbw_fd(fd)) { + return smbw_close(fd); + } + + return (* f)(fd); +} + +static int fcntlx(int fd, int cmd, long arg, int (* f)(int, int, long)) +{ + if (smbw_fd(fd)) { + return smbw_fcntl(fd, cmd, arg); + } + + return (* f)(fd, cmd, arg); +} + +static int getdentsx(int fd, struct dirent *external, unsigned int count, int (* f)(int, struct dirent *, unsigned int)) +{ + if (smbw_fd(fd)) { + int i; + int internal_count; + struct SMBW_dirent *internal; + int ret; + int n; + + /* + * LIMITATION: If they pass a count which is not a multiple of + * the size of struct dirent, they will not get a partial + * structure; we ignore the excess count. + */ + n = (count / sizeof(struct dirent)); + + internal_count = sizeof(struct SMBW_dirent) * n; + internal = malloc(internal_count); + if (internal == NULL) { + errno = ENOMEM; + return -1; + } + ret = smbw_getdents(fd, internal, internal_count); + if (ret <= 0) + return ret; + + ret = sizeof(struct dirent) * n; + + for (i = 0; i < n; i++) + dirent_convert(&internal[i], &external[i]); + + return ret; + } + + return (* f)(fd, external, count); +} + +static off_t lseekx(int fd, + off_t offset, + int whence, + off_t (* f)(int, off_t, int)) +{ + off_t ret; + + /* + * We have left the definitions of the smbw_ functions undefined, + * because types such as off_t can differ in meaning betweent his + * function and smbw.c et al. Functions that return other than an + * integer value, however, MUST have their return value defined. + */ + off64_t smbw_lseek(); + + if (smbw_fd(fd)) { + return (off_t) smbw_lseek(fd, offset, whence); + } + + ret = (* f)(fd, offset, whence); + if (smbw_debug) + { + printf("lseekx(%d, 0x%llx) returned 0x%llx\n", + fd, + (unsigned long long) offset, + (unsigned long long) ret); + } + return ret; +} + +static off64_t lseek64x(int fd, + off64_t offset, + int whence, + off64_t (* f)(int, off64_t, int)) +{ + off64_t ret; + + /* + * We have left the definitions of the smbw_ functions undefined, + * because types such as off_t can differ in meaning betweent his + * function and smbw.c et al. Functions that return other than an + * integer value, however, MUST have their return value defined. + */ + off64_t smbw_lseek(); + + if (smbw_fd(fd)) + ret = smbw_lseek(fd, offset, whence); + else + ret = (* f)(fd, offset, whence); + if (smbw_debug) + { + printf("lseek64x(%d, 0x%llx) returned 0x%llx\n", + fd, + (unsigned long long) offset, + (unsigned long long) ret); + } + return ret; +} + +static ssize_t readx(int fd, void *buf, size_t count, ssize_t (* f)(int, void *, size_t)) +{ + if (smbw_fd(fd)) { + return smbw_read(fd, buf, count); + } + + return (* f)(fd, buf, count); +} + +static ssize_t writex(int fd, void *buf, size_t count, ssize_t (* f)(int, void *, size_t)) +{ + if (smbw_fd(fd)) { + return smbw_write(fd, buf, count); + } + + return (* f)(fd, buf, count); +} + + +/** + ** Wrapper Functions + **/ + +int open(__const char *name, int flags, ...) +{ + va_list ap; + mode_t mode; + + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + + check_init("open"); + + return openx((char *) name, flags, mode, smbw_libc.open); +} + +int _open(char *name, int flags, mode_t mode) +{ + check_init("open"); + + return openx(name, flags, mode, smbw_libc._open); +} + +int __open(char *name, int flags, mode_t mode) +{ + check_init("open"); + + return openx(name, flags, mode, smbw_libc.__open); +} + +int open64 (__const char *name, int flags, ...) +{ + va_list ap; + mode_t mode; + + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + + check_init("open64"); + return openx((char *) name, flags, mode, smbw_libc.open64); +} + +int _open64(char *name, int flags, mode_t mode) +{ + check_init("_open64"); + return openx(name, flags, mode, smbw_libc._open64); +} + +int __open64(char *name, int flags, mode_t mode) +{ + check_init("__open64"); + return openx(name, flags, mode, smbw_libc.__open64); +} + +ssize_t pread(int fd, void *buf, size_t size, off_t ofs) +{ + check_init("pread"); + + if (smbw_fd(fd)) { + return smbw_pread(fd, buf, size, ofs); + } + + return (* smbw_libc.pread)(fd, buf, size, ofs); +} + +ssize_t pread64(int fd, void *buf, size_t size, off64_t ofs) +{ + check_init("pread64"); + + if (smbw_fd(fd)) { + return smbw_pread(fd, buf, size, (off_t) ofs); + } + + return (* smbw_libc.pread64)(fd, buf, size, ofs); +} + +ssize_t pwrite(int fd, const void *buf, size_t size, off_t ofs) +{ + check_init("pwrite"); + + if (smbw_fd(fd)) { + return smbw_pwrite(fd, (void *) buf, size, ofs); + } + + return (* smbw_libc.pwrite)(fd, (void *) buf, size, ofs); +} + +ssize_t pwrite64(int fd, const void *buf, size_t size, off64_t ofs) +{ + check_init("pwrite64"); + + if (smbw_fd(fd)) { + return smbw_pwrite(fd, (void *) buf, size, (off_t) ofs); + } + + return (* smbw_libc.pwrite64)(fd, (void *) buf, size, ofs); +} + +int chdir(const char *name) +{ + check_init("chdir"); + return smbw_chdir((char *) name);; +} + +int __chdir(char *name) +{ + check_init("__chdir"); + return smbw_chdir(name); +} + +int _chdir(char *name) +{ + check_init("_chdir"); + return smbw_chdir(name); +} + +int close(int fd) +{ + check_init("close"); + return closex(fd, smbw_libc.close); +} + +int __close(int fd) +{ + check_init("__close"); + return closex(fd, smbw_libc.__close); +} + +int _close(int fd) +{ + check_init("_close"); + return closex(fd, smbw_libc._close); +} + +int fchdir(int fd) +{ + check_init("fchdir"); + return smbw_fchdir(fd); +} + +int __fchdir(int fd) +{ + check_init("__fchdir"); + return fchdir(fd); +} + +int _fchdir(int fd) +{ + check_init("_fchdir"); + return fchdir(fd); +} + +int fcntl (int fd, int cmd, ...) +{ + va_list ap; + long arg; + + va_start(ap, cmd); + arg = va_arg(ap, long); + va_end(ap); + + check_init("fcntl"); + return fcntlx(fd, cmd, arg, smbw_libc.fcntl); +} + +int __fcntl(int fd, int cmd, ...) +{ + va_list ap; + long arg; + + va_start(ap, cmd); + arg = va_arg(ap, long); + va_end(ap); + + check_init("__fcntl"); + return fcntlx(fd, cmd, arg, smbw_libc.__fcntl); +} + +int _fcntl(int fd, int cmd, ...) +{ + va_list ap; + long arg; + + va_start(ap, cmd); + arg = va_arg(ap, long); + va_end(ap); + + check_init("_fcntl"); + return fcntlx(fd, cmd, arg, smbw_libc._fcntl); +} + +int getdents(int fd, struct dirent *dirp, unsigned int count) +{ + check_init("getdents"); + return getdentsx(fd, dirp, count, smbw_libc.getdents); +} + +int __getdents(int fd, struct dirent *dirp, unsigned int count) +{ + check_init("__getdents"); + return getdentsx(fd, dirp, count, smbw_libc.__getdents); +} + +int _getdents(int fd, struct dirent *dirp, unsigned int count) +{ + check_init("_getdents"); + return getdentsx(fd, dirp, count, smbw_libc._getdents); +} + +int getdents64(int fd, struct dirent64 *external, unsigned int count) +{ + check_init("getdents64"); + if (smbw_fd(fd)) { + int i; + struct SMBW_dirent *internal; + int ret; + int n; + + /* + * LIMITATION: If they pass a count which is not a multiple of + * the size of struct dirent, they will not get a partial + * structure; we ignore the excess count. + */ + n = (count / sizeof(struct dirent64)); + + internal = malloc(sizeof(struct SMBW_dirent) * n); + if (internal == NULL) { + errno = ENOMEM; + return -1; + } + ret = smbw_getdents(fd, internal, count); + if (ret <= 0) + return ret; + + ret = sizeof(struct dirent) * count; + + for (i = 0; count; i++, count--) + dirent64_convert(&internal[i], &external[i]); + + return ret; + } + + return (* smbw_libc.getdents64)(fd, external, count); +} + +off_t lseek(int fd, off_t offset, int whence) +{ + off_t ret; + check_init("lseek"); + ret = lseekx(fd, offset, whence, smbw_libc.lseek); + if (smbw_debug) + { + printf("lseek(%d, 0x%llx) returned 0x%llx\n", + fd, + (unsigned long long) offset, + (unsigned long long) ret); + } + return ret; +} + +off_t __lseek(int fd, off_t offset, int whence) +{ + off_t ret; + check_init("__lseek"); + ret = lseekx(fd, offset, whence, smbw_libc.__lseek); + if (smbw_debug) + { + printf("__lseek(%d, 0x%llx) returned 0x%llx\n", + fd, + (unsigned long long) offset, + (unsigned long long) ret); + } + return ret; +} + +off_t _lseek(int fd, off_t offset, int whence) +{ + off_t ret; + check_init("_lseek"); + ret = lseekx(fd, offset, whence, smbw_libc._lseek); + if (smbw_debug) + { + printf("_lseek(%d, 0x%llx) returned 0x%llx\n", + fd, + (unsigned long long) offset, + (unsigned long long) ret); + } + return ret; +} + +off64_t lseek64(int fd, off64_t offset, int whence) +{ + off64_t ret; + check_init("lseek64"); + ret = lseek64x(fd, offset, whence, smbw_libc.lseek64); + if (smbw_debug) + { + printf("lseek64(%d, 0x%llx) returned 0x%llx\n", + fd, + (unsigned long long) offset, + (unsigned long long) ret); + } + return ret; +} + +off64_t __lseek64(int fd, off64_t offset, int whence) +{ + check_init("__lseek64"); + return lseek64x(fd, offset, whence, smbw_libc.__lseek64); +} + +off64_t _lseek64(int fd, off64_t offset, int whence) +{ + off64_t ret; + check_init("_lseek64"); + ret = lseek64x(fd, offset, whence, smbw_libc._lseek64); + if (smbw_debug) + { + printf("_lseek64(%d, 0x%llx) returned 0x%llx\n", + fd, + (unsigned long long) offset, + (unsigned long long) ret); + } + return ret; +} + +ssize_t read(int fd, void *buf, size_t count) +{ + check_init("read"); + return readx(fd, buf, count, smbw_libc.read); +} + +ssize_t __read(int fd, void *buf, size_t count) +{ + check_init("__read"); + return readx(fd, buf, count, smbw_libc.__read); +} + +ssize_t _read(int fd, void *buf, size_t count) +{ + check_init("_read"); + return readx(fd, buf, count, smbw_libc._read); +} + +ssize_t write(int fd, const void *buf, size_t count) +{ + check_init("write"); + return writex(fd, (void *) buf, count, smbw_libc.write); +} + +ssize_t __write(int fd, const void *buf, size_t count) +{ + check_init("__write"); + return writex(fd, (void *) buf, count, smbw_libc.__write); +} + +ssize_t _write(int fd, const void *buf, size_t count) +{ + check_init("_write"); + return writex(fd, (void *) buf, count, smbw_libc._write); +} + +int access(const char *name, int mode) +{ + check_init("access"); + + if (smbw_path((char *) name)) { + return smbw_access((char *) name, mode); + } + + return (* smbw_libc.access)((char *) name, mode); +} + +int chmod(const char *name, mode_t mode) +{ + check_init("chmod"); + + if (smbw_path((char *) name)) { + return smbw_chmod((char *) name, mode); + } + + return (* smbw_libc.chmod)((char *) name, mode); +} + +int fchmod(int fd, mode_t mode) +{ + check_init("fchmod"); + + if (smbw_fd(fd)) { + /* Not yet implemented in libsmbclient */ + return ENOTSUP; + } + + return (* smbw_libc.fchmod)(fd, mode); +} + +int chown(const char *name, uid_t owner, gid_t group) +{ + check_init("chown"); + + if (smbw_path((char *) name)) { + return smbw_chown((char *) name, owner, group); + } + + return (* smbw_libc.chown)((char *) name, owner, group); +} + +int fchown(int fd, uid_t owner, gid_t group) +{ + check_init("fchown"); + + if (smbw_fd(fd)) { + /* Not yet implemented in libsmbclient */ + return ENOTSUP; + } + + return (* smbw_libc.fchown)(fd, owner, group); +} + +char *getcwd(char *buf, size_t size) +{ + check_init("getcwd"); + return (char *)smbw_getcwd(buf, size); +} + +int mkdir(const char *name, mode_t mode) +{ + check_init("mkdir"); + + if (smbw_path((char *) name)) { + return smbw_mkdir((char *) name, mode); + } + + return (* smbw_libc.mkdir)((char *) name, mode); +} + +int __fxstat(int vers, int fd, struct stat *st) +{ + check_init("__fxstat"); + + if (smbw_fd(fd)) { + struct SMBW_stat statbuf; + int ret = smbw_fstat(fd, &statbuf); + stat_convert(&statbuf, st); + return ret; + } + + return (* smbw_libc.__fxstat)(vers, fd, st); +} + +int __xstat(int vers, const char *name, struct stat *st) +{ + check_init("__xstat"); + + if (smbw_path((char *) name)) { + struct SMBW_stat statbuf; + int ret = smbw_stat((char *) name, &statbuf); + stat_convert(&statbuf, st); + return ret; + } + + return (* smbw_libc.__xstat)(vers, (char *) name, st); +} + +int __lxstat(int vers, const char *name, struct stat *st) +{ + check_init("__lxstat"); + + if (smbw_path((char *) name)) { + struct SMBW_stat statbuf; + int ret = smbw_stat((char *) name, &statbuf); + stat_convert(&statbuf, st); + return ret; + } + + return (* smbw_libc.__lxstat)(vers, (char *) name, st); +} + +int stat(const char *name, struct stat *st) +{ + check_init("stat"); + + if (smbw_path((char *) name)) { + struct SMBW_stat statbuf; + int ret = smbw_stat((char *) name, &statbuf); + stat_convert(&statbuf, st); + return ret; + } + + return (* smbw_libc.stat)((char *) name, st); +} + +int lstat(const char *name, struct stat *st) +{ + check_init("lstat"); + + if (smbw_path((char *) name)) { + struct SMBW_stat statbuf; + int ret = smbw_stat((char *) name, &statbuf); + stat_convert(&statbuf, st); + return ret; + } + + return (* smbw_libc.lstat)((char *) name, st); +} + +int fstat(int fd, struct stat *st) +{ + check_init("fstat"); + + if (smbw_fd(fd)) { + struct SMBW_stat statbuf; + int ret = smbw_fstat(fd, &statbuf); + stat_convert(&statbuf, st); + return ret; + } + + return (* smbw_libc.fstat)(fd, st); +} + +int unlink(const char *name) +{ + check_init("unlink"); + + if (smbw_path((char *) name)) { + return smbw_unlink((char *) name); + } + + return (* smbw_libc.unlink)((char *) name); +} + +int utime(const char *name, const struct utimbuf *tvp) +{ + check_init("utime"); + + if (smbw_path(name)) { + return smbw_utime(name, (struct utimbuf *) tvp); + } + + return (* smbw_libc.utime)((char *) name, (struct utimbuf *) tvp); +} + +int utimes(const char *name, const struct timeval *tvp) +{ + check_init("utimes"); + + if (smbw_path(name)) { + return smbw_utimes(name, (struct timeval *) tvp); + } + + return (* smbw_libc.utimes)((char *) name, (struct timeval *) tvp); +} + +int readlink(const char *path, char *buf, size_t bufsize) +{ + check_init("readlink"); + + if (smbw_path((char *) path)) { + return smbw_readlink(path, (char *) buf, bufsize); + } + + return (* smbw_libc.readlink)((char *) path, buf, bufsize); +} + +int rename(const char *oldname, const char *newname) +{ + int p1, p2; + + check_init("rename"); + + p1 = smbw_path((char *) oldname); + p2 = smbw_path((char *) newname); + if (p1 ^ p2) { + /* can't cross filesystem boundaries */ + errno = EXDEV; + return -1; + } + if (p1 && p2) { + return smbw_rename((char *) oldname, (char *) newname); + } + + return (* smbw_libc.rename)((char *) oldname, (char *) newname); +} + +int rmdir(const char *name) +{ + check_init("rmdir"); + + if (smbw_path((char *) name)) { + return smbw_rmdir((char *) name); + } + + return (* smbw_libc.rmdir)((char *) name); +} + +int symlink(const char *topath, const char *frompath) +{ + int p1, p2; + + check_init("symlink"); + + p1 = smbw_path((char *) topath); + p2 = smbw_path((char *) frompath); + if (p1 || p2) { + /* can't handle symlinks */ + errno = EPERM; + return -1; + } + + return (* smbw_libc.symlink)((char *) topath, (char *) frompath); +} + +int dup(int fd) +{ + check_init("dup"); + + if (smbw_fd(fd)) { + return smbw_dup(fd); + } + + return (* smbw_libc.dup)(fd); +} + +int dup2(int oldfd, int newfd) +{ + check_init("dup2"); + + if (smbw_fd(newfd)) { + (* smbw_libc.close)(newfd); + } + + if (smbw_fd(oldfd)) { + return smbw_dup2(oldfd, newfd); + } + + return (* smbw_libc.dup2)(oldfd, newfd); +} + + +DIR *opendir(const char *name) +{ + check_init("opendir"); + + if (smbw_path((char *) name)) { + return (void *)smbw_opendir((char *) name); + } + + return (* smbw_libc.opendir)((char *) name); +} + +struct dirent *readdir(DIR *dir) +{ + check_init("readdir"); + + if (smbw_dirp(dir)) { + static struct dirent external; + struct SMBW_dirent * internal = (void *)smbw_readdir(dir); + if (internal != NULL) { + dirent_convert(internal, &external); + return &external; + } + return NULL; + } + return (* smbw_libc.readdir)(dir); +} + +int closedir(DIR *dir) +{ + check_init("closedir"); + + if (smbw_dirp(dir)) { + return smbw_closedir(dir); + } + + return (* smbw_libc.closedir)(dir); +} + +long telldir(DIR *dir) +{ + check_init("telldir"); + + if (smbw_dirp(dir)) { + return (long) smbw_telldir(dir); + } + + return (* smbw_libc.telldir)(dir); +} + +void seekdir(DIR *dir, long offset) +{ + check_init("seekdir"); + + if (smbw_dirp(dir)) { + smbw_seekdir(dir, (long long) offset); + return; + } + + (* smbw_libc.seekdir)(dir, offset); +} + +int creat(const char *path, mode_t mode) +{ + extern int creat_bits; + + check_init("creat"); + return openx((char *) path, creat_bits, mode, smbw_libc.open); +} + +int creat64(const char *path, mode_t mode) +{ + extern int creat_bits; + + check_init("creat64"); + return openx((char *) path, creat_bits, mode, smbw_libc.open64); +} + +int __xstat64 (int ver, const char *name, struct stat64 *st64) +{ + check_init("__xstat64"); + + if (smbw_path((char *) name)) { + struct SMBW_stat statbuf; + int ret = smbw_stat((char *) name, &statbuf); + stat64_convert(&statbuf, st64); + return ret; + } + + return (* smbw_libc.__xstat64)(ver, (char *) name, st64); +} + +int stat64(const char *name, struct stat64 *st64) +{ + check_init("stat64"); + + if (smbw_path((char *) name)) { + struct SMBW_stat statbuf; + int ret = smbw_stat((char *) name, &statbuf); + stat64_convert(&statbuf, st64); + return ret; + } + + return (* smbw_libc.stat64)((char *) name, st64); +} + +int __fxstat64(int ver, int fd, struct stat64 *st64) +{ + check_init("__fxstat64"); + + if (smbw_fd(fd)) { + struct SMBW_stat statbuf; + int ret = smbw_fstat(fd, &statbuf); + stat64_convert(&statbuf, st64); + return ret; + } + + return (* smbw_libc.__fxstat64)(ver, fd, st64); +} + +int fstat64(int fd, struct stat64 *st64) +{ + check_init("fstat64"); + + if (smbw_fd(fd)) { + struct SMBW_stat statbuf; + int ret = smbw_fstat(fd, &statbuf); + stat64_convert(&statbuf, st64); + return ret; + } + + return (* smbw_libc.fstat64)(fd, st64); +} + +int __lxstat64(int ver, const char *name, struct stat64 *st64) +{ + check_init("__lxstat64"); + + if (smbw_path((char *) name)) { + struct SMBW_stat statbuf; + int ret = smbw_stat(name, &statbuf); + stat64_convert(&statbuf, st64); + return ret; + } + + return (* smbw_libc.__lxstat64)(ver, (char *) name, st64); +} + +int lstat64(const char *name, struct stat64 *st64) +{ + check_init("lstat64"); + + if (smbw_path((char *) name)) { + struct SMBW_stat statbuf; + int ret = smbw_stat((char *) name, &statbuf); + stat64_convert(&statbuf, st64); + return ret; + } + + return (* smbw_libc.lstat64)((char *) name, st64); +} + +int _llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t *result, unsigned int whence) +{ + check_init("_llseek"); + + if (smbw_fd(fd)) { + *result = lseek(fd, offset_low, whence); + return (*result < 0 ? -1 : 0); + } + + return (* smbw_libc._llseek)(fd, offset_high, offset_low, result, whence); +} + +struct dirent64 *readdir64(DIR *dir) +{ + check_init("readdir64"); + + if (smbw_dirp(dir)) { + static struct dirent64 external; + struct SMBW_dirent * internal = (void *)smbw_readdir(dir); + if (internal != NULL) { + dirent64_convert(internal, &external); + return &external; + } + return NULL; + } + + return (* smbw_libc.readdir64)(dir); +} + +int readdir_r(DIR *dir, struct dirent *external, struct dirent **result) +{ + check_init("readdir_r"); + + if (smbw_dirp(dir)) { + struct SMBW_dirent internal; + int ret = smbw_readdir_r(dir, &internal, NULL); + if (ret == 0) { + dirent_convert(&internal, external); + *result = external; + } + return ret; + } + + return (* smbw_libc.readdir_r)(dir, external, result); +} + +int readdir64_r(DIR *dir, struct dirent64 *external, struct dirent64 **result) +{ + check_init("readdir64_r"); + + if (smbw_dirp(dir)) { + struct SMBW_dirent internal; + int ret = smbw_readdir_r(dir, &internal, NULL); + if (ret == 0) { + dirent64_convert(&internal, external); + *result = external; + } + return ret; + } + + return (* smbw_libc.readdir64_r)(dir, external, result); +} + +int fork(void) +{ + check_init("fork"); + return smbw_fork(); +} + +int setxattr(const char *fname, + const char *name, + const void *value, + size_t size, + int flags) +{ + if (smbw_path(fname)) { + return smbw_setxattr(fname, name, value, size, flags); + } + + return (* smbw_libc.setxattr)(fname, name, value, size, flags); +} + +int lsetxattr(const char *fname, + const char *name, + const void *value, + size_t size, + int flags) +{ + if (smbw_path(fname)) { + return smbw_lsetxattr(fname, name, value, size, flags); + } + + return (* smbw_libc.lsetxattr)(fname, name, value, size, flags); +} + +int fsetxattr(int fd, + const char *name, + const void *value, + size_t size, + int flags) +{ + if (smbw_fd(fd)) { + return smbw_fsetxattr(fd, name, value, size, flags); + } + + return (* smbw_libc.fsetxattr)(fd, name, value, size, flags); +} + +int getxattr(const char *fname, + const char *name, + const void *value, + size_t size) +{ + if (smbw_path(fname)) { + return smbw_getxattr(fname, name, value, size); + } + + return (* smbw_libc.getxattr)(fname, name, value, size); +} + +int lgetxattr(const char *fname, + const char *name, + const void *value, + size_t size) +{ + if (smbw_path(fname)) { + return smbw_lgetxattr(fname, name, value, size); + } + + return (* smbw_libc.lgetxattr)(fname, name, value, size); +} + +int fgetxattr(int fd, + const char *name, + const void *value, + size_t size) +{ + if (smbw_fd(fd)) { + return smbw_fgetxattr(fd, name, value, size); + } + + return (* smbw_libc.fgetxattr)(fd, name, value, size); +} + +int removexattr(const char *fname, + const char *name) +{ + if (smbw_path(fname)) { + return smbw_removexattr(fname, name); + } + + return (* smbw_libc.removexattr)(fname, name); +} + +int lremovexattr(const char *fname, + const char *name) +{ + if (smbw_path(fname)) { + return smbw_lremovexattr(fname, name); + } + + return (* smbw_libc.lremovexattr)(fname, name); +} + +int fremovexattr(int fd, + const char *name) +{ + if (smbw_fd(fd)) { + return smbw_fremovexattr(fd, name); + } + + return (* smbw_libc.fremovexattr)(fd, name); +} + +int listxattr(const char *fname, + char *list, + size_t size) +{ + if (smbw_path(fname)) { + return smbw_listxattr(fname, list, size); + } + + return (* smbw_libc.listxattr)(fname, list, size); +} + +int llistxattr(const char *fname, + char *list, + size_t size) +{ + if (smbw_path(fname)) { + return smbw_llistxattr(fname, list, size); + } + + return (* smbw_libc.llistxattr)(fname, list, size); +} + +int flistxattr(int fd, + char *list, + size_t size) +{ + if (smbw_fd(fd)) { + return smbw_flistxattr(fd, list, size); + } + + return (* smbw_libc.flistxattr)(fd, list, size); +} + + +/* + * We're ending up with a different implementation of malloc() with smbwrapper + * than without it. The one with it does not support returning a non-NULL + * pointer from a call to malloc(0), and many apps depend on getting a valid + * pointer when requesting zero length (e.g. df, emacs). + * + * Unfortunately, initializing the smbw_libc[] array via the dynamic link + * library (libdl) requires malloc so we can't just do the same type of + * mapping to the C library as we do with everything else. We need to + * implement a different way of allocating memory that ensures that the C + * library version of malloc() gets used. This is the only place where we + * kludge the code to use an undocumented interface to the C library. + * + * If anyone can come up with a way to dynamically link to the C library + * rather than using this undocumented interface, I'd sure love to hear about + * it. Better yet, if you can figure out where the alternate malloc() + * functions are coming from and arrange for them not to be called, that would + * be even better. We should try to avoid wrapping functions that don't + * really require it. + */ + +void *malloc(size_t size) +{ + void *__libc_malloc(size_t size); + return __libc_malloc(size); +} + +void *calloc(size_t nmemb, size_t size) +{ + void *__libc_calloc(size_t nmemb, size_t size); + return __libc_calloc(nmemb, size); +} + +void *realloc(void *ptr, size_t size) +{ + void *__libc_realloc(void *ptr, size_t size); + return __libc_realloc(ptr, size); +} + +void free(void *ptr) +{ + static int in_progress = 0; + void __libc_free(void *ptr); + + if (in_progress) return; + in_progress = 1; + __libc_free(ptr); + in_progress = 0; +} + + +#if 0 /* SELECT */ + +static struct sigaction user_action[_NSIG]; + +static void +smbw_sigaction_handler(int signum, + siginfo_t *info, + void *context) +{ + /* Our entire purpose for trapping signals is to call this! */ + sys_select_signal(); + + /* Call the user's handler */ + if (user_action[signum].sa_handler != SIG_IGN && + user_action[signum].sa_handler != SIG_DFL && + user_action[signum].sa_handler != SIG_ERR) { + (* user_action[signum].sa_sigaction)(signum, info, context); + } +} + + +/* + * Every Samba signal handler must call sys_select_signal() to avoid a race + * condition, so we'll take whatever signal handler is currently assigned, + * call call sys_select_signal() in addition to their call. + */ +static int +do_select(int n, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout, + int (* select_fn)(int n, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout)) +{ + int i; + int ret; + int saved_errno; + sigset_t sigset; + struct sigaction new_action; + + saved_errno = errno; + for (i=1; i<_NSIG; i++) { + sigemptyset(&sigset); + new_action.sa_mask = sigset; + new_action.sa_flags = SA_SIGINFO; + new_action.sa_sigaction = smbw_sigaction_handler; + + if (sigaction(i, &new_action, &user_action[i]) < 0) { + if (errno != EINVAL) { + return -1; + } + } + } + errno = saved_errno; + + ret = (* select_fn)(n, readfds, writefds, exceptfds, timeout); + saved_errno = errno; + + for (i=0; i<_NSIG; i++) { + (void) sigaction(i, &user_action[i], NULL); + } + + errno = saved_errno; + return ret; +} + +int +select(int n, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout) +{ + check_init("select"); + + return do_select(n, readfds, writefds, exceptfds, + timeout, smbw_libc.select); +} + +int +_select(int n, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout) +{ + check_init("_select"); + + return do_select(n, readfds, writefds, exceptfds, + timeout, smbw_libc._select); +} + +int +__select(int n, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout) +{ + check_init("__select"); + + return do_select(n, readfds, writefds, exceptfds, + timeout, smbw_libc.__select); +} + +#endif diff --git a/examples/libsmbclient/smbwrapper/wrapper.h b/examples/libsmbclient/smbwrapper/wrapper.h new file mode 100644 index 0000000000..6d0d9f527a --- /dev/null +++ b/examples/libsmbclient/smbwrapper/wrapper.h @@ -0,0 +1,209 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + SMB wrapper functions + Copyright (C) Derrell Lipman 2003-2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __WRAPPER_H__ +#define __WRAPPER_H__ + +#include <sys/stat.h> +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <dirent.h> +#include <utime.h> +#include <signal.h> +#include <stdio.h> + +extern int smbw_fd_map[__FD_SETSIZE]; +extern int smbw_ref_count[__FD_SETSIZE]; +extern char smbw_cwd[PATH_MAX]; +extern char smbw_prefix[]; + +typedef struct SMBW_stat { + unsigned long s_dev; /* device */ + unsigned long s_ino; /* inode */ + unsigned long s_mode; /* protection */ + unsigned long s_nlink; /* number of hard links */ + unsigned long s_uid; /* user ID of owner */ + unsigned long s_gid; /* group ID of owner */ + unsigned long s_rdev; /* device type (if inode device) */ + unsigned long long s_size; /* total size, in bytes */ + unsigned long s_blksize; /* blocksize for filesystem I/O */ + unsigned long s_blocks; /* number of blocks allocated */ + unsigned long s_atime; /* time of last access */ + unsigned long s_mtime; /* time of last modification */ + unsigned long s_ctime; /* time of last change */ +} SMBW_stat; + +typedef struct SMBW_dirent { + unsigned long d_ino; /* inode number */ + unsigned long long d_off; /* offset to the next dirent */ + unsigned long d_reclen; /* length of this record */ + unsigned long d_type; /* type of file */ + char d_name[256]; /* filename */ + char d_comment[256]; /* comment */ +} SMBW_dirent; + +struct kernel_sigaction { + __sighandler_t k_sa_handler; + unsigned long sa_flags; + sigset_t sa_mask; +}; + +typedef struct SMBW_libc +{ + /* write() is first, to allow debugging */ + ssize_t (* write)(int fd, void *buf, size_t count); + int (* open)(char *name, int flags, mode_t mode); + int (* _open)(char *name, int flags, mode_t mode) ; + int (* __open)(char *name, int flags, mode_t mode) ; + int (* open64)(char *name, int flags, mode_t mode); + int (* _open64)(char *name, int flags, mode_t mode) ; + int (* __open64)(char *name, int flags, mode_t mode) ; + ssize_t (* pread)(int fd, void *buf, size_t size, off_t ofs); + ssize_t (* pread64)(int fd, void *buf, size_t size, off64_t ofs); + ssize_t (* pwrite)(int fd, void *buf, size_t size, off_t ofs); + ssize_t (* pwrite64)(int fd, void *buf, size_t size, off64_t ofs); + int (* close)(int fd); + int (* __close)(int fd); + int (* _close)(int fd); + int (* fcntl)(int fd, int cmd, long arg); + int (* __fcntl)(int fd, int cmd, long arg); + int (* _fcntl)(int fd, int cmd, long arg); + int (* getdents)(int fd, struct dirent *dirp, unsigned int count); + int (* __getdents)(int fd, struct dirent *dirp, unsigned int count); + int (* _getdents)(int fd, struct dirent *dirp, unsigned int count); + int (* getdents64)(int fd, struct dirent64 *dirp, unsigned int count); + off_t (* lseek)(int fd, off_t offset, int whence); + off_t (* __lseek)(int fd, off_t offset, int whence); + off_t (* _lseek)(int fd, off_t offset, int whence); + off64_t (* lseek64)(int fd, off64_t offset, int whence); + off64_t (* __lseek64)(int fd, off64_t offset, int whence); + off64_t (* _lseek64)(int fd, off64_t offset, int whence); + ssize_t (* read)(int fd, void *buf, size_t count); + ssize_t (* __read)(int fd, void *buf, size_t count); + ssize_t (* _read)(int fd, void *buf, size_t count); + ssize_t (* __write)(int fd, void *buf, size_t count); + ssize_t (* _write)(int fd, void *buf, size_t count); + int (* access)(char *name, int mode); + int (* chmod)(char *name, mode_t mode); + int (* fchmod)(int fd, mode_t mode); + int (* chown)(char *name, uid_t owner, gid_t group); + int (* fchown)(int fd, uid_t owner, gid_t group); + int (* __xstat)(int vers, char *name, struct stat *st); + char * ( *getcwd)(char *buf, size_t size); + int (* mkdir)(char *name, mode_t mode); + int (* __fxstat)(int vers, int fd, struct stat *st); + int (* __lxstat)(int vers, char *name, struct stat *st); + int (* stat)(char *name, struct stat *st); + int (* lstat)(char *name, struct stat *st); + int (* fstat)(int fd, struct stat *st); + int (* unlink)(char *name); + int (* utime)(char *name, struct utimbuf *tvp); + int (* utimes)(char *name, struct timeval *tvp); + int (* readlink)(char *path, char *buf, size_t bufsize); + int (* rename)(char *oldname, char *newname); + int (* rmdir)(char *name); + int (* symlink)(char *topath, char *frompath); + int (* dup)(int fd); + int (* dup2)(int oldfd, int newfd); + DIR * (* opendir)(char *name); + struct dirent * (* readdir)(DIR *dir); + int (* closedir)(DIR *dir); + off_t (* telldir)(DIR *dir); + void (* seekdir)(DIR *dir, off_t offset); + int (* creat)(char *path, mode_t mode); + int (* creat64)(char *path, mode_t mode); + int (* __xstat64)(int ver, char *name, struct stat64 *st64); + int (* stat64)(char *name, struct stat64 *st64); + int (* __fxstat64)(int ver, int fd, struct stat64 *st64); + int (* fstat64)(int fd, struct stat64 *st64); + int (* __lxstat64)(int ver, char *name, struct stat64 *st64); + int (* lstat64)(char *name, struct stat64 *st64); + int (* _llseek)(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t *result, unsigned int whence); + struct dirent64 * (* readdir64)(DIR *dir); + int (* readdir_r)(DIR *dir, struct dirent *entry, struct dirent **result); + int (* readdir64_r)(DIR *dir, struct dirent64 *entry, struct dirent64 **result); + int (* setxattr)(const char *fname, + const char *name, + const void *value, + size_t size, + int flags); + int (* lsetxattr)(const char *fname, + const char *name, + const void *value, + size_t size, + int flags); + int (* fsetxattr)(int smbw_fd, + const char *name, + const void *value, + size_t size, + int flags); + int (* getxattr)(const char *fname, + const char *name, + const void *value, + size_t size); + int (* lgetxattr)(const char *fname, + const char *name, + const void *value, + size_t size); + int (* fgetxattr)(int smbw_fd, + const char *name, + const void *value, + size_t size); + int (* removexattr)(const char *fname, + const char *name); + int (* lremovexattr)(const char *fname, + const char *name); + int (* fremovexattr)(int smbw_fd, + const char *name); + int (* listxattr)(const char *fname, + char *list, + size_t size); + int (* llistxattr)(const char *fname, + char *list, + size_t size); + int (* flistxattr)(int smbw_fd, + char *list, + size_t size); + int (* chdir)(const char *path); + int (* fchdir)(int fd); + pid_t (* fork)(void); + int (* select)(int n, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout); + int (* _select)(int n, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout); + int (* __select)(int n, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout); +} SMBW_libc_pointers; + +extern SMBW_libc_pointers smbw_libc; + +#endif /* __WRAPPER_H__ */ |