1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-14 19:24:43 +03:00
Andrew Tridgell 58e9534300 r23785: use the GPLv3 boilerplate as recommended by the FSF and the license text
(This used to be commit d0e89d246d8e5e64196d6c1d16d39a70579ca42f)
2007-10-10 12:28:23 -05:00

356 lines
9.7 KiB
C

/*
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#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);
}