2002-08-27 13:30:17 +04:00
/*
* AppleTalk VFS module for Samba - 3. x
*
* Copyright ( C ) Alexei Kotovich , 2002
2003-05-12 03:34:18 +04:00
* Copyright ( C ) Stefan ( metze ) Metzmacher , 2003
2002-08-27 13:30:17 +04:00
*
* 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
2007-07-09 23:25:36 +04:00
* the Free Software Foundation ; either version 3 of the License , or
2002-08-27 13:30:17 +04:00
* ( 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
2007-07-10 09:23:25 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2002-08-27 13:30:17 +04:00
*/
2003-05-12 03:34:18 +04:00
# include "includes.h"
2011-03-23 00:34:22 +03:00
# include "smbd/smbd.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2003-05-12 03:34:18 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
2002-08-27 13:30:17 +04:00
# define APPLEDOUBLE ".AppleDouble"
# define ADOUBLEMODE 0777
/* atalk functions */
static int atalk_build_paths ( TALLOC_CTX * ctx , const char * path ,
2009-11-27 16:58:46 +03:00
const char * fname ,
char * * adbl_path , char * * orig_path ,
SMB_STRUCT_STAT * adbl_info ,
2011-10-18 22:24:35 +04:00
SMB_STRUCT_STAT * orig_info ) ;
2002-08-27 13:30:17 +04:00
static int atalk_unlink_file ( const char * path ) ;
static int atalk_get_path_ptr ( char * path )
{
int i = 0 ;
int ptr = 0 ;
for ( i = 0 ; path [ i ] ; i + + ) {
if ( path [ i ] = = ' / ' )
ptr = i ;
/* get out some 'spam';) from win32's file name */
else if ( path [ i ] = = ' : ' ) {
path [ i ] = ' \0 ' ;
break ;
}
}
return ptr ;
}
2009-11-27 16:58:46 +03:00
static int atalk_build_paths ( TALLOC_CTX * ctx , const char * path ,
const char * fname ,
char * * adbl_path , char * * orig_path ,
SMB_STRUCT_STAT * adbl_info ,
2011-10-18 22:24:35 +04:00
SMB_STRUCT_STAT * orig_info )
2002-08-27 13:30:17 +04:00
{
int ptr0 = 0 ;
int ptr1 = 0 ;
char * dname = 0 ;
char * name = 0 ;
if ( ! ctx | | ! path | | ! fname | | ! adbl_path | | ! orig_path | |
! adbl_info | | ! orig_info )
return - 1 ;
#if 0
DEBUG ( 3 , ( " ATALK: PATH: %s[%s] \n " , path , fname ) ) ;
# endif
2011-10-18 22:54:53 +04:00
if ( strstr_m ( path , APPLEDOUBLE ) | | strstr_m ( fname , APPLEDOUBLE ) ) {
2002-08-27 13:30:17 +04:00
DEBUG ( 3 , ( " ATALK: path %s[%s] already contains %s \n " , path , fname , APPLEDOUBLE ) ) ;
return - 1 ;
}
if ( fname [ 0 ] = = ' . ' ) ptr0 + + ;
if ( fname [ 1 ] = = ' / ' ) ptr0 + + ;
* orig_path = talloc_asprintf ( ctx , " %s/%s " , path , & fname [ ptr0 ] ) ;
/* get pointer to last '/' */
ptr1 = atalk_get_path_ptr ( * orig_path ) ;
2011-10-18 22:24:35 +04:00
sys_lstat ( * orig_path , orig_info , false ) ;
2002-08-27 13:30:17 +04:00
2009-05-14 17:34:42 +04:00
if ( S_ISDIR ( orig_info - > st_ex_mode ) ) {
2002-08-27 13:30:17 +04:00
* adbl_path = talloc_asprintf ( ctx , " %s/%s/%s/ " ,
path , & fname [ ptr0 ] , APPLEDOUBLE ) ;
} else {
dname = talloc_strdup ( ctx , * orig_path ) ;
dname [ ptr1 ] = ' \0 ' ;
name = * orig_path ;
* adbl_path = talloc_asprintf ( ctx , " %s/%s/%s " ,
dname , APPLEDOUBLE , & name [ ptr1 + 1 ] ) ;
}
#if 0
DEBUG ( 3 , ( " ATALK: DEBUG: \n %s \n %s \n " , * orig_path , * adbl_path ) ) ;
# endif
2011-10-18 22:24:35 +04:00
sys_lstat ( * adbl_path , adbl_info , false ) ;
2002-08-27 13:30:17 +04:00
return 0 ;
}
static int atalk_unlink_file ( const char * path )
{
int ret = 0 ;
become_root ( ) ;
ret = unlink ( path ) ;
unbecome_root ( ) ;
return ret ;
}
static void atalk_add_to_list ( name_compare_entry * * list )
{
int i , count = 0 ;
name_compare_entry * new_list = 0 ;
name_compare_entry * cur_list = 0 ;
cur_list = * list ;
if ( cur_list ) {
for ( i = 0 , count = 0 ; cur_list [ i ] . name ; i + + , count + + ) {
2011-10-18 22:54:53 +04:00
if ( strstr_m ( cur_list [ i ] . name , APPLEDOUBLE ) )
2002-08-27 13:30:17 +04:00
return ;
}
}
2010-03-10 06:15:44 +03:00
if ( ! ( new_list = SMB_CALLOC_ARRAY ( name_compare_entry , count + 2 ) ) )
2002-08-27 13:30:17 +04:00
return ;
for ( i = 0 ; i < count ; i + + ) {
2004-12-07 21:25:53 +03:00
new_list [ i ] . name = SMB_STRDUP ( cur_list [ i ] . name ) ;
2002-08-27 13:30:17 +04:00
new_list [ i ] . is_wild = cur_list [ i ] . is_wild ;
}
2004-12-07 21:25:53 +03:00
new_list [ i ] . name = SMB_STRDUP ( APPLEDOUBLE ) ;
2002-08-27 13:30:17 +04:00
new_list [ i ] . is_wild = False ;
free_namearray ( * list ) ;
* list = new_list ;
new_list = 0 ;
cur_list = 0 ;
}
static void atalk_rrmdir ( TALLOC_CTX * ctx , char * path )
{
char * dpath ;
2004-11-27 21:57:44 +03:00
SMB_STRUCT_DIRENT * dent = 0 ;
2005-08-22 22:03:08 +04:00
SMB_STRUCT_DIR * dir ;
2002-08-27 13:30:17 +04:00
if ( ! path ) return ;
2012-03-28 06:01:19 +04:00
dir = opendir ( path ) ;
2003-02-12 00:56:38 +03:00
if ( ! dir ) return ;
2012-03-28 06:03:00 +04:00
while ( NULL ! = ( dent = readdir ( dir ) ) ) {
2003-02-12 00:56:38 +03:00
if ( strcmp ( dent - > d_name , " . " ) = = 0 | |
strcmp ( dent - > d_name , " .. " ) = = 0 )
continue ;
if ( ! ( dpath = talloc_asprintf ( ctx , " %s/%s " ,
path , dent - > d_name ) ) )
continue ;
atalk_unlink_file ( dpath ) ;
2002-08-27 13:30:17 +04:00
}
2003-02-12 00:56:38 +03:00
2012-03-28 06:08:27 +04:00
closedir ( dir ) ;
2002-08-27 13:30:17 +04:00
}
/* Disk operations */
/* Directory operations */
2006-12-19 23:16:52 +03:00
static SMB_STRUCT_DIR * atalk_opendir ( struct vfs_handle_struct * handle , const char * fname , const char * mask , uint32 attr )
2002-08-27 13:30:17 +04:00
{
2005-08-22 22:03:08 +04:00
SMB_STRUCT_DIR * ret = 0 ;
2003-05-12 03:34:18 +04:00
2006-07-11 22:01:26 +04:00
ret = SMB_VFS_NEXT_OPENDIR ( handle , fname , mask , attr ) ;
2002-08-27 13:30:17 +04:00
/*
* when we try to perform delete operation upon file which has fork
* in . / . AppleDouble and this directory wasn ' t hidden by Samba ,
* MS Windows explorer causes the error : " Cannot find the specified file "
* There is some workaround to avoid this situation , i . e . if
* connection has not . AppleDouble entry in either veto or hide
* list then it would be nice to add one .
*/
2006-07-11 22:01:26 +04:00
atalk_add_to_list ( & handle - > conn - > hide_list ) ;
atalk_add_to_list ( & handle - > conn - > veto_list ) ;
2002-08-27 13:30:17 +04:00
return ret ;
}
2011-02-09 02:07:48 +03:00
static SMB_STRUCT_DIR * atalk_fdopendir ( struct vfs_handle_struct * handle , files_struct * fsp , const char * mask , uint32 attr )
{
SMB_STRUCT_DIR * ret = 0 ;
ret = SMB_VFS_NEXT_FDOPENDIR ( handle , fsp , mask , attr ) ;
if ( ret = = NULL ) {
return ret ;
}
/*
* when we try to perform delete operation upon file which has fork
* in . / . AppleDouble and this directory wasn ' t hidden by Samba ,
* MS Windows explorer causes the error : " Cannot find the specified file "
* There is some workaround to avoid this situation , i . e . if
* connection has not . AppleDouble entry in either veto or hide
* list then it would be nice to add one .
*/
atalk_add_to_list ( & handle - > conn - > hide_list ) ;
atalk_add_to_list ( & handle - > conn - > veto_list ) ;
return ret ;
}
2006-07-11 22:01:26 +04:00
static int atalk_rmdir ( struct vfs_handle_struct * handle , const char * path )
2002-08-27 13:30:17 +04:00
{
2007-10-19 04:40:25 +04:00
bool add = False ;
2002-08-27 13:30:17 +04:00
TALLOC_CTX * ctx = 0 ;
char * dpath ;
2006-07-11 22:01:26 +04:00
if ( ! handle - > conn - > origpath | | ! path ) goto exit_rmdir ;
2002-08-27 13:30:17 +04:00
/* due to there is no way to change bDeleteVetoFiles variable
* from this module , gotta use talloc stuff . .
*/
2011-10-18 22:54:53 +04:00
strstr_m ( path , APPLEDOUBLE ) ? ( add = False ) : ( add = True ) ;
2002-08-27 13:30:17 +04:00
2002-12-22 19:03:28 +03:00
if ( ! ( ctx = talloc_init ( " remove_directory " ) ) )
2002-08-27 13:30:17 +04:00
goto exit_rmdir ;
if ( ! ( dpath = talloc_asprintf ( ctx , " %s/%s%s " ,
2006-07-11 22:01:26 +04:00
handle - > conn - > origpath , path , add ? " / " APPLEDOUBLE : " " ) ) )
2002-08-27 13:30:17 +04:00
goto exit_rmdir ;
atalk_rrmdir ( ctx , dpath ) ;
exit_rmdir :
talloc_destroy ( ctx ) ;
2006-07-11 22:01:26 +04:00
return SMB_VFS_NEXT_RMDIR ( handle , path ) ;
2002-08-27 13:30:17 +04:00
}
/* File operations */
2009-07-01 04:04:38 +04:00
static int atalk_rename ( struct vfs_handle_struct * handle ,
const struct smb_filename * smb_fname_src ,
const struct smb_filename * smb_fname_dst )
2002-08-27 13:30:17 +04:00
{
int ret = 0 ;
2009-07-01 04:04:38 +04:00
char * oldname = NULL ;
char * adbl_path = NULL ;
char * orig_path = NULL ;
2002-08-27 13:30:17 +04:00
SMB_STRUCT_STAT adbl_info ;
SMB_STRUCT_STAT orig_info ;
2009-07-01 04:04:38 +04:00
NTSTATUS status ;
2002-08-27 13:30:17 +04:00
2009-07-01 04:04:38 +04:00
ret = SMB_VFS_NEXT_RENAME ( handle , smb_fname_src , smb_fname_dst ) ;
2002-08-27 13:30:17 +04:00
2009-07-01 04:04:38 +04:00
status = get_full_smb_filename ( talloc_tos ( ) , smb_fname_src , & oldname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2002-08-27 13:30:17 +04:00
return ret ;
2009-07-01 04:04:38 +04:00
}
2002-08-27 13:30:17 +04:00
2009-07-01 04:04:38 +04:00
if ( atalk_build_paths ( talloc_tos ( ) , handle - > conn - > origpath , oldname ,
& adbl_path , & orig_path , & adbl_info ,
2011-10-18 22:24:35 +04:00
& orig_info ) ! = 0 )
2007-03-01 05:43:33 +03:00
goto exit_rename ;
2002-08-27 13:30:17 +04:00
2009-05-14 17:34:42 +04:00
if ( S_ISDIR ( orig_info . st_ex_mode ) | | S_ISREG ( orig_info . st_ex_mode ) ) {
2002-08-27 13:30:17 +04:00
DEBUG ( 3 , ( " ATALK: %s has passed.. \n " , adbl_path ) ) ;
goto exit_rename ;
}
atalk_unlink_file ( adbl_path ) ;
exit_rename :
2009-07-02 20:27:44 +04:00
TALLOC_FREE ( oldname ) ;
2009-07-01 04:04:38 +04:00
TALLOC_FREE ( adbl_path ) ;
TALLOC_FREE ( orig_path ) ;
2002-08-27 13:30:17 +04:00
return ret ;
}
2009-07-02 20:27:44 +04:00
static int atalk_unlink ( struct vfs_handle_struct * handle ,
const struct smb_filename * smb_fname )
2002-08-27 13:30:17 +04:00
{
int ret = 0 , i ;
2009-07-02 20:27:44 +04:00
char * path = NULL ;
char * adbl_path = NULL ;
char * orig_path = NULL ;
2002-08-27 13:30:17 +04:00
SMB_STRUCT_STAT adbl_info ;
SMB_STRUCT_STAT orig_info ;
2009-07-02 20:27:44 +04:00
NTSTATUS status ;
2002-08-27 13:30:17 +04:00
2009-07-02 20:27:44 +04:00
ret = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
2002-08-27 13:30:17 +04:00
2009-07-02 20:27:44 +04:00
status = get_full_smb_filename ( talloc_tos ( ) , smb_fname , & path ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ret ;
}
2002-08-27 13:30:17 +04:00
/* no .AppleDouble sync if veto or hide list is empty,
* otherwise " Cannot find the specified file " error will be caused
*/
2006-07-11 22:01:26 +04:00
if ( ! handle - > conn - > veto_list ) return ret ;
if ( ! handle - > conn - > hide_list ) return ret ;
2002-08-27 13:30:17 +04:00
2006-07-11 22:01:26 +04:00
for ( i = 0 ; handle - > conn - > veto_list [ i ] . name ; i + + ) {
2011-10-18 22:54:53 +04:00
if ( strstr_m ( handle - > conn - > veto_list [ i ] . name , APPLEDOUBLE ) )
2002-08-27 13:30:17 +04:00
break ;
}
2006-07-11 22:01:26 +04:00
if ( ! handle - > conn - > veto_list [ i ] . name ) {
for ( i = 0 ; handle - > conn - > hide_list [ i ] . name ; i + + ) {
2011-10-18 22:54:53 +04:00
if ( strstr_m ( handle - > conn - > hide_list [ i ] . name , APPLEDOUBLE ) )
2002-08-27 13:30:17 +04:00
break ;
else {
DEBUG ( 3 , ( " ATALK: %s is not hidden, skipped.. \n " ,
APPLEDOUBLE ) ) ;
2009-07-02 20:27:44 +04:00
goto exit_unlink ;
2002-08-27 13:30:17 +04:00
}
}
}
2009-07-02 20:27:44 +04:00
if ( atalk_build_paths ( talloc_tos ( ) , handle - > conn - > origpath , path ,
& adbl_path , & orig_path ,
2011-10-18 22:24:35 +04:00
& adbl_info , & orig_info ) ! = 0 )
2007-03-01 05:43:33 +03:00
goto exit_unlink ;
2002-08-27 13:30:17 +04:00
2009-05-14 17:34:42 +04:00
if ( S_ISDIR ( orig_info . st_ex_mode ) | | S_ISREG ( orig_info . st_ex_mode ) ) {
2002-08-27 13:30:17 +04:00
DEBUG ( 3 , ( " ATALK: %s has passed.. \n " , adbl_path ) ) ;
goto exit_unlink ;
}
atalk_unlink_file ( adbl_path ) ;
2009-07-02 20:27:44 +04:00
exit_unlink :
TALLOC_FREE ( path ) ;
TALLOC_FREE ( adbl_path ) ;
TALLOC_FREE ( orig_path ) ;
2002-08-27 13:30:17 +04:00
return ret ;
}
2006-07-11 22:01:26 +04:00
static int atalk_chmod ( struct vfs_handle_struct * handle , const char * path , mode_t mode )
2002-08-27 13:30:17 +04:00
{
int ret = 0 ;
char * adbl_path = 0 ;
char * orig_path = 0 ;
SMB_STRUCT_STAT adbl_info ;
SMB_STRUCT_STAT orig_info ;
TALLOC_CTX * ctx ;
2006-07-11 22:01:26 +04:00
ret = SMB_VFS_NEXT_CHMOD ( handle , path , mode ) ;
2002-08-27 13:30:17 +04:00
2006-07-11 22:01:26 +04:00
if ( ! path ) return ret ;
2002-08-27 13:30:17 +04:00
2002-12-22 19:03:28 +03:00
if ( ! ( ctx = talloc_init ( " chmod_file " ) ) )
2002-08-27 13:30:17 +04:00
return ret ;
2009-11-27 16:58:46 +03:00
if ( atalk_build_paths ( ctx , handle - > conn - > origpath , path , & adbl_path ,
2011-10-18 22:24:35 +04:00
& orig_path , & adbl_info , & orig_info ) ! = 0 )
2007-03-01 05:43:33 +03:00
goto exit_chmod ;
2002-08-27 13:30:17 +04:00
2009-05-14 17:34:42 +04:00
if ( ! S_ISDIR ( orig_info . st_ex_mode ) & & ! S_ISREG ( orig_info . st_ex_mode ) ) {
2002-08-27 13:30:17 +04:00
DEBUG ( 3 , ( " ATALK: %s has passed.. \n " , orig_path ) ) ;
goto exit_chmod ;
}
chmod ( adbl_path , ADOUBLEMODE ) ;
exit_chmod :
talloc_destroy ( ctx ) ;
return ret ;
}
2006-07-11 22:01:26 +04:00
static int atalk_chown ( struct vfs_handle_struct * handle , const char * path , uid_t uid , gid_t gid )
2002-08-27 13:30:17 +04:00
{
int ret = 0 ;
char * adbl_path = 0 ;
char * orig_path = 0 ;
SMB_STRUCT_STAT adbl_info ;
SMB_STRUCT_STAT orig_info ;
TALLOC_CTX * ctx ;
2006-07-11 22:01:26 +04:00
ret = SMB_VFS_NEXT_CHOWN ( handle , path , uid , gid ) ;
2002-08-27 13:30:17 +04:00
2006-07-11 22:01:26 +04:00
if ( ! path ) return ret ;
2002-08-27 13:30:17 +04:00
2002-12-22 19:03:28 +03:00
if ( ! ( ctx = talloc_init ( " chown_file " ) ) )
2002-08-27 13:30:17 +04:00
return ret ;
2009-11-27 16:58:46 +03:00
if ( atalk_build_paths ( ctx , handle - > conn - > origpath , path ,
& adbl_path , & orig_path ,
2011-10-18 22:24:35 +04:00
& adbl_info , & orig_info ) ! = 0 )
2007-03-01 05:43:33 +03:00
goto exit_chown ;
2002-08-27 13:30:17 +04:00
2009-05-14 17:34:42 +04:00
if ( ! S_ISDIR ( orig_info . st_ex_mode ) & & ! S_ISREG ( orig_info . st_ex_mode ) ) {
2002-08-27 13:30:17 +04:00
DEBUG ( 3 , ( " ATALK: %s has passed.. \n " , orig_path ) ) ;
goto exit_chown ;
}
2009-01-01 05:06:57 +03:00
if ( chown ( adbl_path , uid , gid ) = = - 1 ) {
DEBUG ( 3 , ( " ATALK: chown error %s \n " , strerror ( errno ) ) ) ;
}
2002-08-27 13:30:17 +04:00
exit_chown :
talloc_destroy ( ctx ) ;
return ret ;
}
2007-05-24 03:55:12 +04:00
static int atalk_lchown ( struct vfs_handle_struct * handle , const char * path , uid_t uid , gid_t gid )
{
int ret = 0 ;
char * adbl_path = 0 ;
char * orig_path = 0 ;
SMB_STRUCT_STAT adbl_info ;
SMB_STRUCT_STAT orig_info ;
TALLOC_CTX * ctx ;
ret = SMB_VFS_NEXT_CHOWN ( handle , path , uid , gid ) ;
if ( ! path ) return ret ;
if ( ! ( ctx = talloc_init ( " lchown_file " ) ) )
return ret ;
2009-11-27 16:58:46 +03:00
if ( atalk_build_paths ( ctx , handle - > conn - > origpath , path ,
& adbl_path , & orig_path ,
2011-10-18 22:24:35 +04:00
& adbl_info , & orig_info ) ! = 0 )
2007-05-24 03:55:12 +04:00
goto exit_lchown ;
2009-05-14 17:34:42 +04:00
if ( ! S_ISDIR ( orig_info . st_ex_mode ) & & ! S_ISREG ( orig_info . st_ex_mode ) ) {
2007-05-24 03:55:12 +04:00
DEBUG ( 3 , ( " ATALK: %s has passed.. \n " , orig_path ) ) ;
goto exit_lchown ;
}
2009-01-01 05:06:57 +03:00
if ( lchown ( adbl_path , uid , gid ) = = - 1 ) {
DEBUG ( 3 , ( " ATALK: lchown error %s \n " , strerror ( errno ) ) ) ;
}
2007-05-24 03:55:12 +04:00
exit_lchown :
talloc_destroy ( ctx ) ;
return ret ;
}
2009-07-24 04:28:58 +04:00
static struct vfs_fn_pointers vfs_netatalk_fns = {
2011-12-04 08:45:04 +04:00
. opendir_fn = atalk_opendir ,
. fdopendir_fn = atalk_fdopendir ,
. rmdir_fn = atalk_rmdir ,
. rename_fn = atalk_rename ,
. unlink_fn = atalk_unlink ,
. chmod_fn = atalk_chmod ,
. chown_fn = atalk_chown ,
. lchown_fn = atalk_lchown ,
2002-08-27 13:30:17 +04:00
} ;
2006-12-19 23:16:52 +03:00
NTSTATUS vfs_netatalk_init ( void ) ;
2003-04-28 21:48:48 +04:00
NTSTATUS vfs_netatalk_init ( void )
2002-08-27 13:30:17 +04:00
{
2009-07-24 04:28:58 +04:00
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " netatalk " ,
& vfs_netatalk_fns ) ;
2002-08-27 13:30:17 +04:00
}