1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-25 06:04:04 +03:00
Jeremy Allison 768761820e Added the same open()/fopen()/creat()/mmap() -> sys_XXX calls.
Tidied up some of the mess (no other word for it). Still doesn't
compile cleanly. There are calls with incorrect parameters that
don't seem to be doing the right thing.

This code still needs surgery :-(.

Jeremy.
(This used to be commit 18ff93a9abbf68ee8c59c0af3e57c63e4a015dac)
1998-11-17 20:50:07 +00:00

1510 lines
29 KiB
C

/*
Unix SMB/Netbios implementation.
Version 2.0
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;
extern int DEBUGLEVEL;
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;
static pstring servicesf = CONFIGFILE;
extern FILE *dbf;
char *p;
int eno;
pstring line;
if (initialised) return;
initialised = 1;
eno = errno;
smbw_busy++;
DEBUGLEVEL = 0;
setup_logging("smbsh",True);
dbf = 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);
}
charset_initialise();
in_client = True;
load_interfaces();
lp_load(servicesf,True,False,False);
get_myname(global_myname,NULL);
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);
string_sub(smbw_prefix,"//", "/");
DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix));
}
slprintf(line,sizeof(line)-1,"PWD_%d", 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;
}
}
}
/*****************************************************
parse a smb path into its components.
*******************************************************/
char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
{
static pstring s;
char *p, *p2;
int len = strlen(smbw_prefix)-1;
*server = *share = *path = 0;
if (fname[0] == '/') {
pstrcpy(s, fname);
} else {
slprintf(s,sizeof(s)-1, "%s/%s", smbw_cwd, fname);
}
clean_fname(s);
DEBUG(5,("cleaned %s (fname=%s cwd=%s)\n",
s, fname, smbw_cwd));
if (strncmp(s,smbw_prefix,len) ||
(s[len] != '/' && s[len] != 0)) return s;
p = s + len;
if (*p == '/') p++;
p2 = strchr(p,'/');
if (p2) {
len = (int)(p2-p);
} else {
len = strlen(p);
}
len = MIN(len,sizeof(fstring)-1);
strncpy(server, p, len);
server[len] = 0;
p = p2;
if (!p) {
if (len == 0) {
char *workgroup = smbw_getshared("WORKGROUP");
if (!workgroup) workgroup = lp_workgroup();
slprintf(server,sizeof(fstring)-1, "%s#1D", workgroup);
}
fstrcpy(share,"IPC$");
pstrcpy(path,"");
goto ok;
}
p++;
p2 = strchr(p,'/');
if (p2) {
len = (int)(p2-p);
} else {
len = strlen(p);
}
len = MIN(len,sizeof(fstring)-1);
strncpy(share, p, len);
share[len] = 0;
p = p2;
if (!p) {
pstrcpy(path,"\\");
goto ok;
}
pstrcpy(path,p);
string_sub(path, "/", "\\");
ok:
DEBUG(4,("parsed path name=%s cwd=%s [%s] [%s] [%s]\n",
fname, smbw_cwd,
server, share, path));
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;
/* 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)
{
uint8 eclass;
uint32 ecode;
int ret;
ret = cli_error(c, &eclass, &ecode);
if (ret) {
DEBUG(3,("smbw_error %d %d (0x%x) -> %d\n",
(int)eclass, (int)ecode, (int)ecode, ret));
}
return ret;
}
/*****************************************************
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;
extern struct in_addr ipzero;
ip = ipzero;
ZERO_STRUCT(c);
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 = "";
/* 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) 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(server_n,'#')) && strcmp(p+1,"1D")==0) {
struct in_addr sip;
pstring s;
fstrcpy(group, server_n);
p = strchr(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);
ip = ipzero;
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;
}
/* 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;
if (srv->server_name) free(srv->server_name);
if (srv->share_name) free(srv->share_name);
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) {
if (file->f->fname) {
free(file->f->fname);
}
free(file->f);
}
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) {
free(file->f->fname);
free(file->f);
}
ZERO_STRUCTP(file);
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);
free(srv->server_name);
free(srv->share_name);
DLIST_REMOVE(smbw_srvs, srv);
ZERO_STRUCTP(srv);
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", 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_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
#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