From 977d6015564932410ff69e291b8c6eddeece334d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 4 Oct 1998 03:28:43 +0000 Subject: - split smbw directory code into smbw_dir.c - fixed a bug in the handling of multiple connections to different servers (This used to be commit a9f9d8c3d8c18a5ab4c18c1348ee9c8d643880fa) --- source3/smbwrapper/smbw_dir.c | 611 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 611 insertions(+) create mode 100644 source3/smbwrapper/smbw_dir.c (limited to 'source3/smbwrapper/smbw_dir.c') diff --git a/source3/smbwrapper/smbw_dir.c b/source3/smbwrapper/smbw_dir.c new file mode 100644 index 0000000000..db10204b10 --- /dev/null +++ b/source3/smbwrapper/smbw_dir.c @@ -0,0 +1,611 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + SMB wrapper directory 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 "smbw.h" +#include "wrapper.h" + +extern pstring smb_cwd; + +static struct smbw_dir *smbw_dirs; + +extern struct bitmap *smbw_file_bmap; +extern int DEBUGLEVEL; + +extern int smbw_busy; + +/***************************************************** +map a fd to a smbw_dir structure +*******************************************************/ +struct smbw_dir *smbw_dir(int fd) +{ + struct smbw_dir *dir; + + for (dir=smbw_dirs;dir;dir=dir->next) { + if (dir->fd == fd) return dir; + } + return NULL; +} + +/***************************************************** +check if a DIR* is one of ours +*******************************************************/ +int smbw_dirp(DIR *dirp) +{ + struct smbw_dir *d = (struct smbw_dir *)dirp; + struct smbw_dir *dir; + + for (dir=smbw_dirs;dir;dir=dir->next) { + if (dir == d) return 1; + } + return 0; +} + +/***************************************************** +free a smbw_dir structure and all entries +*******************************************************/ +static void free_dir(struct smbw_dir *dir) +{ + if (dir->list) { + free(dir->list); + } + if (dir->path) free(dir->path); + ZERO_STRUCTP(dir); + free(dir); +} + + +static struct smbw_dir *cur_dir; + +/***************************************************** +add a entry to a directory listing +*******************************************************/ +static void smbw_dir_add(struct file_info *finfo) +{ + DEBUG(5,("%s\n", finfo->name)); + + if (cur_dir->malloced == cur_dir->count) { + cur_dir->list = (struct file_info *)Realloc(cur_dir->list, + sizeof(cur_dir->list[0])* + (cur_dir->count+100)); + if (!cur_dir->list) { + /* oops */ + return; + } + cur_dir->malloced += 100; + } + + cur_dir->list[cur_dir->count] = *finfo; + cur_dir->count++; +} + +/***************************************************** +add a entry to a directory listing +*******************************************************/ +static void smbw_share_add(const char *share, uint32 type, const char *comment) +{ + struct file_info finfo; + + ZERO_STRUCT(finfo); + + pstrcpy(finfo.name, share); + finfo.mode = aRONLY | aDIR; + + smbw_dir_add(&finfo); +} + + +/***************************************************** +open a directory on the server +*******************************************************/ +int smbw_dir_open(const char *fname) +{ + fstring server, share; + pstring path; + struct smbw_server *srv=NULL; + struct smbw_dir *dir=NULL; + pstring mask; + int fd; + char *s; + + DEBUG(4,("%s\n", __FUNCTION__)); + + if (!fname) { + errno = EINVAL; + return -1; + } + + smbw_init(); + + /* work out what server they are after */ + s = smbw_parse_path(fname, server, share, path); + + DEBUG(4,("dir_open share=%s\n", share)); + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + dir = (struct smbw_dir *)malloc(sizeof(*dir)); + if (!dir) { + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(dir); + + cur_dir = dir; + + slprintf(mask, sizeof(mask)-1, "%s\\*", path); + string_sub(mask,"\\\\","\\"); + + if (strcmp(share,"IPC$") == 0) { + DEBUG(4,("doing NetShareEnum\n")); + if (cli_RNetShareEnum(&srv->cli, smbw_share_add) <= 0) { + errno = smbw_errno(&srv->cli); + goto failed; + } + } else { + if (cli_list(&srv->cli, mask, aHIDDEN|aSYSTEM|aDIR, + smbw_dir_add) <= 0) { + errno = smbw_errno(&srv->cli); + goto failed; + } + } + + cur_dir = NULL; + + fd = bitmap_find(smbw_file_bmap, 0); + if (fd == -1) { + errno = EMFILE; + goto failed; + } + + DLIST_ADD(smbw_dirs, dir); + + bitmap_set(smbw_file_bmap, fd); + + dir->fd = fd + SMBW_FD_OFFSET; + dir->srv = srv; + dir->path = strdup(s); + + DEBUG(4,(" -> %d\n", dir->count)); + + return dir->fd; + + failed: + if (dir) { + free_dir(dir); + } + + return -1; +} + +/***************************************************** +a wrapper for fstat() on a directory +*******************************************************/ +int smbw_dir_fstat(int fd, struct stat *st) +{ + struct smbw_dir *dir; + + DEBUG(4,("%s\n", __FUNCTION__)); + + dir = smbw_dir(fd); + if (!dir) { + errno = EBADF; + return -1; + } + + ZERO_STRUCTP(st); + + smbw_setup_stat(st, "", dir->count*sizeof(struct dirent), aDIR); + + st->st_dev = dir->srv->dev; + + return 0; +} + +/***************************************************** +close a directory handle +*******************************************************/ +int smbw_dir_close(int fd) +{ + struct smbw_dir *dir; + + DEBUG(4,("%s\n", __FUNCTION__)); + + dir = smbw_dir(fd); + if (!dir) { + DEBUG(4,("%s(%d)\n", __FUNCTION__, __LINE__)); + errno = EBADF; + return -1; + } + + bitmap_clear(smbw_file_bmap, dir->fd - SMBW_FD_OFFSET); + + DLIST_REMOVE(smbw_dirs, dir); + + free_dir(dir); + + return 0; +} + + +/***************************************************** +a wrapper for getdents() +*******************************************************/ +int smbw_getdents(unsigned int fd, struct dirent *dirp, int count) +{ + struct smbw_dir *dir; + int n=0; + + DEBUG(4,("%s\n", __FUNCTION__)); + + smbw_busy++; + + dir = smbw_dir(fd); + if (!dir) { + errno = EBADF; + smbw_busy--; + return -1; + } + + while (count>=sizeof(*dirp) && (dir->offset < dir->count)) { + dirp->d_off = (dir->offset+1)*sizeof(*dirp); + dirp->d_reclen = sizeof(*dirp); + safe_strcpy(&dirp->d_name[0], dir->list[dir->offset].name, + sizeof(dirp->d_name)-1); + dirp->d_ino = smbw_inode(dir->list[dir->offset].name); + dir->offset++; + count -= dirp->d_reclen; + if (dir->offset == dir->count) { + dirp->d_off = -1; + } + dirp++; + n++; + } + + smbw_busy--; + return n*sizeof(*dirp); +} + + +/***************************************************** +a wrapper for chdir() +*******************************************************/ +int smbw_chdir(const char *name) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + uint32 mode = aDIR; + char *cwd; + + smbw_init(); + + if (smbw_busy) return real_chdir(cwd); + + smbw_busy++; + + if (!name) { + errno = EINVAL; + goto failed; + } + + DEBUG(4,("%s (%s)\n", __FUNCTION__, name)); + + /* work out what server they are after */ + cwd = smbw_parse_path(name, server, share, path); + + if (strncmp(cwd,SMBW_PREFIX,strlen(SMBW_PREFIX))) { + if (real_chdir(cwd) == 0) { + DEBUG(4,("set SMBW_CWD to %s\n", cwd)); + pstrcpy(smb_cwd, cwd); + if (setenv(SMBW_PWD_ENV, smb_cwd, 1)) { + DEBUG(4,("setenv failed\n")); + } + goto success; + } + errno = ENOENT; + goto failed; + } + + /* get a connection to the server */ + srv = smbw_server(server, share); + if (!srv) { + /* smbw_server sets errno */ + goto failed; + } + + if (strcmp(share,"IPC$") && + !smbw_getatr(srv, path, + &mode, NULL, NULL, NULL, NULL)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + if (!(mode & aDIR)) { + errno = ENOTDIR; + goto failed; + } + + DEBUG(4,("set SMBW_CWD2 to %s\n", cwd)); + pstrcpy(smb_cwd, cwd); + if (setenv(SMBW_PWD_ENV, smb_cwd, 1)) { + DEBUG(4,("setenv failed\n")); + } + + /* we don't want the old directory to be busy */ + real_chdir("/"); + + success: + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for lseek() on directories +*******************************************************/ +off_t smbw_dir_lseek(int fd, off_t offset, int whence) +{ + struct smbw_dir *dir; + off_t ret; + + DEBUG(4,("%s offset=%d whence=%d\n", __FUNCTION__, + (int)offset, whence)); + + dir = smbw_dir(fd); + if (!dir) { + errno = EBADF; + return -1; + } + + switch (whence) { + case SEEK_SET: + dir->offset = offset/sizeof(struct dirent); + break; + case SEEK_CUR: + dir->offset += offset/sizeof(struct dirent); + break; + case SEEK_END: + dir->offset = (dir->count * sizeof(struct dirent)) + offset; + dir->offset /= sizeof(struct dirent); + break; + } + + ret = dir->offset * sizeof(struct dirent); + + DEBUG(4,(" -> %d\n", (int)ret)); + + return ret; +} + + +/***************************************************** +a wrapper for mkdir() +*******************************************************/ +int smbw_mkdir(const char *fname, mode_t mode) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + + DEBUG(4,("%s (%s)\n", __FUNCTION__, fname)); + + 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_mkdir(&srv->cli, path)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + +/***************************************************** +a wrapper for rmdir() +*******************************************************/ +int smbw_rmdir(const char *fname) +{ + struct smbw_server *srv; + fstring server, share; + pstring path; + + DEBUG(4,("%s (%s)\n", __FUNCTION__, fname)); + + 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_rmdir(&srv->cli, path)) { + errno = smbw_errno(&srv->cli); + goto failed; + } + + smbw_busy--; + return 0; + + failed: + smbw_busy--; + return -1; +} + + +/***************************************************** +a wrapper for getcwd() +*******************************************************/ +char *smbw_getcwd(char *buf, size_t size) +{ + smbw_init(); + + if (smbw_busy) { + return __getcwd(buf, size); + } + + smbw_busy++; + + if (!buf) { + if (size <= 0) size = strlen(smb_cwd)+1; + buf = (char *)malloc(size); + if (!buf) { + errno = ENOMEM; + smbw_busy--; + return NULL; + } + } + + if (strlen(smb_cwd) > size-1) { + errno = ERANGE; + smbw_busy--; + return NULL; + } + + safe_strcpy(buf, smb_cwd, size); + + smbw_busy--; + return buf; +} + +/***************************************************** +a wrapper for fchdir() +*******************************************************/ +int smbw_fchdir(unsigned int fd) +{ + struct smbw_dir *dir; + + DEBUG(4,("%s\n", __FUNCTION__)); + + smbw_busy++; + + dir = smbw_dir(fd); + if (!dir) { + errno = EBADF; + smbw_busy--; + return -1; + } + + smbw_busy--; + + return chdir(dir->path); +} + +/***************************************************** +open a directory on the server +*******************************************************/ +DIR *smbw_opendir(const char *fname) +{ + int fd; + + smbw_busy++; + + fd = smbw_dir_open(fname); + + if (fd == -1) { + smbw_busy--; + return NULL; + } + + smbw_busy--; + + return (DIR *)smbw_dir(fd); +} + +/***************************************************** +read one entry from a directory +*******************************************************/ +struct dirent *smbw_readdir(struct smbw_dir *d) +{ + static struct dirent de; + + if (smbw_getdents(d->fd, &de, sizeof(struct dirent)) > 0) + return &de; + + return NULL; +} + +/***************************************************** +close a DIR* +*******************************************************/ +int smbw_closedir(struct smbw_dir *d) +{ + return smbw_close(d->fd); +} + +/***************************************************** +seek in a directory +*******************************************************/ +void smbw_seekdir(struct smbw_dir *d, off_t offset) +{ + smbw_dir_lseek(d->fd,offset, SEEK_SET); +} + +/***************************************************** +current loc in a directory +*******************************************************/ +off_t smbw_telldir(struct smbw_dir *d) +{ + return smbw_dir_lseek(d->fd,0,SEEK_CUR); +} -- cgit