mirror of
https://github.com/samba-team/samba.git
synced 2025-01-14 19:24:43 +03:00
58e9534300
(This used to be commit d0e89d246d8e5e64196d6c1d16d39a70579ca42f)
356 lines
9.7 KiB
C
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);
|
|
}
|