1998-10-04 03:28:43 +00:00
/*
Unix SMB / Netbios implementation .
Version 2.0
SMB wrapper directory 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 0213 9 , USA .
*/
# include "includes.h"
# include "wrapper.h"
extern pstring smb_cwd ;
static struct smbw_dir * smbw_dirs ;
extern struct bitmap * smbw_file_bmap ;
extern int DEBUGLEVEL ;
extern int smbw_busy ;
/*****************************************************
map a fd to a smbw_dir structure
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct smbw_dir * smbw_dir ( int fd )
{
struct smbw_dir * dir ;
for ( dir = smbw_dirs ; dir ; dir = dir - > next ) {
if ( dir - > fd = = fd ) return dir ;
}
return NULL ;
}
/*****************************************************
check if a DIR * is one of ours
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int smbw_dirp ( DIR * dirp )
{
struct smbw_dir * d = ( struct smbw_dir * ) dirp ;
struct smbw_dir * dir ;
for ( dir = smbw_dirs ; dir ; dir = dir - > next ) {
if ( dir = = d ) return 1 ;
}
return 0 ;
}
/*****************************************************
free a smbw_dir structure and all entries
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void free_dir ( struct smbw_dir * dir )
{
if ( dir - > list ) {
free ( dir - > list ) ;
}
if ( dir - > path ) free ( dir - > path ) ;
ZERO_STRUCTP ( dir ) ;
free ( dir ) ;
}
static struct smbw_dir * cur_dir ;
/*****************************************************
add a entry to a directory listing
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void smbw_dir_add ( struct file_info * finfo )
{
DEBUG ( 5 , ( " %s \n " , finfo - > name ) ) ;
if ( cur_dir - > malloced = = cur_dir - > count ) {
cur_dir - > list = ( struct file_info * ) Realloc ( cur_dir - > list ,
sizeof ( cur_dir - > list [ 0 ] ) *
( cur_dir - > count + 100 ) ) ;
if ( ! cur_dir - > list ) {
/* oops */
return ;
}
cur_dir - > malloced + = 100 ;
}
cur_dir - > list [ cur_dir - > count ] = * finfo ;
cur_dir - > count + + ;
}
/*****************************************************
add a entry to a directory listing
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void smbw_share_add ( const char * share , uint32 type , const char * comment )
{
struct file_info finfo ;
ZERO_STRUCT ( finfo ) ;
pstrcpy ( finfo . name , share ) ;
finfo . mode = aRONLY | aDIR ;
smbw_dir_add ( & finfo ) ;
}
/*****************************************************
open a directory on the server
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int smbw_dir_open ( const char * fname )
{
fstring server , share ;
pstring path ;
struct smbw_server * srv = NULL ;
struct smbw_dir * dir = NULL ;
pstring mask ;
int fd ;
char * s ;
DEBUG ( 4 , ( " %s \n " , __FUNCTION__ ) ) ;
if ( ! fname ) {
errno = EINVAL ;
return - 1 ;
}
smbw_init ( ) ;
/* work out what server they are after */
s = smbw_parse_path ( fname , server , share , path ) ;
DEBUG ( 4 , ( " dir_open share=%s \n " , share ) ) ;
/* get a connection to the server */
srv = smbw_server ( server , share ) ;
if ( ! srv ) {
/* smbw_server sets errno */
goto failed ;
}
dir = ( struct smbw_dir * ) malloc ( sizeof ( * dir ) ) ;
if ( ! dir ) {
errno = ENOMEM ;
goto failed ;
}
ZERO_STRUCTP ( dir ) ;
cur_dir = dir ;
slprintf ( mask , sizeof ( mask ) - 1 , " %s \\ * " , path ) ;
string_sub ( mask , " \\ \\ " , " \\ " ) ;
if ( strcmp ( share , " IPC$ " ) = = 0 ) {
DEBUG ( 4 , ( " doing NetShareEnum \n " ) ) ;
if ( cli_RNetShareEnum ( & srv - > cli , smbw_share_add ) < = 0 ) {
errno = smbw_errno ( & srv - > cli ) ;
goto failed ;
}
} else {
if ( cli_list ( & srv - > cli , mask , aHIDDEN | aSYSTEM | aDIR ,
smbw_dir_add ) < = 0 ) {
errno = smbw_errno ( & srv - > cli ) ;
goto failed ;
}
}
cur_dir = NULL ;
1998-10-04 06:22:08 +00:00
fd = open ( SMBW_DUMMY , O_WRONLY ) ;
1998-10-04 03:28:43 +00:00
if ( fd = = - 1 ) {
errno = EMFILE ;
goto failed ;
}
1998-10-04 04:48:17 +00:00
if ( bitmap_query ( smbw_file_bmap , fd ) ) {
DEBUG ( 0 , ( " ERROR: fd used in smbw_dir_open \n " ) ) ;
errno = EIO ;
goto failed ;
}
1998-10-04 03:28:43 +00:00
DLIST_ADD ( smbw_dirs , dir ) ;
bitmap_set ( smbw_file_bmap , fd ) ;
1998-10-04 04:48:17 +00:00
dir - > fd = fd ;
1998-10-04 03:28:43 +00:00
dir - > srv = srv ;
dir - > path = strdup ( s ) ;
DEBUG ( 4 , ( " -> %d \n " , dir - > count ) ) ;
return dir - > fd ;
failed :
if ( dir ) {
free_dir ( dir ) ;
}
return - 1 ;
}
/*****************************************************
a wrapper for fstat ( ) on a directory
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int smbw_dir_fstat ( int fd , struct stat * st )
{
struct smbw_dir * dir ;
DEBUG ( 4 , ( " %s \n " , __FUNCTION__ ) ) ;
dir = smbw_dir ( fd ) ;
if ( ! dir ) {
errno = EBADF ;
return - 1 ;
}
ZERO_STRUCTP ( st ) ;
smbw_setup_stat ( st , " " , dir - > count * sizeof ( struct dirent ) , aDIR ) ;
st - > st_dev = dir - > srv - > dev ;
return 0 ;
}
/*****************************************************
close a directory handle
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int smbw_dir_close ( int fd )
{
struct smbw_dir * dir ;
DEBUG ( 4 , ( " %s \n " , __FUNCTION__ ) ) ;
dir = smbw_dir ( fd ) ;
if ( ! dir ) {
DEBUG ( 4 , ( " %s(%d) \n " , __FUNCTION__ , __LINE__ ) ) ;
errno = EBADF ;
return - 1 ;
}
1998-10-04 04:48:17 +00:00
bitmap_clear ( smbw_file_bmap , dir - > fd ) ;
close ( dir - > fd ) ;
1998-10-04 03:28:43 +00:00
DLIST_REMOVE ( smbw_dirs , dir ) ;
free_dir ( dir ) ;
return 0 ;
}
/*****************************************************
a wrapper for getdents ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int smbw_getdents ( unsigned int fd , struct dirent * dirp , int count )
{
struct smbw_dir * dir ;
int n = 0 ;
DEBUG ( 4 , ( " %s \n " , __FUNCTION__ ) ) ;
smbw_busy + + ;
dir = smbw_dir ( fd ) ;
if ( ! dir ) {
errno = EBADF ;
smbw_busy - - ;
return - 1 ;
}
while ( count > = sizeof ( * dirp ) & & ( dir - > offset < dir - > count ) ) {
dirp - > d_off = ( dir - > offset + 1 ) * sizeof ( * dirp ) ;
dirp - > d_reclen = sizeof ( * dirp ) ;
safe_strcpy ( & dirp - > d_name [ 0 ] , dir - > list [ dir - > offset ] . name ,
sizeof ( dirp - > d_name ) - 1 ) ;
dirp - > d_ino = smbw_inode ( dir - > list [ dir - > offset ] . name ) ;
dir - > offset + + ;
count - = dirp - > d_reclen ;
if ( dir - > offset = = dir - > count ) {
dirp - > d_off = - 1 ;
}
dirp + + ;
n + + ;
}
smbw_busy - - ;
return n * sizeof ( * dirp ) ;
}
/*****************************************************
a wrapper for chdir ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int smbw_chdir ( const char * name )
{
struct smbw_server * srv ;
fstring server , share ;
pstring path ;
uint32 mode = aDIR ;
char * cwd ;
smbw_init ( ) ;
if ( smbw_busy ) return real_chdir ( cwd ) ;
smbw_busy + + ;
if ( ! name ) {
errno = EINVAL ;
goto failed ;
}
DEBUG ( 4 , ( " %s (%s) \n " , __FUNCTION__ , name ) ) ;
/* work out what server they are after */
cwd = smbw_parse_path ( name , server , share , path ) ;
if ( strncmp ( cwd , SMBW_PREFIX , strlen ( SMBW_PREFIX ) ) ) {
if ( real_chdir ( cwd ) = = 0 ) {
DEBUG ( 4 , ( " set SMBW_CWD to %s \n " , cwd ) ) ;
pstrcpy ( smb_cwd , cwd ) ;
if ( setenv ( SMBW_PWD_ENV , smb_cwd , 1 ) ) {
DEBUG ( 4 , ( " setenv failed \n " ) ) ;
}
goto success ;
}
errno = ENOENT ;
goto failed ;
}
/* get a connection to the server */
srv = smbw_server ( server , share ) ;
if ( ! srv ) {
/* smbw_server sets errno */
goto failed ;
}
if ( strcmp ( share , " IPC$ " ) & &
! smbw_getatr ( srv , path ,
& mode , NULL , NULL , NULL , NULL ) ) {
errno = smbw_errno ( & srv - > cli ) ;
goto failed ;
}
if ( ! ( mode & aDIR ) ) {
errno = ENOTDIR ;
goto failed ;
}
DEBUG ( 4 , ( " set SMBW_CWD2 to %s \n " , cwd ) ) ;
pstrcpy ( smb_cwd , cwd ) ;
if ( setenv ( SMBW_PWD_ENV , smb_cwd , 1 ) ) {
DEBUG ( 4 , ( " setenv failed \n " ) ) ;
}
/* we don't want the old directory to be busy */
real_chdir ( " / " ) ;
success :
smbw_busy - - ;
return 0 ;
failed :
smbw_busy - - ;
return - 1 ;
}
/*****************************************************
a wrapper for lseek ( ) on directories
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
off_t smbw_dir_lseek ( int fd , off_t offset , int whence )
{
struct smbw_dir * dir ;
off_t ret ;
DEBUG ( 4 , ( " %s offset=%d whence=%d \n " , __FUNCTION__ ,
( int ) offset , whence ) ) ;
dir = smbw_dir ( fd ) ;
if ( ! dir ) {
errno = EBADF ;
return - 1 ;
}
switch ( whence ) {
case SEEK_SET :
dir - > offset = offset / sizeof ( struct dirent ) ;
break ;
case SEEK_CUR :
dir - > offset + = offset / sizeof ( struct dirent ) ;
break ;
case SEEK_END :
dir - > offset = ( dir - > count * sizeof ( struct dirent ) ) + offset ;
dir - > offset / = sizeof ( struct dirent ) ;
break ;
}
ret = dir - > offset * sizeof ( struct dirent ) ;
DEBUG ( 4 , ( " -> %d \n " , ( int ) ret ) ) ;
return ret ;
}
/*****************************************************
a wrapper for mkdir ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int smbw_mkdir ( const char * fname , mode_t mode )
{
struct smbw_server * srv ;
fstring server , share ;
pstring path ;
DEBUG ( 4 , ( " %s (%s) \n " , __FUNCTION__ , fname ) ) ;
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_mkdir ( & srv - > cli , path ) ) {
errno = smbw_errno ( & srv - > cli ) ;
goto failed ;
}
smbw_busy - - ;
return 0 ;
failed :
smbw_busy - - ;
return - 1 ;
}
/*****************************************************
a wrapper for rmdir ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int smbw_rmdir ( const char * fname )
{
struct smbw_server * srv ;
fstring server , share ;
pstring path ;
DEBUG ( 4 , ( " %s (%s) \n " , __FUNCTION__ , fname ) ) ;
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_rmdir ( & srv - > cli , path ) ) {
errno = smbw_errno ( & srv - > cli ) ;
goto failed ;
}
smbw_busy - - ;
return 0 ;
failed :
smbw_busy - - ;
return - 1 ;
}
/*****************************************************
a wrapper for getcwd ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * smbw_getcwd ( char * buf , size_t size )
{
smbw_init ( ) ;
if ( smbw_busy ) {
return __getcwd ( buf , size ) ;
}
smbw_busy + + ;
if ( ! buf ) {
if ( size < = 0 ) size = strlen ( smb_cwd ) + 1 ;
buf = ( char * ) malloc ( size ) ;
if ( ! buf ) {
errno = ENOMEM ;
smbw_busy - - ;
return NULL ;
}
}
if ( strlen ( smb_cwd ) > size - 1 ) {
errno = ERANGE ;
smbw_busy - - ;
return NULL ;
}
safe_strcpy ( buf , smb_cwd , size ) ;
smbw_busy - - ;
return buf ;
}
/*****************************************************
a wrapper for fchdir ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int smbw_fchdir ( unsigned int fd )
{
struct smbw_dir * dir ;
DEBUG ( 4 , ( " %s \n " , __FUNCTION__ ) ) ;
smbw_busy + + ;
dir = smbw_dir ( fd ) ;
if ( ! dir ) {
errno = EBADF ;
smbw_busy - - ;
return - 1 ;
}
smbw_busy - - ;
return chdir ( dir - > path ) ;
}
/*****************************************************
open a directory on the server
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
DIR * smbw_opendir ( const char * fname )
{
int fd ;
smbw_busy + + ;
fd = smbw_dir_open ( fname ) ;
if ( fd = = - 1 ) {
smbw_busy - - ;
return NULL ;
}
smbw_busy - - ;
return ( DIR * ) smbw_dir ( fd ) ;
}
/*****************************************************
read one entry from a directory
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-10-04 04:33:56 +00:00
struct dirent * smbw_readdir ( DIR * dirp )
1998-10-04 03:28:43 +00:00
{
1998-10-04 04:33:56 +00:00
struct smbw_dir * d = ( struct smbw_dir * ) dirp ;
1998-10-04 03:28:43 +00:00
static struct dirent de ;
if ( smbw_getdents ( d - > fd , & de , sizeof ( struct dirent ) ) > 0 )
return & de ;
return NULL ;
}
/*****************************************************
close a DIR *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-10-04 04:33:56 +00:00
int smbw_closedir ( DIR * dirp )
1998-10-04 03:28:43 +00:00
{
1998-10-04 04:33:56 +00:00
struct smbw_dir * d = ( struct smbw_dir * ) dirp ;
1998-10-04 03:28:43 +00:00
return smbw_close ( d - > fd ) ;
}
/*****************************************************
seek in a directory
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-10-04 04:33:56 +00:00
void smbw_seekdir ( DIR * dirp , off_t offset )
1998-10-04 03:28:43 +00:00
{
1998-10-04 04:33:56 +00:00
struct smbw_dir * d = ( struct smbw_dir * ) dirp ;
1998-10-04 03:28:43 +00:00
smbw_dir_lseek ( d - > fd , offset , SEEK_SET ) ;
}
/*****************************************************
current loc in a directory
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-10-04 04:33:56 +00:00
off_t smbw_telldir ( DIR * dirp )
1998-10-04 03:28:43 +00:00
{
1998-10-04 04:33:56 +00:00
struct smbw_dir * d = ( struct smbw_dir * ) dirp ;
1998-10-04 03:28:43 +00:00
return smbw_dir_lseek ( d - > fd , 0 , SEEK_CUR ) ;
}