1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00

Restructuring of the code to remove dos_ChDir/dos_GetWd and re-vector them

through the VFS. All file access/directory access code in smbd should now
go via the vfs. Added vfs_chown/vfs_chmod calls. Still looking at vfs_get_nt_acl()
vfs_set_nt_acl() call API design.
Jeremy.
(This used to be commit f96625ec12)
This commit is contained in:
Jeremy Allison 2000-09-27 19:09:59 +00:00
parent 8c93ddf3e0
commit b43b2e4f8a
14 changed files with 485 additions and 346 deletions

View File

@ -90,8 +90,6 @@ BOOL dos_file_exist(char *fname,SMB_STRUCT_STAT *sbuf);
BOOL dos_directory_exist(char *dname,SMB_STRUCT_STAT *st);
time_t dos_file_modtime(char *fname);
SMB_OFF_T dos_file_size(char *file_name);
int dos_ChDir(char *path);
char *dos_GetWd(char *path);
/*The following definitions come from lib/error.c */
@ -339,7 +337,6 @@ void smb_setlen(char *buf,int len);
int set_message(char *buf,int num_words,int num_bytes,BOOL zero);
void dos_clean_name(char *s);
void unix_clean_name(char *s);
BOOL reduce_name(char *s,char *dir,BOOL widelinks);
void make_dir_struct(char *buf,char *mask,char *fname,SMB_OFF_T size,int mode,time_t date);
void close_low_fds(void);
int set_blocking(int fd, BOOL set);
@ -3854,23 +3851,35 @@ int vfswrap_lstat(char *path,
SMB_STRUCT_STAT *sbuf);
int vfswrap_unlink(char *path);
int vfswrap_chmod(char *path, mode_t mode);
int vfswrap_chown(char *path, uid_t uid, gid_t gid);
int vfswrap_chdir(char *path);
char *vfswrap_getwd(char *path);
int vfswrap_utime(char *path, struct utimbuf *times);
int vfswrap_ftruncate(int fd, SMB_OFF_T offset);
BOOL vfswrap_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
size_t vfswrap_get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc);
BOOL vfswrap_set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd);
/*The following definitions come from smbd/vfs.c */
int vfs_init_default(connection_struct *conn);
BOOL vfs_init_custom(connection_struct *conn);
BOOL vfs_directory_exist(connection_struct *conn, char *dname,
SMB_STRUCT_STAT *st);
int vfs_stat(connection_struct *conn, char *fname, SMB_STRUCT_STAT *st);
BOOL vfs_directory_exist(connection_struct *conn, char *dname, SMB_STRUCT_STAT *st);
int vfs_unlink(connection_struct *conn, char *fname);
int vfs_chmod(connection_struct *conn, char *fname,mode_t mode);
int vfs_chown(connection_struct *conn, char *fname, uid_t uid, gid_t gid);
int vfs_chdir(connection_struct *conn, char *fname);
char *vfs_getwd(connection_struct *conn, char *unix_path);
BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf);
ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N);
SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp,
int out_fd, files_struct *out_fsp,
SMB_OFF_T n, char *header, int headlen, int align);
char *vfs_readdirname(connection_struct *conn, void *p);
int vfs_ChDir(connection_struct *conn, char *path);
char *vfs_GetWd(connection_struct *conn, char *path);
BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks);
/*The following definitions come from smbwrapper/realcalls.c */

View File

