Viewing file: smbw_dir.c (9.76 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* 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" #include "bsd-strlfunc.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;
smbw_strlcpy(dirent_external->d_name, dirent_internal->name, sizeof(dirent_external->d_name) - 1); smbw_strlcpy(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; } }
smbw_strlcpy(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; } }
smbw_strlcpy(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; smbw_strlcpy(dirent_external.d_name, dirent_internal->name, sizeof(dirent_external.d_name) - 1); smbw_strlcpy(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); }
|