diff options
Diffstat (limited to 'source3/smbwrapper/smbw.c')
-rw-r--r-- | source3/smbwrapper/smbw.c | 1554 |
1 files changed, 1554 insertions, 0 deletions
diff --git a/source3/smbwrapper/smbw.c b/source3/smbwrapper/smbw.c new file mode 100644 index 0000000000..2dd7c4ea6d --- /dev/null +++ b/source3/smbwrapper/smbw.c @@ -0,0 +1,1554 @@ +/* + Unix SMB/CIFS implementation. + SMB wrapper functions + Copyright (C) Andrew Tridgell 1998 + + 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 "includes.h" +#include "realcalls.h" + +pstring smbw_cwd; + +static struct smbw_file *smbw_files; +static struct smbw_server *smbw_srvs; + +struct bitmap *smbw_file_bmap; +extern pstring global_myname; + +fstring smbw_prefix = SMBW_PREFIX; + +int smbw_busy=0; + +/* needs to be here because of dumb include files on some systems */ +int creat_bits = O_WRONLY|O_CREAT|O_TRUNC; + + +/***************************************************** +initialise structures +*******************************************************/ +void smbw_init(void) +{ + extern BOOL in_client; + static int initialised; + char *p; + int eno; + pstring line; + + if (initialised) return; + initialised = 1; + + eno = errno; + + smbw_busy++; + + DEBUGLEVEL = 0; + setup_logging("smbsh",True); + + dbf = x_stderr; + + if ((p=smbw_getshared("LOGFILE"))) { + dbf = sys_fopen(p, "a"); + } + + smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN); + if (!smbw_file_bmap) { + exit(1); + } + + in_client = True; + + load_interfaces(); + + if ((p=smbw_getshared("SERVICESF"))) { + pstrcpy(dyn_CONFIGFILE, p); + } + + lp_load(dyn_CONFIGFILE,True,False,False); + + get_myname(global_myname); + + if ((p=smbw_getshared("DEBUG"))) { + DEBUGLEVEL = atoi(p); + } + + if ((p=smbw_getshared("RESOLVE_ORDER"))) { + lp_set_name_resolve_order(p); + } + + if ((p=smbw_getshared("PREFIX"))) { + slprintf(smbw_prefix,sizeof(fstring)-1, "/%s/", p); + all_string_sub(smbw_prefix,"//", "/", 0); + DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix)); + } + + slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid()); + + p = smbw_getshared(line); + if (!p) { + sys_getwd(smbw_cwd); + } + pstrcpy(smbw_cwd, p); + DEBUG(4,("Initial cwd is %s\n", smbw_cwd)); + + smbw_busy--; + + set_maxfiles(SMBW_MAX_OPEN); + + BlockSignals(True,SIGPIPE); + + errno = eno; +} + +/***************************************************** +determine if a file descriptor is a smb one +*******************************************************/ +int smbw_fd(int fd) +{ + if (smbw_busy) return 0; + return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd); +} + +/***************************************************** +determine if a file descriptor is an internal smbw fd +*******************************************************/ +int smbw_local_fd(int fd) +{ + struct smbw_server *srv; + + smbw_init(); + + if (smbw_busy) return 0; + if (smbw_shared_fd(fd)) return 1; + + for (srv=smbw_srvs;srv;srv=srv->next) { + if (srv->cli.fd == fd) return 1; + } + + return 0; +} + +/***************************************************** +a crude inode number generator +*******************************************************/ +ino_t smbw_inode(const char *name) +{ + if (!*name) return 2; + return (ino_t)str_checksum(name); +} + +/***************************************************** +remove redundent stuff from a filename +*******************************************************/ +void clean_fname(char *name) +{ + char *p, *p2; + int l; + int modified = 1; + + if (!name) return; + + while (modified) { + modified = 0; + + DEBUG(5,("cleaning %s\n", name)); + + if ((p=strstr(name,"/./"))) { + modified = 1; + while (*p) { + p[0] = p[2]; + p++; + } + } + + if ((p=strstr(name,"//"))) { + modified = 1; + while (*p) { + p[0] = p[1]; + p++; + } + } + + if (strcmp(name,"/../")==0) { + modified = 1; + name[1] = 0; + } + + if ((p=strstr(name,"/../"))) { + modified = 1; + for (p2=(p>name?p-1:p);p2>name;p2--) { + if (p2[0] == '/') break; + } + while (*p2) { + p2[0] = p2[3]; + p2++; + } + } + + if (strcmp(name,"/..")==0) { + modified = 1; + name[1] = 0; + } + + 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; + } + } + + l = strlen(name); + p = l>=2?(name+l-2):name; + if (strcmp(p,"/.")==0) { + if (p == name) { + p[1] = 0; + } else { + p[0] = 0; + } + } + + if (strncmp(p=name,"./",2) == 0) { + modified = 1; + do { + p[0] = p[2]; + } while (*p++); + } + + l = strlen(p=name); + if (l > 1 && p[l-1] == '/') { + modified = 1; + p[l-1] = 0; + } + } +} + + + +/***************************************************** +find a workgroup (any workgroup!) that has a master +browser on the local network +*******************************************************/ +static char *smbw_find_workgroup(void) +{ + fstring server; + char *p; + struct in_addr *ip_list = NULL; + int count = 0; + int i; + + /* first off see if an existing workgroup name exists */ + p = smbw_getshared("WORKGROUP"); + if (!p) p = lp_workgroup(); + + slprintf(server, sizeof(server), "%s#1D", p); + if (smbw_server(server, "IPC$")) return p; + + /* go looking for workgroups */ + if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) { + DEBUG(1,("No workgroups found!")); + return p; + } + + for (i=0;i<count;i++) { + static fstring name; + if (name_status_find("*", 0, 0x1d, ip_list[i], name)) { + slprintf(server, sizeof(server), "%s#1D", name); + if (smbw_server(server, "IPC$")) { + smbw_setshared("WORKGROUP", name); + SAFE_FREE(ip_list); + return name; + } + } + } + + SAFE_FREE(ip_list); + + return p; +} + +/***************************************************** +parse a smb path into its components. +server is one of + 1) the name of the SMB server + 2) WORKGROUP#1D for share listing + 3) WORKGROUP#__ for workgroup listing +share is the share on the server to query +path is the SMB path on the server +return the full path (ie. add cwd if needed) +*******************************************************/ +char *smbw_parse_path(const char *fname, char *server, char *share, char *path) +{ + static pstring s; + char *p; + int len; + fstring workgroup; + + /* add cwd if necessary */ + if (fname[0] != '/') { + slprintf(s, sizeof(s), "%s/%s", smbw_cwd, fname); + } else { + pstrcpy(s, fname); + } + clean_fname(s); + + /* see if it has the right prefix */ + len = strlen(smbw_prefix)-1; + if (strncmp(s,smbw_prefix,len) || + (s[len] != '/' && s[len] != 0)) return s; + + /* ok, its for us. Now parse out the workgroup, share etc. */ + p = s+len; + if (*p == '/') p++; + if (!next_token(&p, workgroup, "/", sizeof(fstring))) { + /* we're in /smb - give a list of workgroups */ + slprintf(server,sizeof(fstring), "%s#01", smbw_find_workgroup()); + fstrcpy(share,"IPC$"); + pstrcpy(path,""); + return s; + } + + if (!next_token(&p, server, "/", sizeof(fstring))) { + /* we are in /smb/WORKGROUP */ + slprintf(server,sizeof(fstring), "%s#1D", workgroup); + fstrcpy(share,"IPC$"); + pstrcpy(path,""); + } + + if (!next_token(&p, share, "/", sizeof(fstring))) { + /* we are in /smb/WORKGROUP/SERVER */ + fstrcpy(share,"IPC$"); + pstrcpy(path,""); + } + + pstrcpy(path, p); + + all_string_sub(path, "/", "\\", 0); + + return s; +} + +/***************************************************** +determine if a path name (possibly relative) is in the +smb name space +*******************************************************/ +int smbw_path(const char *path) +{ + fstring server, share; + pstring s; + char *cwd; + int len; + + if(!path) + return 0; + + /* this is needed to prevent recursion with the BSD malloc which + opens /etc/malloc.conf on the first call */ + if (strncmp(path,"/etc/", 5) == 0) { + return 0; + } + + smbw_init(); + + len = strlen(smbw_prefix)-1; + + if (path[0] == '/' && strncmp(path,smbw_prefix,len)) { + return 0; + } + + if (smbw_busy) return 0; + + DEBUG(3,("smbw_path(%s)\n", path)); + + cwd = smbw_parse_path(path, server, share, s); + + if (strncmp(cwd,smbw_prefix,len) == 0 && + (cwd[len] == '/' || cwd[len] == 0)) { + return 1; + } + + return 0; +} + +/***************************************************** +return a unix errno from a SMB error pair +*******************************************************/ +int smbw_errno(struct cli_state *c) +{ + return cli_errno(c); +} + +/* Return a username and password given a server and share name */ + +void get_envvar_auth_data(char *server, char *share, char **workgroup, + char **username, char **password) +{ + /* Fall back to shared memory/environment variables */ + + *username = smbw_getshared("USER"); + if (!*username) *username = getenv("USER"); + if (!*username) *username = "guest"; + + *workgroup = smbw_getshared("WORKGROUP"); + if (!*workgroup) *workgroup = lp_workgroup(); + + *password = smbw_getshared("PASSWORD"); + if (!*password) *password = ""; +} + +static smbw_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data; + +/***************************************************** +set the get auth data function +******************************************************/ +void smbw_set_auth_data_fn(smbw_get_auth_data_fn fn) +{ + get_auth_data_fn = fn; +} + +/***************************************************** +return a connection to a server (existing or new) +*******************************************************/ +struct smbw_server *smbw_server(char *server, char *share) +{ + struct smbw_server *srv=NULL; + struct cli_state c; + char *username; + char *password; + char *workgroup; + struct nmb_name called, calling; + char *p, *server_n = server; + fstring group; + pstring ipenv; + struct in_addr ip; + + zero_ip(&ip); + ZERO_STRUCT(c); + + get_auth_data_fn(server, share, &workgroup, &username, &password); + + /* try to use an existing connection */ + for (srv=smbw_srvs;srv;srv=srv->next) { + if (strcmp(server,srv->server_name)==0 && + strcmp(share,srv->share_name)==0 && + strcmp(workgroup,srv->workgroup)==0 && + strcmp(username, srv->username) == 0) + return srv; + } + + if (server[0] == 0) { + errno = EPERM; + return NULL; + } + + make_nmb_name(&calling, global_myname, 0x0); + make_nmb_name(&called , server, 0x20); + + DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server)); + + if ((p=strchr_m(server_n,'#')) && + (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) { + struct in_addr sip; + pstring s; + + fstrcpy(group, server_n); + p = strchr_m(group,'#'); + *p = 0; + + /* cache the workgroup master lookup */ + slprintf(s,sizeof(s)-1,"MASTER_%s", group); + if (!(server_n = smbw_getshared(s))) { + if (!find_master_ip(group, &sip)) { + errno = ENOENT; + return NULL; + } + fstrcpy(group, inet_ntoa(sip)); + server_n = group; + smbw_setshared(s,server_n); + } + } + + DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); + + again: + slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n); + + zero_ip(&ip); + if ((p=smbw_getshared(ipenv))) { + ip = *(interpret_addr2(p)); + } + + /* have to open a new connection */ + if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) { + errno = ENOENT; + return NULL; + } + + if (!cli_session_request(&c, &calling, &called)) { + cli_shutdown(&c); + if (strcmp(called.name, "*SMBSERVER")) { + make_nmb_name(&called , "*SMBSERVER", 0x20); + goto again; + } + errno = ENOENT; + return NULL; + } + + DEBUG(4,(" session request ok\n")); + + if (!cli_negprot(&c)) { + cli_shutdown(&c); + errno = ENOENT; + return NULL; + } + + if (!cli_session_setup(&c, username, + password, strlen(password), + password, strlen(password), + workgroup) && + /* try an anonymous login if it failed */ + !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) { + cli_shutdown(&c); + errno = EPERM; + return NULL; + } + + DEBUG(4,(" session setup ok\n")); + + if (!cli_send_tconX(&c, share, "?????", + password, strlen(password)+1)) { + errno = smbw_errno(&c); + cli_shutdown(&c); + return NULL; + } + + smbw_setshared(ipenv,inet_ntoa(ip)); + + DEBUG(4,(" tconx ok\n")); + + srv = (struct smbw_server *)malloc(sizeof(*srv)); + if (!srv) { + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(srv); + + srv->cli = c; + + srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); + + srv->server_name = strdup(server); + if (!srv->server_name) { + errno = ENOMEM; + goto failed; + } + + srv->share_name = strdup(share); + if (!srv->share_name) { + errno = ENOMEM; + goto failed; + } + + srv->workgroup = strdup(workgroup); + if (!srv->workgroup) { + errno = ENOMEM; + goto failed; + } + + srv->username = strdup(username); + if (!srv->username) { + errno = ENOMEM; + goto failed; + } + + /* some programs play with file descriptors fairly intimately. We + try to get out of the way by duping to a high fd number */ + if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) { + if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) == + srv->cli.fd+SMBW_CLI_FD) { + close(srv->cli.fd); + srv->cli.fd += SMBW_CLI_FD; + } + } + + DLIST_ADD(smbw_srvs, srv); + + return srv; + + failed: + cli_shutdown(&c); + if (!srv) return NULL; + + SAFE_FREE(srv->server_name); + SAFE_FREE(srv->share_name); + SAFE_FREE(srv); + return NULL; +} + + +/***************************************************** +map a fd to a smbw_file structure +*******************************************************/ +struct smbw_file *smbw_file(int fd) +{ + struct smbw_file *file; + + for (file=smbw_files;file;file=file->next) { + if (file->fd == fd) return file; + } + return NULL; +} + +/***************************************************** +a wrapper for open() +*******************************************************/ +int smbw_open(const char *fname, int flags, mode_t mode) +{ + fstring server, share; + pstring path; + struct smbw_server *srv=NULL; + int eno=0, fd = -1; + struct smbw_file *file=NULL; + + smbw_init(); + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (path[strlen(path)-1] == '\\') { + fd = -1; + } else { + fd = cli_open(&srv->cli, path, flags, DENY_NONE); + } + if (fd == -1) { + /* it might be a directory. Maybe we should use chkpath? */ + eno = smbw_errno(&srv->cli); + fd = smbw_dir_open(fname); + if (fd == -1) errno = eno; + smbw_busy--; + return fd; + } + + file = (struct smbw_file *)malloc(sizeof(*file)); + if (!file) { + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(file); + + file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f))); + if (!file->f) { + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(file->f); + + file->f->cli_fd = fd; + file->f->fname = strdup(path); + if (!file->f->fname) { + errno = ENOMEM; + goto failed; + } + file->srv = srv; + file->fd = open(SMBW_DUMMY, O_WRONLY); + if (file->fd == -1) { + errno = EMFILE; + goto failed; + } + + if (bitmap_query(smbw_file_bmap, file->fd)) { + DEBUG(0,("ERROR: fd used in smbw_open\n")); + errno = EIO; + goto failed; + } + + file->f->ref_count=1; + + bitmap_set(smbw_file_bmap, file->fd); + + DLIST_ADD(smbw_files, file); + + DEBUG(4,("opened %s\n", fname)); + + smbw_busy--; + return file->fd; + + failed: + if (fd != -1) { + cli_close(&srv->cli, fd); + } + if (file) { + if (file->f) { + SAFE_FREE(file->f->fname); + SAFE_FREE(file->f); + } + SAFE_FREE(file); + } + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for pread() +*******************************************************/ +ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs) +{ + struct smbw_file *file; + int ret; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + smbw_busy--; + return -1; + } + + ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count); + + if (ret == -1) { + errno = smbw_errno(&file->srv->cli); + smbw_busy--; + return -1; + } + + smbw_busy--; + return ret; +} + +/***************************************************** +a wrapper for read() +*******************************************************/ +ssize_t smbw_read(int fd, void *buf, size_t count) +{ + struct smbw_file *file; + int ret; + + DEBUG(4,("smbw_read(%d, %d)\n", fd, (int)count)); + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + smbw_busy--; + return -1; + } + + ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, + file->f->offset, count); + + if (ret == -1) { + errno = smbw_errno(&file->srv->cli); + smbw_busy--; + return -1; + } + + file->f->offset += ret; + + DEBUG(4,(" -> %d\n", ret)); + + smbw_busy--; + return ret; +} + + + +/***************************************************** +a wrapper for write() +*******************************************************/ +ssize_t smbw_write(int fd, void *buf, size_t count) +{ + struct smbw_file *file; + int ret; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + smbw_busy--; + return -1; + } + + ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, file->f->offset, count); + + if (ret == -1) { + errno = smbw_errno(&file->srv->cli); + smbw_busy--; + return -1; + } + + file->f->offset += ret; + + smbw_busy--; + return ret; +} + +/***************************************************** +a wrapper for pwrite() +*******************************************************/ +ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs) +{ + struct smbw_file *file; + int ret; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + smbw_busy--; + return -1; + } + + ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, ofs, count); + + if (ret == -1) { + errno = smbw_errno(&file->srv->cli); + smbw_busy--; + return -1; + } + + smbw_busy--; + return ret; +} + +/***************************************************** +a wrapper for close() +*******************************************************/ +int smbw_close(int fd) +{ + struct smbw_file *file; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + int ret = smbw_dir_close(fd); + smbw_busy--; + return ret; + } + + if (file->f->ref_count == 1 && + !cli_close(&file->srv->cli, file->f->cli_fd)) { + errno = smbw_errno(&file->srv->cli); + smbw_busy--; + return -1; + } + + + bitmap_clear(smbw_file_bmap, file->fd); + close(file->fd); + + DLIST_REMOVE(smbw_files, file); + + file->f->ref_count--; + if (file->f->ref_count == 0) { + SAFE_FREE(file->f->fname); + SAFE_FREE(file->f); + } + ZERO_STRUCTP(file); + SAFE_FREE(file); + + smbw_busy--; + + return 0; +} + + +/***************************************************** +a wrapper for fcntl() +*******************************************************/ +int smbw_fcntl(int fd, int cmd, long arg) +{ + return 0; +} + + +/***************************************************** +a wrapper for access() +*******************************************************/ +int smbw_access(const char *name, int mode) +{ + struct stat st; + + DEBUG(4,("smbw_access(%s, 0x%x)\n", name, mode)); + + if (smbw_stat(name, &st)) return -1; + + if (((mode & R_OK) && !(st.st_mode & S_IRUSR)) || + ((mode & W_OK) && !(st.st_mode & S_IWUSR)) || + ((mode & X_OK) && !(st.st_mode & S_IXUSR))) { + errno = EACCES; + return -1; + } + + return 0; +} + +/***************************************************** +a wrapper for realink() - needed for correct errno setting +*******************************************************/ +int smbw_readlink(const char *path, char *buf, size_t bufsize) +{ + struct stat st; + int ret; + + ret = smbw_stat(path, &st); + if (ret != 0) { + DEBUG(4,("readlink(%s) failed\n", path)); + return -1; + } + + /* it exists - say it isn't a link */ + DEBUG(4,("readlink(%s) not a link\n", path)); + + errno = EINVAL; + return -1; +} + + +/***************************************************** +a wrapper for unlink() +*******************************************************/ +int smbw_unlink(const char *fname) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (strncmp(srv->cli.dev, "LPT", 3) == 0) { + int job = smbw_stat_printjob(srv, path, NULL, NULL); + if (job == -1) { + goto failed; + } + if (cli_printjob_del(&srv->cli, job) != 0) { + goto failed; + } + } else if (!cli_unlink(&srv->cli, path)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for rename() +*******************************************************/ +int smbw_rename(const char *oldname, const char *newname) +{ + struct smbw_server *srv; + fstring server1, share1; + pstring path1; + fstring server2, share2; + pstring path2; + + if (!oldname || !newname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + DEBUG(4,("smbw_rename(%s,%s)\n", oldname, newname)); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(oldname, server1, share1, path1); + smbw_parse_path(newname, server2, share2, path2); + + if (strcmp(server1, server2) || strcmp(share1, share2)) { + /* can't cross filesystems */ + errno = EXDEV; + return -1; + } + + /* get a connection to the server */ + srv = smbw_server(server1, share1); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (!cli_rename(&srv->cli, path1, path2)) { + int eno = smbw_errno(&srv->cli); + if (eno != EEXIST || + !cli_unlink(&srv->cli, path2) || + !cli_rename(&srv->cli, path1, path2)) { + errno = eno; + goto failed; + } + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for utime and utimes +*******************************************************/ +static int smbw_settime(const char *fname, time_t t) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + uint16 mode; + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + if (!cli_setatr(&srv->cli, path, mode, t)) { + /* some servers always refuse directory changes */ + if (!(mode & aDIR)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + +/***************************************************** +a wrapper for utime +*******************************************************/ +int smbw_utime(const char *fname, void *buf) +{ + struct utimbuf *tbuf = (struct utimbuf *)buf; + return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL)); +} + +/***************************************************** +a wrapper for utime +*******************************************************/ +int smbw_utimes(const char *fname, void *buf) +{ + struct timeval *tbuf = (struct timeval *)buf; + return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL)); +} + + +/***************************************************** +a wrapper for chown() +*******************************************************/ +int smbw_chown(const char *fname, uid_t owner, gid_t group) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + uint16 mode; + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + /* assume success */ + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + +/***************************************************** +a wrapper for chmod() +*******************************************************/ +int smbw_chmod(const char *fname, mode_t newmode) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + uint32 mode; + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + smbw_busy++; + + /* work out what server they are after */ + smbw_parse_path(fname, server, share, path); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + mode = 0; + + if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY; + if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH; + if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM; + if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN; + + if (!cli_setatr(&srv->cli, path, mode, 0)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + +/***************************************************** +a wrapper for lseek() +*******************************************************/ +off_t smbw_lseek(int fd, off_t offset, int whence) +{ + struct smbw_file *file; + size_t size; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + off_t ret = smbw_dir_lseek(fd, offset, whence); + smbw_busy--; + return ret; + } + + switch (whence) { + case SEEK_SET: + file->f->offset = offset; + break; + case SEEK_CUR: + file->f->offset += offset; + break; + case SEEK_END: + if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd, + NULL, &size, NULL, NULL, NULL, + NULL, NULL) && + !cli_getattrE(&file->srv->cli, file->f->cli_fd, + NULL, &size, NULL, NULL, NULL)) { + errno = EINVAL; + smbw_busy--; + return -1; + } + file->f->offset = size + offset; + break; + } + + smbw_busy--; + return file->f->offset; +} + + +/***************************************************** +a wrapper for dup() +*******************************************************/ +int smbw_dup(int fd) +{ + int fd2; + struct smbw_file *file, *file2; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + goto failed; + } + + fd2 = dup(file->fd); + if (fd2 == -1) { + goto failed; + } + + if (bitmap_query(smbw_file_bmap, fd2)) { + DEBUG(0,("ERROR: fd already open in dup!\n")); + errno = EIO; + goto failed; + } + + file2 = (struct smbw_file *)malloc(sizeof(*file2)); + if (!file2) { + close(fd2); + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(file2); + + *file2 = *file; + file2->fd = fd2; + + file->f->ref_count++; + + bitmap_set(smbw_file_bmap, fd2); + + DLIST_ADD(smbw_files, file2); + + smbw_busy--; + return fd2; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for dup2() +*******************************************************/ +int smbw_dup2(int fd, int fd2) +{ + struct smbw_file *file, *file2; + + smbw_busy++; + + file = smbw_file(fd); + if (!file) { + errno = EBADF; + goto failed; + } + + if (bitmap_query(smbw_file_bmap, fd2)) { + DEBUG(0,("ERROR: fd already open in dup2!\n")); + errno = EIO; + goto failed; + } + + if (dup2(file->fd, fd2) != fd2) { + goto failed; + } + + file2 = (struct smbw_file *)malloc(sizeof(*file2)); + if (!file2) { + close(fd2); + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(file2); + + *file2 = *file; + file2->fd = fd2; + + file->f->ref_count++; + + bitmap_set(smbw_file_bmap, fd2); + + DLIST_ADD(smbw_files, file2); + + smbw_busy--; + return fd2; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +close a connection to a server +*******************************************************/ +static void smbw_srv_close(struct smbw_server *srv) +{ + smbw_busy++; + + cli_shutdown(&srv->cli); + + SAFE_FREE(srv->server_name); + SAFE_FREE(srv->share_name); + + DLIST_REMOVE(smbw_srvs, srv); + + ZERO_STRUCTP(srv); + + SAFE_FREE(srv); + + smbw_busy--; +} + +/***************************************************** +when we fork we have to close all connections and files +in the child +*******************************************************/ +int smbw_fork(void) +{ + pid_t child; + int p[2]; + char c=0; + pstring line; + + struct smbw_file *file, *next_file; + struct smbw_server *srv, *next_srv; + + if (pipe(p)) return real_fork(); + + child = real_fork(); + + if (child) { + /* block the parent for a moment until the sockets are + closed */ + close(p[1]); + read(p[0], &c, 1); + close(p[0]); + return child; + } + + close(p[0]); + + /* close all files */ + for (file=smbw_files;file;file=next_file) { + next_file = file->next; + close(file->fd); + } + + /* close all server connections */ + for (srv=smbw_srvs;srv;srv=next_srv) { + next_srv = srv->next; + smbw_srv_close(srv); + } + + slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid()); + smbw_setshared(line,smbw_cwd); + + /* unblock the parent */ + write(p[1], &c, 1); + close(p[1]); + + /* and continue in the child */ + return 0; +} + +#ifndef NO_ACL_WRAPPER +/***************************************************** +say no to acls +*******************************************************/ + int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp) +{ + if (cmd == GETACL || cmd == GETACLCNT) return 0; + errno = ENOSYS; + return -1; +} +#endif + +#ifndef NO_FACL_WRAPPER +/***************************************************** +say no to acls +*******************************************************/ + int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp) +{ + if (cmd == GETACL || cmd == GETACLCNT) return 0; + errno = ENOSYS; + return -1; +} +#endif + +#ifdef HAVE_EXPLICIT_LARGEFILE_SUPPORT +#ifdef HAVE_STAT64 +/* this can't be in wrapped.c because of include conflicts */ + void stat64_convert(struct stat *st, struct stat64 *st64) +{ + st64->st_size = st->st_size; + st64->st_mode = st->st_mode; + st64->st_ino = st->st_ino; + st64->st_dev = st->st_dev; + st64->st_rdev = st->st_rdev; + st64->st_nlink = st->st_nlink; + st64->st_uid = st->st_uid; + st64->st_gid = st->st_gid; + st64->st_atime = st->st_atime; + st64->st_mtime = st->st_mtime; + st64->st_ctime = st->st_ctime; + st64->st_blksize = st->st_blksize; + st64->st_blocks = st->st_blocks; +} +#endif + +#ifdef HAVE_READDIR64 + void dirent64_convert(struct dirent *d, struct dirent64 *d64) +{ + d64->d_ino = d->d_ino; + d64->d_off = d->d_off; + d64->d_reclen = d->d_reclen; + pstrcpy(d64->d_name, d->d_name); +} +#endif +#endif + + +#ifdef HAVE___XSTAT +/* Definition of `struct stat' used in the linux kernel.. */ +struct kernel_stat { + unsigned short int st_dev; + unsigned short int __pad1; + unsigned long int st_ino; + unsigned short int st_mode; + unsigned short int st_nlink; + unsigned short int st_uid; + unsigned short int st_gid; + unsigned short int st_rdev; + unsigned short int __pad2; + unsigned long int st_size; + unsigned long int st_blksize; + unsigned long int st_blocks; + unsigned long int st_atime; + unsigned long int __unused1; + unsigned long int st_mtime; + unsigned long int __unused2; + unsigned long int st_ctime; + unsigned long int __unused3; + unsigned long int __unused4; + unsigned long int __unused5; +}; + +/* + * Prototype for gcc in 'fussy' mode. + */ + void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf); + void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf) +{ +#ifdef _STAT_VER_LINUX_OLD + if (vers == _STAT_VER_LINUX_OLD) { + memcpy(st, kbuf, sizeof(*st)); + return; + } +#endif + + ZERO_STRUCTP(st); + + st->st_dev = kbuf->st_dev; + st->st_ino = kbuf->st_ino; + st->st_mode = kbuf->st_mode; + st->st_nlink = kbuf->st_nlink; + st->st_uid = kbuf->st_uid; + st->st_gid = kbuf->st_gid; + st->st_rdev = kbuf->st_rdev; + st->st_size = kbuf->st_size; + st->st_blksize = kbuf->st_blksize; + st->st_blocks = kbuf->st_blocks; + st->st_atime = kbuf->st_atime; + st->st_mtime = kbuf->st_mtime; + st->st_ctime = kbuf->st_ctime; +} +#endif |