@ -184,9 +184,16 @@ struct vfs_ops {
int (*lstat)(char *path, SMB_STRUCT_STAT *sbuf);
int (*unlink)(char *path);
int (*chmod)(char *path, mode_t mode);
int (*chown)(char *path, uid_t uid, gid_t gid);
int (*chdir)(char *path);
char *(*getwd)(char *buf);
int (*utime)(char *path, struct utimbuf *times);
int (*ftruncate)(int fd, SMB_OFF_T offset);
BOOL (*lock)(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
#if 0
size_t (*get_nt_acl)(files_struct *fsp, SEC_DESC **ppdesc);
BOOL (*set_nt_acl)(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd);
#endif
};
struct vfs_options {

View File

@ -33,6 +33,7 @@
extern int DEBUGLEVEL;
#if 0 /* Use vfs_unlink. */
/*******************************************************************
Unlink wrapper that calls dos_to_unix.
********************************************************************/
@ -41,6 +42,7 @@ int dos_unlink(char *fname)
{
return(unlink(dos_to_unix(fname,False)));
}
#endif
/*******************************************************************
Open() wrapper that calls dos_to_unix.
@ -85,10 +87,12 @@ char *dos_readdirname(DIR *p)
A chown() wrapper that calls dos_to_unix.
********************************************************************/
#if 0 /* Use vfs_chown. */
int dos_chown(char *fname, uid_t uid, gid_t gid)
{
return(sys_chown(dos_to_unix(fname,False),uid,gid));
}
#endif
/*******************************************************************
A stat() wrapper that calls dos_to_unix.
@ -134,6 +138,7 @@ int dos_rmdir(char *dname)
return(rmdir(dos_to_unix(dname,False)));
}
#if 0 /* VFS */
/*******************************************************************
chdir() - call dos_to_unix.
********************************************************************/
@ -142,6 +147,7 @@ int dos_chdir(char *dname)
{
return(chdir(dos_to_unix(dname,False)));
}
#endif
/*******************************************************************
Utime() - call dos_to_unix.
@ -282,6 +288,7 @@ int dos_chmod(char *fname,mode_t mode)
return(chmod(dos_to_unix(fname,False),mode));
}
#if 0 /* VFS */
/*******************************************************************
Getwd - takes a UNIX directory name and returns the name
in dos format.
@ -295,6 +302,7 @@ char *dos_getwd(char *unix_path)
unix_to_dos(wd, True);
return wd;
}
#endif /* VFS */
/*******************************************************************
Check if a DOS file exists. Use vfs_file_exist function instead.
@ -333,164 +341,3 @@ SMB_OFF_T dos_file_size(char *file_name)
{
return get_file_size(dos_to_unix(file_name, False));
}
/*******************************************************************
A wrapper for dos_chdir().
********************************************************************/
int dos_ChDir(char *path)
{
int res;
static pstring LastDir="";
if (strcsequal(path,"."))
return(0);
if (*path == '/' && strcsequal(LastDir,path))
return(0);
DEBUG(3,("dos_ChDir to %s\n",path));
res = dos_chdir(path);
if (!res)
pstrcpy(LastDir,path);
return(res);
}
/* number of list structures for a caching GetWd function. */
#define MAX_GETWDCACHE (50)
struct
{
SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
char *dos_path; /* The pathname in DOS format. */
BOOL valid;
} ino_list[MAX_GETWDCACHE];
BOOL use_getwd_cache=True;
/****************************************************************************
Prompte a ptr (to make it recently used)
****************************************************************************/
static void array_promote(char *array,int elsize,int element)
{
char *p;
if (element == 0)
return;
p = (char *)malloc(elsize);
if (!p)
{
DEBUG(5,("Ahh! Can't malloc\n"));
return;
}
memcpy(p,array + element * elsize, elsize);
memmove(array + elsize,array,elsize*element);
memcpy(array,p,elsize);
free(p);
}
/*******************************************************************
Return the absolute current directory path - given a UNIX pathname.
Note that this path is returned in DOS format, not UNIX
format.
********************************************************************/
char *dos_GetWd(char *path)
{
pstring s;
static BOOL getwd_cache_init = False;
SMB_STRUCT_STAT st, st2;
int i;
*s = 0;
if (!use_getwd_cache)
return(dos_getwd(path));
/* init the cache */
if (!getwd_cache_init)
{
getwd_cache_init = True;
for (i=0;i<MAX_GETWDCACHE;i++)
{
string_set(&ino_list[i].dos_path,"");
ino_list[i].valid = False;
}
}
/* Get the inode of the current directory, if this doesn't work we're
in trouble :-) */
if (sys_stat(".",&st) == -1)
{
DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
return(dos_getwd(path));
}
for (i=0; i<MAX_GETWDCACHE; i++)
if (ino_list[i].valid)
{
/* If we have found an entry with a matching inode and dev number
then find the inode number for the directory in the cached string.
If this agrees with that returned by the stat for the current
directory then all is o.k. (but make sure it is a directory all
the same...) */
if (st.st_ino == ino_list[i].inode &&
st.st_dev == ino_list[i].dev)
{
if (dos_stat(ino_list[i].dos_path,&st2) == 0)
{
if (st.st_ino == st2.st_ino &&
st.st_dev == st2.st_dev &&
(st2.st_mode & S_IFMT) == S_IFDIR)
{
pstrcpy (path, ino_list[i].dos_path);
/* promote it for future use */
array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
return (path);
}
else
{
/* If the inode is different then something's changed,
scrub the entry and start from scratch. */
ino_list[i].valid = False;
}
}
}
}
/* We don't have the information to hand so rely on traditional methods.
The very slow getcwd, which spawns a process on some systems, or the
not quite so bad getwd. */
if (!dos_getwd(s))
{
DEBUG(0,("dos_GetWd: dos_getwd call failed, errno %s\n",strerror(errno)));
return (NULL);
}
pstrcpy(path,s);
DEBUG(5,("dos_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
/* add it to the cache */
i = MAX_GETWDCACHE - 1;
string_set(&ino_list[i].dos_path,s);
ino_list[i].dev = st.st_dev;
ino_list[i].inode = st.st_ino;
ino_list[i].valid = True;
/* put it at the top of the list */
array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
return (path);
}

View File

@ -410,137 +410,6 @@ void unix_clean_name(char *s)
trim_string(s,NULL,"/..");
}
/*******************************************************************
reduce a file name, removing .. elements and checking that
it is below dir in the heirachy. This uses dos_GetWd() and so must be run
on the system that has the referenced file system.
widelinks are allowed if widelinks is true
********************************************************************/
BOOL reduce_name(char *s,char *dir,BOOL widelinks)
{
#ifndef REDUCE_PATHS
return True;
#else
pstring dir2;
pstring wd;
pstring base_name;
pstring newname;
char *p=NULL;
BOOL relative = (*s != '/');
*dir2 = *wd = *base_name = *newname = 0;
if (widelinks)
{
unix_clean_name(s);
/* can't have a leading .. */
if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
{
DEBUG(3,("Illegal file name? (%s)\n",s));
return(False);
}
if (strlen(s) == 0)
pstrcpy(s,"./");
return(True);
}
DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
/* remove any double slashes */
all_string_sub(s,"//","/",0);
pstrcpy(base_name,s);
p = strrchr(base_name,'/');
if (!p)
return(True);
if (!dos_GetWd(wd))
{
DEBUG(0,("couldn't getwd for %s %s\n",s,dir));
return(False);
}
if (dos_ChDir(dir) != 0)
{
DEBUG(0,("couldn't chdir to %s\n",dir));
return(False);
}
if (!dos_GetWd(dir2))
{
DEBUG(0,("couldn't getwd for %s\n",dir));
dos_ChDir(wd);
return(False);
}
if (p && (p != base_name))
{
*p = 0;
if (strcmp(p+1,".")==0)
p[1]=0;
if (strcmp(p+1,"..")==0)
*p = '/';
}
if (dos_ChDir(base_name) != 0)
{
dos_ChDir(wd);
DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,base_name));
return(False);
}
if (!dos_GetWd(newname))
{
dos_ChDir(wd);
DEBUG(2,("couldn't get wd for %s %s\n",s,dir2));
return(False);
}
if (p && (p != base_name))
{
pstrcat(newname,"/");
pstrcat(newname,p+1);
}
{
size_t l = strlen(dir2);
if (dir2[l-1] == '/')
l--;
if (strncmp(newname,dir2,l) != 0)
{
dos_ChDir(wd);
DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
return(False);
}
if (relative)
{
if (newname[l] == '/')
pstrcpy(s,newname + l + 1);
else
pstrcpy(s,newname+l);
}
else
pstrcpy(s,newname);
}
dos_ChDir(wd);
if (strlen(s) == 0)
pstrcpy(s,"./");
DEBUG(3,("reduced to %s\n",s));
return(True);
#endif
}
/****************************************************************************
make a dir struct
****************************************************************************/

View File

@ -92,7 +92,7 @@ pstring global_scope = "";
#define VALID(i) iSERVICE(i).valid
int keepalive = DEFAULT_KEEPALIVE;
extern BOOL use_getwd_cache;
BOOL use_getwd_cache;
extern int extra_time_offset;

View File

@ -61,7 +61,7 @@ mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname)
dname = parent_dirname(fname);
DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname));
if (dos_stat(dname,&sbuf) != 0) {
if (vfs_stat(conn,dname,&sbuf) != 0) {
DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno)));
return(0); /* *** shouldn't happen! *** */
}
@ -191,7 +191,7 @@ int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *
if (!st) {
st = &st1;
if (conn->vfs_ops.stat(dos_to_unix(fname,False),st)) return(-1);
if (vfs_stat(conn,fname,st)) return(-1);
}
if (S_ISDIR(st->st_mode)) dosmode |= aDIR;
@ -227,7 +227,7 @@ int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *
unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
}
return(conn->vfs_ops.chmod(dos_to_unix(fname,False),unixmode));
return(vfs_chmod(conn,fname,unixmode));
}
@ -258,7 +258,7 @@ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
(as DOS does).
*/
if(conn->vfs_ops.stat(dos_to_unix(fname,False),&sb) != 0)
if(vfs_stat(conn,fname,&sb) != 0)
return -1;
/* Check if we have write access. */

View File

@ -419,7 +419,7 @@ BOOL check_name(char *name,connection_struct *conn)
return(0);
}
ret = reduce_name(name,conn->connectpath,lp_widelinks(SNUM(conn)));
ret = reduce_name(conn,name,conn->connectpath,lp_widelinks(SNUM(conn)));
/* Check if we are allowing users to follow symlinks */
/* Patch from David Clerc <David.Clerc@cui.unige.ch>

View File

@ -51,7 +51,7 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
ZERO_STRUCTP(data);
if(dos_stat(path, &st) == -1) return False;
if(vfs_stat(conn,path, &st) == -1) return False;
data->modify_time = st.st_mtime;
data->status_time = st.st_ctime;
@ -102,7 +102,7 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
/*
* Do the stat - but ignore errors.
*/
dos_stat(full_name, &st);
vfs_stat(conn,full_name, &st);
data->total_time += (st.st_mtime + st.st_ctime);
}

View File

@ -732,7 +732,7 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
*/
saved_conn = fsp->conn;
saved_vuid = current_user.vuid;
dos_GetWd(saved_dir);
vfs_GetWd(saved_conn,saved_dir);
unbecome_user();
/* Save the chain fnum. */
file_chain_save();
@ -814,7 +814,7 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
exit_server("unable to re-become user");
}
/* Including the directory. */
dos_ChDir(saved_dir);
vfs_ChDir(saved_conn,saved_dir);
/* Restore the chain fnum. */
file_chain_restore();

View File

@ -1100,7 +1100,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
unix_convert(fname,conn,0,&bad_path,&sbuf);
if (check_name(fname,conn))
{
if (VALID_STAT(sbuf) || dos_stat(fname,&sbuf) == 0)
if (VALID_STAT(sbuf) || vfs_stat(conn,fname,&sbuf) == 0)
{
mode = dos_mode(conn,fname,&sbuf);
size = sbuf.st_size;

View File

@ -56,8 +56,8 @@ BOOL become_service(connection_struct *conn,BOOL do_chdir)
snum = SNUM(conn);
if (do_chdir &&
dos_ChDir(conn->connectpath) != 0 &&
dos_ChDir(conn->origpath) != 0) {
vfs_ChDir(conn,conn->connectpath) != 0 &&
vfs_ChDir(conn,conn->origpath) != 0) {
DEBUG(0,("chdir (%s) failed\n",
conn->connectpath));
return(False);
@ -575,7 +575,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
return NULL;
}
if (dos_ChDir(conn->connectpath) != 0) {
if (vfs_ChDir(conn,conn->connectpath) != 0) {
DEBUG(0,("Can't change directory to %s (%s)\n",
conn->connectpath,strerror(errno)));
unbecome_user();
@ -598,9 +598,9 @@ connection_struct *make_connection(char *service,char *user,char *password, int
{
pstring s;
pstrcpy(s,conn->connectpath);
dos_GetWd(s);
vfs_GetWd(conn,s);
string_set(&conn->connectpath,s);
dos_ChDir(conn->connectpath);
vfs_ChDir(conn,conn->connectpath);
}
#endif

View File

@ -146,8 +146,6 @@ static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *p
DOM_SID grp_sid;
DOM_SID file_owner_sid;
DOM_SID file_grp_sid;
uint32 owner_rid;
uint32 grp_rid;
SEC_ACL *dacl = psd->dacl;
BOOL all_aces_are_inherit_only = (is_directory ? True : False);
int i;
@ -353,7 +351,7 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
} else {
if(fsp->is_directory || fsp->fd == -1) {
if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
return 0;
}
} else {
@ -458,14 +456,14 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
*/
if(fsp->is_directory) {
if(dos_stat(fsp->fsp_name, &sbuf) != 0)
if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0)
return False;
} else {
int ret;
if(fsp->fd == -1)
ret = conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name,False), &sbuf);
ret = vfs_stat(fsp->conn,fsp->fsp_name,&sbuf);
else
ret = conn->vfs_ops.fstat(fsp->fd,&sbuf);
@ -492,7 +490,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
DEBUG(3,("call_nt_transact_set_security_desc: chown %s. uid = %u, gid = %u.\n",
fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
if(dos_chown( fsp->fsp_name, user, grp) == -1) {
if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
DEBUG(3,("call_nt_transact_set_security_desc: chown %s, %u, %u failed. Error = %s.\n",
fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
return False;
@ -504,7 +502,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
*/
if(fsp->is_directory) {
if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
return False;
}
} else {
@ -512,7 +510,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
int ret;
if(fsp->fd == -1)
ret = conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name,False), &sbuf);
ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf);
else
ret = conn->vfs_ops.fstat(fsp->fd,&sbuf);

View File

@ -284,6 +284,42 @@ int vfswrap_chmod(char *path, mode_t mode)
return result;
}
int vfswrap_chown(char *path, uid_t uid, gid_t gid)
{
int result;
#ifdef VFS_CHECK_NULL
if (path == NULL) {
smb_panic("NULL pointer passed to vfswrap_chown()\n");
}
#endif
result = sys_chown(path, uid, gid);
return result;
}
int vfswrap_chdir(char *path)
{
#ifdef VFS_CHECK_NULL
if (path == NULL) {
smb_panic("NULL pointer passed to vfswrap_chdir()\n");
}
#endif
return chdir(path);
}
char *vfswrap_getwd(char *path)
{
#ifdef VFS_CHECK_NULL
if (path == NULL) {
smb_panic("NULL pointer passed to vfswrap_getwd()\n");
}
#endif
return sys_getwd(path);
}
int vfswrap_utime(char *path, struct utimbuf *times)
{
int result;
@ -310,3 +346,13 @@ BOOL vfswrap_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
{
return fcntl_lock(fd, op, offset, count,type);
}
#if 0
size_t vfswrap_get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
{
}
BOOL vfswrap_set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
{
}
#endif

View File

@ -64,9 +64,16 @@ struct vfs_ops default_vfs_ops = {
vfswrap_lstat,
vfswrap_unlink,
vfswrap_chmod,
vfswrap_chown,
vfswrap_chdir,
vfswrap_getwd,
vfswrap_utime,
vfswrap_ftruncate,
vfswrap_lock
vfswrap_lock,
#if 0
vfswrap_get_nt_acl,
vfswrap_set_nt_acl
#endif
};
/****************************************************************************
@ -208,6 +215,10 @@ BOOL vfs_init_custom(connection_struct *conn)
conn->vfs_ops.chmod = default_vfs_ops.chmod;
}
if (conn->vfs_ops.chown == NULL) {
conn->vfs_ops.chown = default_vfs_ops.chown;
}
if (conn->vfs_ops.utime == NULL) {
conn->vfs_ops.utime = default_vfs_ops.utime;
}
@ -224,20 +235,33 @@ BOOL vfs_init_custom(connection_struct *conn)
}
#endif
BOOL vfs_directory_exist(connection_struct *conn, char *dname,
SMB_STRUCT_STAT *st)
/*******************************************************************
vfs stat wrapper that calls dos_to_unix.
********************************************************************/
int vfs_stat(connection_struct *conn, char *fname, SMB_STRUCT_STAT *st)
{
SMB_STRUCT_STAT st2;
BOOL ret;
return(conn->vfs_ops.stat(dos_to_unix(fname,False),st));
}
if (!st) st = &st2;
/*******************************************************************
Check if directory exists.
********************************************************************/
if (conn->vfs_ops.stat(dos_to_unix(dname,False),st) != 0)
return(False);
BOOL vfs_directory_exist(connection_struct *conn, char *dname, SMB_STRUCT_STAT *st)
{
SMB_STRUCT_STAT st2;
BOOL ret;
ret = S_ISDIR(st->st_mode);
if(!ret)
errno = ENOTDIR;
if (!st)
st = &st2;
if (vfs_stat(conn,dname,st) != 0)
return(False);
ret = S_ISDIR(st->st_mode);
if(!ret)
errno = ENOTDIR;
return ret;
}
@ -248,26 +272,70 @@ BOOL vfs_directory_exist(connection_struct *conn, char *dname,
int vfs_unlink(connection_struct *conn, char *fname)
{
return(conn->vfs_ops.unlink(dos_to_unix(fname,False)));
return(conn->vfs_ops.unlink(dos_to_unix(fname,False)));
}
/*******************************************************************
check if a vfs file exists
vfs chmod wrapper that calls dos_to_unix.
********************************************************************/
int vfs_chmod(connection_struct *conn, char *fname,mode_t mode)
{
return(conn->vfs_ops.chmod(dos_to_unix(fname,False), mode));
}
/*******************************************************************
vfs chown wrapper that calls dos_to_unix.
********************************************************************/
int vfs_chown(connection_struct *conn, char *fname, uid_t uid, gid_t gid)
{
return(conn->vfs_ops.chown(dos_to_unix(fname,False), uid, gid));
}
/*******************************************************************
A wrapper for vfs_chdir().
********************************************************************/
int vfs_chdir(connection_struct *conn, char *fname)
{
return(conn->vfs_ops.chdir(dos_to_unix(fname,False)));
}
/*******************************************************************
vfs getwd wrapper that calls dos_to_unix.
********************************************************************/
char *vfs_getwd(connection_struct *conn, char *unix_path)
{
char *wd;
wd = conn->vfs_ops.getwd(unix_path);
if (wd)
unix_to_dos(wd, True);
return wd;
}
/*******************************************************************
Check if a vfs file exists.
********************************************************************/
BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf)
{
SMB_STRUCT_STAT st;
if (!sbuf) sbuf = &st;
if (conn->vfs_ops.stat(dos_to_unix(fname,False),sbuf) != 0)
return(False);
SMB_STRUCT_STAT st;
return(S_ISREG(sbuf->st_mode));
if (!sbuf)
sbuf = &st;
if (vfs_stat(conn,fname,sbuf) != 0)
return(False);
return(S_ISREG(sbuf->st_mode));
}
/****************************************************************************
write data to a fd on the vfs
Write data to a fd on the vfs.
****************************************************************************/
ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N)
{
size_t total=0;
@ -286,8 +354,9 @@ ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N)
}
/****************************************************************************
transfer some data between two file_struct's
Transfer some data between two file_struct's.
****************************************************************************/
SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp,
int out_fd, files_struct *out_fsp,
SMB_OFF_T n, char *header, int headlen, int align)
@ -376,22 +445,26 @@ SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp,
}
/*******************************************************************
a vfs_readdir wrapper which just returns the file name
A vfs_readdir wrapper which just returns the file name.
********************************************************************/
char *vfs_readdirname(connection_struct *conn, void *p)
{
struct dirent *ptr;
char *dname;
if (!p) return(NULL);
if (!p)
return(NULL);
ptr = (struct dirent *)conn->vfs_ops.readdir(p);
if (!ptr) return(NULL);
if (!ptr)
return(NULL);
dname = ptr->d_name;
#ifdef NEXT2
if (telldir(p) < 0) return(NULL);
if (telldir(p) < 0)
return(NULL);
#endif
#ifdef HAVE_BROKEN_READDIR
@ -474,3 +547,293 @@ static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
#endif
/*******************************************************************
A wrapper for vfs_chdir().
********************************************************************/
int vfs_ChDir(connection_struct *conn, char *path)
{
int res;
static pstring LastDir="";
if (strcsequal(path,"."))
return(0);
if (*path == '/' && strcsequal(LastDir,path))
return(0);
DEBUG(3,("vfs_ChDir to %s\n",path));
res = vfs_chdir(conn,path);
if (!res)
pstrcpy(LastDir,path);
return(res);
}
/* number of list structures for a caching GetWd function. */
#define MAX_GETWDCACHE (50)
struct
{
SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
char *dos_path; /* The pathname in DOS format. */
BOOL valid;
} ino_list[MAX_GETWDCACHE];
extern BOOL use_getwd_cache;
/****************************************************************************
Prompte a ptr (to make it recently used)
****************************************************************************/
static void array_promote(char *array,int elsize,int element)
{
char *p;
if (element == 0)
return;
p = (char *)malloc(elsize);
if (!p) {
DEBUG(5,("array_promote: malloc fail\n"));
return;
}
memcpy(p,array + element * elsize, elsize);
memmove(array + elsize,array,elsize*element);
memcpy(array,p,elsize);
free(p);
}
/*******************************************************************
Return the absolute current directory path - given a UNIX pathname.
Note that this path is returned in DOS format, not UNIX
format. Note this can be called with conn == NULL.
********************************************************************/
char *vfs_GetWd(connection_struct *conn, char *path)
{
pstring s;
static BOOL getwd_cache_init = False;
SMB_STRUCT_STAT st, st2;
int i;
*s = 0;
if (!use_getwd_cache)
return(vfs_getwd(conn,path));
/* init the cache */
if (!getwd_cache_init)
{
getwd_cache_init = True;
for (i=0;i<MAX_GETWDCACHE;i++)
{
string_set(&ino_list[i].dos_path,"");
ino_list[i].valid = False;
}
}
/* Get the inode of the current directory, if this doesn't work we're
in trouble :-) */
if (vfs_stat(conn, ".",&st) == -1)
{
DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
return(vfs_getwd(conn,path));
}
for (i=0; i<MAX_GETWDCACHE; i++)
if (ino_list[i].valid)
{
/* If we have found an entry with a matching inode and dev number
then find the inode number for the directory in the cached string.
If this agrees with that returned by the stat for the current
directory then all is o.k. (but make sure it is a directory all
the same...) */
if (st.st_ino == ino_list[i].inode &&
st.st_dev == ino_list[i].dev)
{
if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0)
{
if (st.st_ino == st2.st_ino &&
st.st_dev == st2.st_dev &&
(st2.st_mode & S_IFMT) == S_IFDIR)
{
pstrcpy (path, ino_list[i].dos_path);
/* promote it for future use */
array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
return (path);
}
else
{
/* If the inode is different then something's changed,
scrub the entry and start from scratch. */
ino_list[i].valid = False;
}
}
}
}
/* We don't have the information to hand so rely on traditional methods.
The very slow getcwd, which spawns a process on some systems, or the
not quite so bad getwd. */
if (!vfs_getwd(conn,s))
{
DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno)));
return (NULL);
}
pstrcpy(path,s);
DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
/* add it to the cache */
i = MAX_GETWDCACHE - 1;
string_set(&ino_list[i].dos_path,s);
ino_list[i].dev = st.st_dev;
ino_list[i].inode = st.st_ino;
ino_list[i].valid = True;
/* put it at the top of the list */
array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
return (path);
}
/*******************************************************************
Reduce a file name, removing .. elements and checking that
it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
on the system that has the referenced file system.
Widelinks are allowed if widelinks is true.
********************************************************************/
BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
{
#ifndef REDUCE_PATHS
return True;
#else
pstring dir2;
pstring wd;
pstring base_name;
pstring newname;
char *p=NULL;
BOOL relative = (*s != '/');
*dir2 = *wd = *base_name = *newname = 0;
if (widelinks)
{
unix_clean_name(s);
/* can't have a leading .. */
if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
{
DEBUG(3,("Illegal file name? (%s)\n",s));
return(False);
}
if (strlen(s) == 0)
pstrcpy(s,"./");
return(True);
}
DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
/* remove any double slashes */
all_string_sub(s,"//","/",0);
pstrcpy(base_name,s);
p = strrchr(base_name,'/');
if (!p)
return(True);
if (!vfs_GetWd(conn,wd))
{
DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
return(False);
}
if (vfs_ChDir(conn,dir) != 0)
{
DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
return(False);
}
if (!vfs_GetWd(conn,dir2))
{
DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
vfs_ChDir(conn,wd);
return(False);
}
if (p && (p != base_name))
{
*p = 0;
if (strcmp(p+1,".")==0)
p[1]=0;
if (strcmp(p+1,"..")==0)
*p = '/';
}
if (vfs_ChDir(conn,base_name) != 0)
{
vfs_ChDir(conn,wd);
DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
return(False);
}
if (!vfs_GetWd(conn,newname))
{
vfs_ChDir(conn,wd);
DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,dir2));
return(False);
}
if (p && (p != base_name))
{
pstrcat(newname,"/");
pstrcat(newname,p+1);
}
{
size_t l = strlen(dir2);
if (dir2[l-1] == '/')
l--;
if (strncmp(newname,dir2,l) != 0)
{
vfs_ChDir(conn,wd);
DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
return(False);
}
if (relative)
{
if (newname[l] == '/')
pstrcpy(s,newname + l + 1);
else
pstrcpy(s,newname+l);
}
else
pstrcpy(s,newname);
}
vfs_ChDir(conn,wd);
if (strlen(s) == 0)
pstrcpy(s,"./");
DEBUG(3,("reduced to %s\n",s));
return(True);
#endif
}