diff -Nur vfs/Makefile vfs.new/Makefile --- vfs/Makefile Thu Jan 1 00:00:00 1970 +++ vfs.new/Makefile Mon Jul 12 10:48:56 2004 @@ -0,0 +1,40 @@ +########################################################################## +# Makefile for Samba VFS modules +########################################################################### + +CC=gcc -g +LIBTOOL=/usr/bin/libtool +# REPLACE with samba source +SMB=/u/redhat/paris/cvs/samba/smb3.0a20 + +# REPLACE with samba build folder +BUILD=/mnt/hdd/build/smb.1.3 + +CFLAGS=-Wall -I $(BUILD)/include \ +-I$(SMB)/source -I$(SMB)/source/include -I$(SMB)/source/ubiqx -I$(SMB)/source/smbwrapper + + +LDFLAGS=-shared + +VFS_OBJS=vfs_ads.so + +SHELL=/bin/sh + +default: $(VFS_OBJS) + +# Pattern rules + +%.so: %.lo + @echo Linking $< + @$(LIBTOOL) --mode=link $(CC) -o $@ $< $(LDFLAGS) + +%.lo: %.c + @echo Compiling $< + @$(LIBTOOL) --mode=compile $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +# Misc targets + +clean: + rm -rf .libs */.libs + rm -f core *~ *% *.bak *.o */*.o *.lo $(VFS_OBJS) + diff -Nur vfs/README vfs.new/README --- vfs/README Thu Jan 1 00:00:00 1970 +++ vfs.new/README Tue Jul 13 02:28:21 2004 @@ -0,0 +1,34 @@ +This a vfs for NT ADS +you must set SMB and BUILD variables in Makefile. + +old smb.conf +[test_ads] + comment = test ADS Mac/PC directory + path=/home/test_ads/ +# /.AppleD* is mandatory + veto files = /.AppleD*/Network Trash Folder/Icon\r/ + delete veto files = True +# full path to vfs_ads.so + vfs object = /usr/src/samba/vfs/vfs_ads.so + browseable = yes + writable = yes + +new one (current svn tree) +copy vfs_ads.so as ads.so in /lib/vfs/ +eg +cp vfs_ads.so /opt/lib/vfs/ads.so + +smb.conf +[test_ads] + comment = test ADS Mac/PC directory + path=/home/test_ads/ + +# /.AppleD* is mandatory + veto files = /.AppleD*/Network Trash Folder/Icon\r/ + delete veto files = True + vfs objects = ads + browseable = yes + writable = yes + + +Didier diff -Nur vfs/vfs_ads.c vfs.new/vfs_ads.c --- vfs/vfs_ads.c Thu Jan 1 00:00:00 1970 +++ vfs.new/vfs_ads.c Wed Jul 14 16:37:15 2004 @@ -0,0 +1,1029 @@ +/* + * CAP VFS module for Samba 3.x Version 0.3 + * + * Copyright (C) Tim Potter, 1999-2000 + * Copyright (C) Alexander Bokovoy, 2002-2003 + * Copyright (C) Stefan (metze) Metzmacher, 2003 + * Copyright (C) TAKAHASHI Motonobu (monyo), 2003 + * + * 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. + * + * modified for alternate data stream + * Copyright (C) Didier Gautheron 2004 + * + * this module should compile with old 3.0 API and 2004-07 svn API + */ + + +#include "includes.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + +#define ADS_FOLDER ".AppleDouble" +#define ADOUBLEMODE 0777 + +/* FIXME found a better test */ +#ifdef SMB_VFS_OP +#define ADS_NEW_MODULE + +/* for current svn tree */ +#define ADS_TALLOC_INIT(a) talloc_init(a) + +#define HANDLE_PARAMETER vfs_handle_struct *handle, +#define HANDLE handle, + +/* ------------------- */ +#else + +#define ADS_TALLOC_INIT(a) talloc_init() + +#define HANDLE_PARAMETER +#define HANDLE + +/* VFS operations */ +static struct vfs_ops default_vfs_ops; /* For passthrough operation */ +static struct smb_vfs_handle_struct *ads_handle; + +#define SMB_VFS_NEXT_DISK_FREE(a,b,c,d,e,f,g) default_vfs_ops.disk_free(b,c,d,e,f,g) +#define SMB_VFS_NEXT_OPENDIR(a,b,c) default_vfs_ops.opendir(b,c) +#define SMB_VFS_NEXT_READDIR(a,b,c) default_vfs_ops.readdir(b,c) +#define SMB_VFS_NEXT_MKDIR(a,b,c,d) default_vfs_ops.mkdir(b,c,d) +#define SMB_VFS_NEXT_RMDIR(a,b,c) default_vfs_ops.rmdir(b,c) +#define SMB_VFS_NEXT_OPEN(a,b,c,d,e) default_vfs_ops.open(b,c,d,e) +#define SMB_VFS_NEXT_RENAME(a,b,c,d) default_vfs_ops.rename(b,c,d) +#define SMB_VFS_NEXT_STAT(a,b,c,d) default_vfs_ops.stat(b,c,d) +#define SMB_VFS_NEXT_LSTAT(a,b,c,d) default_vfs_ops.lstat(b,c,d) +#define SMB_VFS_NEXT_UNLINK(a,b,c) default_vfs_ops.unlink(b,c) +#define SMB_VFS_NEXT_CHMOD(a,b,c,d) default_vfs_ops.chmod(b,c,d) +#define SMB_VFS_NEXT_CHOWN(a,b,c,d,e) default_vfs_ops.chown(b,c,d,e) +#define SMB_VFS_NEXT_CHDIR(a,b,c) default_vfs_ops.chdir(b,c) +#define SMB_VFS_NEXT_UTIME(a,b,c,d) default_vfs_ops.utime(b,c,d) +#define SMB_VFS_NEXT_SYMLINK(a,b,c,d) default_vfs_ops.symlink(b,c,d) +#define SMB_VFS_NEXT_READLINK(a,b,c,d,e) default_vfs_ops.readlink(b,c,d,e) +#define SMB_VFS_NEXT_LINK(a,b,c,d) default_vfs_ops.link(b,c,d) +#define SMB_VFS_NEXT_MKNOD(a,b,c,d,e) default_vfs_ops.mknod(b,c,d,e) +#define SMB_VFS_NEXT_REALPATH(a,b,c,d) default_vfs_ops.realpath(b,c,d) +#define SMB_VFS_NEXT_SET_NT_ACL(a,b,c,d,e) default_vfs_ops.set_nt_acl(b,c,d,e) +#define SMB_VFS_NEXT_CHMOD_ACL(a,b,c,d) default_vfs_ops.chmod_acl(b,c,d) +#define SMB_VFS_NEXT_SYS_ACL_GET_FILE(a,b,c,d) default_vfs_ops.sys_acl_get_file(b,c,d) +#define SMB_VFS_NEXT_SYS_ACL_SET_FILE(a,b,c,d,e) default_vfs_ops.sys_acl_set_file(b,c,d,e) +#define SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(a,b,c) default_vfs_ops.sys_acl_delete_def_file(b,c) +/* ads functions */ + +#endif + +/* ------------------------- + * format + * .AppleDouble/filename/stream name + * + * return the *LAST* '/' in path + */ +static int ads_get_path_ptr(char *path) +{ + int i = 0; + int ptr = 0; + + for (i = 0; path[i]; i ++) { + if (path[i] == '/') + ptr = i; + } + + return ptr; +} + +/* ------------------------------ + * return the *FIRST* ':' in path +*/ +static int ads_get_stream_ptr(const char *path) +{ + int i = 0; + int ptr = 0; + + for (i = 0; path[i]; i ++) { + if (path[i] == ':') { + ptr = i; + break; + } + } + return ptr; +} + +/* ---------------- + * fname is only a filename +*/ + +static char *ads_canonical_dir(TALLOC_CTX *ctx, const char *path, const char *fname, int isdir) +{ + if (isdir) { + return talloc_asprintf(ctx, "%s/%s/%s/.Parent", path, fname, ADS_FOLDER); + } + return talloc_asprintf(ctx, "%s/%s/%s", path, ADS_FOLDER, fname); + +} + +/* ---------------- + * return directory pathname for an alternate data stream + * fname is *NOT* an altername name (ie foo:bar) +*/ +static char *ads_dir(TALLOC_CTX *ctx, const char *path, const char *fname, int isdir) +{ + int ptr0 = 0; + int ptr1 = 0; + char *temp; + +#if 0 + if (fname[0] == '.') ptr0 ++; + if (fname[1] == '/') ptr0 ++; +#endif + temp = talloc_asprintf(ctx, "%s/%s", path, &fname[ptr0]); + ptr1 = ads_get_path_ptr(temp); + temp[ptr1] = '\0'; + return ads_canonical_dir(ctx, temp, &temp[ptr1 + 1], isdir); +} + +/* ---------------------------------- + * build the pathname for stream, create folder if (mode & O_CREAT) + * return -1 on error + * 0 it's not a stream + * 1 it's a stream + * + * main_path : file fullpathname with :$DATA removed + * ads_path: unix pathname + * if it's not an ADS then main_path == ads_path + * + */ +static int ads_build_paths(TALLOC_CTX *ctx, const char *path, const char *fname, + char **ads_path, char **main_path, SMB_STRUCT_STAT **main_info, int flag) +{ + int ret = 0; + int ptr0 = 0; + int ptr1 = 0; + int ptr2 = 0; + int ptr3 = 0; + char *dname = 0; + char *name = 0; + SMB_STRUCT_STAT ads_info; + + if (!ctx || !path || !fname || !ads_path || !main_path || !main_info || !*main_info) + return -1; +#if 1 + DEBUG(3, ("ADS: PATH: %s[%s]\n", path, fname)); +#endif + if (strstr(path, ADS_FOLDER) || strstr(fname, ADS_FOLDER)) { + DEBUG(1, ("ADS: path %s[%s] already contains %s\n", path, fname, ADS_FOLDER)); + return -1; + } + +#if 0 + if (fname[0] == '.') ptr0 ++; + if (fname[1] == '/') ptr0 ++; +#endif + + *main_path = talloc_asprintf(ctx, "%s/%s", path, &fname[ptr0]); + *ads_path = NULL; + + /* get pointer to last '/' */ + ptr1 = ads_get_path_ptr(*main_path); + ptr2 = ads_get_stream_ptr(*main_path +ptr1 +1); + /* FIXME + * what about ::$DATA or :name:$DATA + */ + + if (ptr2) { + /* it's an alternate stream */ + ptr2 += ptr1 +1; + (*main_path)[ptr2] = 0; + ptr3 = ads_get_stream_ptr(*main_path +ptr2 +1); + if (ptr3) { + ptr3 += ptr2 +1; + /* check it's $DATA */ + if (!strcmp("$DATA", &(*main_path)[ptr3+1])) { + (*main_path)[ptr3] = 0; + } + } + + DEBUG(3, ("ADS: MAIN DATA %s\n", *main_path)); + + if (sys_lstat(*main_path, *main_info) < 0) { + /* if we can't get the main file give up */ + return -1; + } + (*main_path)[ptr2] = ':'; + dname = talloc_strdup(ctx, *main_path); + dname[ptr1] = '\0'; + name = *main_path; + name[ptr2] = '\0'; + if (S_ISDIR((*main_info)->st_mode)) { + *ads_path = talloc_asprintf(ctx, "%s/%s/%s/.Parent/%s", dname, &name[ptr1 + 1], ADS_FOLDER, &name[ptr2 + 1]); + } + else { + *ads_path = talloc_asprintf(ctx, "%s/%s/%s/%s", dname, ADS_FOLDER, &name[ptr1 + 1], &name[ptr2 + 1]); + } + /* XXX are we always the right user ?*/ + if (sys_lstat(*ads_path, &ads_info) < 0) { + int st_ret; + /* */ + if (errno == ENOENT && (flag & O_CREAT)) { + char *ads_base = ads_canonical_dir(ctx, dname, &name[ptr1 + 1], S_ISDIR((*main_info)->st_mode)); + mode_t mode; + + st_ret = mkdir(ads_base, 0777); + if (st_ret < 0) { + if (errno == ENOENT) { + char *ads_double; + if (S_ISDIR((*main_info)->st_mode)) { + ads_double = talloc_asprintf(ctx, "%s/%s/%s", dname, &name[ptr1 + 1], ADS_FOLDER); + } + else { + ads_double = talloc_asprintf(ctx, "%s/%s", dname, ADS_FOLDER); + } + if (mkdir(ads_double, 0777) < 0) + return -1; + if ((st_ret = mkdir(ads_base, 0777)) < 0) + return -1; + + /* we just created .AppleDouble/file/ update mode with dir search + * XXX what about acl? + */ + mode = (*main_info)->st_mode; + if ((mode & (S_IRUSR | S_IWUSR ))) + mode |= S_IXUSR; + if ((mode & (S_IRGRP | S_IWGRP ))) + mode |= S_IXGRP; + if ((mode & (S_IROTH | S_IWOTH ))) + mode |= S_IXOTH; + chmod(ads_base, mode); + } + else + errno = ENOENT; + } + } + else + return -1; + } + ret = 1; + } + else { + *ads_path = *main_path; + if (sys_lstat(*main_path, *main_info) < 0) { + *main_info = NULL; + } + } +#if 1 + DEBUG(3, ("ADS: DEBUG:[%s] [%s]\n", *main_path, *ads_path)); +#endif + return ret; +} + +/* ------------------------ */ +static SMB_BIG_UINT ads_disk_free(HANDLE_PARAMETER connection_struct *conn, const char *path, + BOOL small_query, SMB_BIG_UINT *bsize, + SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) +{ + return SMB_VFS_NEXT_DISK_FREE(handle, conn, path, small_query, bsize, dfree, dsize); +} + +static DIR *ads_opendir(HANDLE_PARAMETER connection_struct *conn, const char *fname) +{ + return SMB_VFS_NEXT_OPENDIR(handle, conn, fname); +} + +static struct dirent *ads_readdir(HANDLE_PARAMETER connection_struct *conn, DIR *dirp) +{ + struct dirent *result; + DEBUG(3,("ads: ads_readdir\n")); + result = SMB_VFS_NEXT_READDIR(handle, conn, dirp); + if (result) { + DEBUG(3,("ads: ads_readdir: %s\n", result->d_name)); + } + return result; +} + +/* ------------------------- */ +static int ads_mkdir(HANDLE_PARAMETER connection_struct *conn, const char *path, mode_t mode) +{ + return SMB_VFS_NEXT_MKDIR(handle, conn, path, mode); +} + +/* ------------------------- */ +static int unlink_file(const char *path) +{ +int ret = 0; + + become_root(); + ret = unlink(path); + unbecome_root(); + return ret; +} + +/* ------------------------- */ +static int unlink_folder(const char *path) +{ +int ret = 0; + + become_root(); + ret = rmdir(path); + unbecome_root(); + return ret; +} + +/* ------------------------- + remove all files in an AppleDouble folder +*/ +static void rrmdir(TALLOC_CTX *ctx, char *path) +{ + int n; + char *dpath; + struct dirent **namelist; + + if (!path) return; + + n = scandir(path, &namelist, 0, alphasort); + if (n < 0) { + return; + } + while (n --) { + if (strcmp(namelist[n]->d_name, ".") == 0 || strcmp(namelist[n]->d_name, "..") == 0) { + free(namelist[n]); + continue; + } + if ((dpath = talloc_asprintf(ctx, "%s/%s",path, namelist[n]->d_name))) { + unlink_file(dpath); + } + free(namelist[n]); + } + free(namelist); + unlink_folder(path); +} + +/* --------------------------- */ +static void rrm_adsdir(TALLOC_CTX *ctx, char *path) +{ + int n; + char *dpath; + struct dirent **namelist; + + if (!path) return; + + n = scandir(path, &namelist, 0, alphasort); + if (n < 0) { + return; + } + while (n --) { + if (strcmp(namelist[n]->d_name, ".") == 0 || strcmp(namelist[n]->d_name, "..") == 0) { + free(namelist[n]); + continue; + } + if ((dpath = talloc_asprintf(ctx, "%s/%s",path, namelist[n]->d_name))) { + rrmdir(ctx, dpath); + } + free(namelist[n]); + } + free(namelist); + unlink_folder(path); +} + +/* ------------------------- + * XXX + * if in smb.conf there's : + * delete veto files = True + * veto files = /.AppleD* / +*/ +static int ads_rmdir( HANDLE_PARAMETER connection_struct *conn, const char *path) +{ + BOOL add = False; + TALLOC_CTX *ctx = 0; + char *dpath; + int ret = 0; + + if (!conn || !conn->origpath || !path) goto exit_rmdir; + + /* .AppleD* */ + strstr(path, ADS_FOLDER) ? (add = False) : (add = True); + + if (!(ctx = ADS_TALLOC_INIT("ads_rmdir"))) + goto exit_rmdir; + + if (!(dpath = talloc_asprintf(ctx, "%s/%s%s",conn->origpath, path, add ? "/"ADS_FOLDER : ""))) + goto exit_rmdir; + + /* remove folder .AppleDouble */ + rrm_adsdir(ctx, dpath); + +exit_rmdir: + ret = SMB_VFS_NEXT_RMDIR(handle, conn, path); + talloc_destroy(ctx); + + return ret; +} + +/* ------------------------- */ +static int ads_open(HANDLE_PARAMETER connection_struct *conn, const char *fname, int flags, mode_t mode) +{ + int ret = 0; + char *ads_path = 0; + char *main_path = 0; + TALLOC_CTX *ctx; + SMB_STRUCT_STAT st; + SMB_STRUCT_STAT *main_info = &st; + + DEBUG(3,("ads: ads_open for %s %x\n", fname, flags)); + if (!(ctx = ADS_TALLOC_INIT("ads_open"))) + return -1; + /* convert to */ + if (ads_build_paths(ctx, conn->origpath, fname, &ads_path, &main_path, &main_info, flags) < 0) { + talloc_destroy(ctx); + return -1; + } + + ret = SMB_VFS_NEXT_OPEN(handle, conn, ads_path, flags, mode); + talloc_destroy(ctx); + return ret; + +} + +static int isDir(SMB_STRUCT_STAT *st) +{ + if (st == NULL) { + return 0; + } + return S_ISDIR(st->st_mode); +} + +/* ------------------------- */ +static int ads_rename(HANDLE_PARAMETER connection_struct *conn, const char *old, const char *new) +{ + int ret = 0; + TALLOC_CTX *ctx; + char *ads_path = 0; + char *main_path = 0; + SMB_STRUCT_STAT st; + SMB_STRUCT_STAT *main_info = &st; + + DEBUG(3,("ads: ads_rename %s --> %sx\n", old, new)); + + if (!(ctx = ADS_TALLOC_INIT("ads_rename"))) + return -1; + + if (ads_build_paths(ctx, conn->origpath, old, &ads_path, &main_path, &main_info, 0) < 0) { + talloc_destroy(ctx); + return -1; + } + + if (ads_path != main_path) { + /* you can't rename an ads ! */ + talloc_destroy(ctx); + errno = EINVAL; + return -1; + } + + ret = SMB_VFS_NEXT_RENAME(handle, conn, old, new); + if (!ret && !isDir(main_info)) { + int ptr1; + int ptr2; + + char *ads_old = ads_dir(ctx, conn->origpath, old, 0); + char *ads_new = ads_dir(ctx, conn->origpath, new, 0); + + /* is dest folder .Adouble there ? */ + ptr1 = ads_get_path_ptr(ads_new); + ptr2 = ads_get_path_ptr(ads_old); + + ads_new[ptr1] = '\0'; + ads_old[ptr2] = '\0'; + if (strcmp(ads_new, ads_old)) { + mkdir(ads_new, 0777); + } + + ads_new[ptr1] = '/'; + ads_old[ptr2] = '/'; + + SMB_VFS_NEXT_RENAME(handle, conn, ads_old, ads_new); + } + + talloc_destroy(ctx); + return ret; +} + +/* ------------------------- + * For an ADS what do we need to return , ADS ? main DATA? +*/ +static int ads_stat(HANDLE_PARAMETER connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sbuf) +{ + int ret = 0; + char *ads_path = 0; + char *main_path = 0; + TALLOC_CTX *ctx; + SMB_STRUCT_STAT st; + SMB_STRUCT_STAT *main_info = &st; + + DEBUG(3,("ads: ads_stat for %s\n", fname)); + + if (!(ctx = ADS_TALLOC_INIT("ads_stat"))) + return -1; + /* which inode ? + */ + if (ads_build_paths(ctx, conn->origpath, fname, &ads_path, &main_path, &main_info, 0) < 0) { + talloc_destroy(ctx); + return -1; + } + + ret = SMB_VFS_NEXT_STAT(handle, conn, ads_path, sbuf); + talloc_destroy(ctx); + return ret; +} + +/* ------------------------- */ +static int ads_lstat(HANDLE_PARAMETER connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf) +{ + int ret = 0; + char *ads_path = 0; + char *main_path = 0; + TALLOC_CTX *ctx; + SMB_STRUCT_STAT st; + SMB_STRUCT_STAT *main_info = &st; + + if (!(ctx = ADS_TALLOC_INIT("ads_lstat"))) + return -1; + /* which inode ? + */ + if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) { + talloc_destroy(ctx); + return -1; + } + + return SMB_VFS_NEXT_LSTAT(handle, conn, ads_path, sbuf); + talloc_destroy(ctx); + return ret; +} + +/* ------------------------- */ +static int ads_unlink(HANDLE_PARAMETER connection_struct *conn, const char *path) +{ + int ret = 0; + + char *ads_path = 0; + char *main_path = 0; + TALLOC_CTX *ctx; + SMB_STRUCT_STAT st; + SMB_STRUCT_STAT *main_info = &st; + + DEBUG(3,("ads: ads_unlink %s\n", path)); + if (!(ctx = ADS_TALLOC_INIT("ads_unlink"))) + return -1; + + if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) { + talloc_destroy(ctx); + return -1; + } + + ret = SMB_VFS_NEXT_UNLINK(handle, conn, ads_path); + /* + if data stream + for each stream + unlink + */ + if (!ret && ads_path == main_path) { + char *ads_base = ads_dir(ctx, conn->origpath, path, isDir(main_info)); + struct dirent *dent = 0; + DIR *dir = opendir(ads_base); + + if (dir) { + char *dpath; + + while (NULL != (dent = readdir(dir))) { + if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) + continue; + if (!(dpath = talloc_asprintf(ctx, "%s/%s", ads_base, dent->d_name))) + continue; + /* XXX need to be root ? */ + SMB_VFS_NEXT_UNLINK(handle, conn, dpath); + } + closedir(dir); + rmdir(ads_base); + } + } + + talloc_destroy(ctx); + return ret; +} + +/* ------------------------- */ +static int ads_chmod(HANDLE_PARAMETER connection_struct *conn, const char *path, mode_t mode) +{ + int ret = 0; + char *ads_path = 0; + char *main_path = 0; + TALLOC_CTX *ctx; + SMB_STRUCT_STAT st; + SMB_STRUCT_STAT *main_info = &st; + + DEBUG(3,("ads: ads_chmod %s\n", path)); + /* if stream + error ?, change only the stream + */ + if (!(ctx = ADS_TALLOC_INIT("ads_chmod"))) + return -1; + + if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) { + talloc_destroy(ctx); + return -1; + } + + ret = SMB_VFS_NEXT_CHMOD(handle, conn, ads_path, mode); + /* + if data stream + for each stream + chmod + */ + if (!ret && ads_path == main_path) { + char *ads_base = ads_dir(ctx, conn->origpath, path, isDir(main_info)); + struct dirent *dent = 0; + DIR *dir = opendir(ads_base); + + if (dir) { + char *dpath; + + while (NULL != (dent = readdir(dir))) { + if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) + continue; + if (!(dpath = talloc_asprintf(ctx, "%s/%s", ads_base, dent->d_name))) + continue; + /* XXX need to be root ? */ + SMB_VFS_NEXT_CHMOD(handle, conn, dpath, mode); + } + closedir(dir); + /* XXX need to change ads_base too*/ + } + } + + talloc_destroy(ctx); + return ret; +} + +/* ------------------------- */ +static int ads_chown(HANDLE_PARAMETER connection_struct *conn, const char *path, uid_t uid, gid_t gid) +{ + int ret = 0; + char *ads_path = 0; + char *main_path = 0; + TALLOC_CTX *ctx; + SMB_STRUCT_STAT st; + SMB_STRUCT_STAT *main_info = &st; + + DEBUG(3,("ads: ads_chown %s\n", path)); + /* if stream + error ?, change only the stream + */ + if (!(ctx = ADS_TALLOC_INIT("ads_chown"))) + return -1; + + if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) { + talloc_destroy(ctx); + return -1; + } + + ret = SMB_VFS_NEXT_CHOWN(handle, conn, ads_path, uid, gid); + /* if data stream + for each stream + chmod + */ + if (!ret && ads_path == main_path) { + char *ads_base = ads_dir(ctx, conn->origpath, path, isDir(main_info)); + struct dirent *dent = 0; + DIR *dir = opendir(ads_base); + + if (dir) { + char *dpath; + + while (NULL != (dent = readdir(dir))) { + if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) + continue; + if (!(dpath = talloc_asprintf(ctx, "%s/%s", ads_base, dent->d_name))) + continue; + /* XXX need to be root ?, what do we do in case of error? */ + SMB_VFS_NEXT_CHOWN(handle, conn, dpath, uid, gid); + } + closedir(dir); + SMB_VFS_NEXT_CHOWN(handle, conn, ads_path, uid, gid); + } + } + + talloc_destroy(ctx); + return ret; +} + +/* ------------------------- */ +static int ads_chdir(HANDLE_PARAMETER connection_struct *conn, const char *path) +{ + DEBUG(3,("ads: ads_chdir for %s\n", path)); + return SMB_VFS_NEXT_CHDIR(handle, conn, path); +} + +static int ads_utime(HANDLE_PARAMETER connection_struct *conn, const char *path, struct utimbuf *times) +{ + return SMB_VFS_NEXT_UTIME(handle, conn, path, times); +} + + +static BOOL ads_symlink(HANDLE_PARAMETER connection_struct *conn, const char *oldpath, const char *newpath) +{ + return SMB_VFS_NEXT_SYMLINK(handle, conn, oldpath, newpath); +} + +static BOOL ads_readlink(HANDLE_PARAMETER connection_struct *conn, const char *path, char *buf, size_t bufsiz) +{ + return SMB_VFS_NEXT_READLINK(handle, conn, path, buf, bufsiz); +} + +static int ads_link( HANDLE_PARAMETER connection_struct *conn, const char *oldpath, const char *newpath) +{ + return SMB_VFS_NEXT_LINK(handle, conn, oldpath, newpath); +} + +static int ads_mknod(HANDLE_PARAMETER connection_struct *conn, const char *path, mode_t mode, SMB_DEV_T dev) +{ + return SMB_VFS_NEXT_MKNOD(handle, conn, path, mode, dev); +} + +static char *ads_realpath(HANDLE_PARAMETER connection_struct *conn, const char *path, char *resolved_path) +{ + return SMB_VFS_NEXT_REALPATH(handle, conn, path, resolved_path); +} + +static BOOL ads_set_nt_acl(HANDLE_PARAMETER files_struct *fsp, const char *name, uint32 security_info_sent, struct security_descriptor_info *psd) +{ + return SMB_VFS_NEXT_SET_NT_ACL(handle, fsp, name, security_info_sent, psd); +} + +static int ads_chmod_acl(HANDLE_PARAMETER connection_struct *conn, const char *name, mode_t mode) +{ + /* If the underlying VFS doesn't have ACL support... */ +#ifdef ADS_NEW_MODULE + if (!handle->vfs_next.ops.chmod_acl) { +#else + if (!default_vfs_ops.chmod_acl) { +#endif + errno = ENOSYS; + return -1; + } + return SMB_VFS_NEXT_CHMOD_ACL(handle, conn, name, mode); +} + +static SMB_ACL_T ads_sys_acl_get_file(HANDLE_PARAMETER connection_struct *conn, const char *path_p, SMB_ACL_TYPE_T type) +{ + return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, conn, path_p, type); +} + +static int ads_sys_acl_set_file(HANDLE_PARAMETER connection_struct *conn, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) +{ + return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, conn, name, acltype, theacl); +} + +static int ads_sys_acl_delete_def_file(HANDLE_PARAMETER connection_struct *conn, const char *path) +{ + return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, conn, path); +} + +#ifdef ADS_NEW_MODULE +static ssize_t ads_getxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, void *value, size_t size) +{ + return SMB_VFS_NEXT_GETXATTR(handle, conn, path, name, value, size); +} + +static ssize_t ads_lgetxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, void *value, size_t +size) +{ + return SMB_VFS_NEXT_LGETXATTR(handle, conn, path, name, value, size); +} + +static ssize_t ads_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, void *value, size_t size) +{ + return SMB_VFS_NEXT_FGETXATTR(handle, fsp, fd, name, value, size); +} + +static ssize_t ads_listxattr(vfs_handle_struct *handle, connection_struct *conn,const char *path, char *list, size_t size) +{ + return SMB_VFS_NEXT_LISTXATTR(handle, conn, path, list, size); +} + +static ssize_t ads_llistxattr(vfs_handle_struct *handle,struct connection_struct *conn,const char *path, char *list, size_t size) +{ + return SMB_VFS_NEXT_LLISTXATTR(handle, conn, path, list, size); +} + +static int ads_removexattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name) +{ + return SMB_VFS_NEXT_REMOVEXATTR(handle, conn, path, name); +} + +static int ads_lremovexattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name) +{ + return SMB_VFS_NEXT_LREMOVEXATTR(handle, conn, path, name); +} + +static int ads_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name) +{ + return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, fd, name); +} + +static int ads_setxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags) +{ + return SMB_VFS_NEXT_SETXATTR(handle, conn, path, name, value, size, flags); +} + +static int ads_lsetxattr(vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags) +{ + return SMB_VFS_NEXT_LSETXATTR(handle, conn, path, name, value, size, flags); +} + +static int ads_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, const void *value, size_t size, int flags) +{ + return SMB_VFS_NEXT_FSETXATTR(handle, fsp, fd, name, value, size, flags); +} + +#endif + +/* ---------------------------------- + * enumerate +*/ +static ssize_t ads_listads(HANDLE_PARAMETER struct connection_struct *conn,const char *path, char *list, size_t size) +{ + char *ads_path = 0; + char *main_path = 0; + TALLOC_CTX *ctx; + size_t len, total = 0; + SMB_STRUCT_STAT st; + SMB_STRUCT_STAT *main_info = &st; + + + if (!list || !path) { + /* aka we have ads functionnality */ + return 0; + } + + DEBUG(3,("ads: ads_listads %s\n", path)); + + if (!(ctx = ADS_TALLOC_INIT("ads_listads"))) + return -1; + + if (ads_build_paths(ctx, conn->origpath, path, &ads_path, &main_path, &main_info, 0) < 0) { + talloc_destroy(ctx); + return -1; + } + + /* + if data stream + for each stream + */ + if (ads_path == main_path) { + char *ads_base = ads_dir(ctx, conn->origpath, path, isDir(main_info)); + struct dirent *dent = 0; + DIR *dir = opendir(ads_base); + + /* XXX need to be root ? */ + if (dir) { + + while (NULL != (dent = readdir(dir))) { + if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) + continue; + len = strlen(dent->d_name) +8 ; + total += len; + if (total >= size) { + talloc_destroy(ctx); + errno = ERANGE; + return -1; + } + snprintf (list, len, ":%s:$DATA", dent->d_name); + list += len; + } + closedir(dir); + } + } + + talloc_destroy(ctx); + return total; +} + +/* ------------------------------------ + * VFS operations structure */ + +#ifndef SMB_VFS_OP +#define SMB_VFS_OP(x) ((void *) x) +#endif + +static vfs_op_tuple ads_op_tuples[] = { + + /* Disk operations */ + + {SMB_VFS_OP(ads_disk_free), SMB_VFS_OP_DISK_FREE, SMB_VFS_LAYER_TRANSPARENT}, + + /* Directory operations */ + + {SMB_VFS_OP(ads_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_readdir), SMB_VFS_OP_READDIR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_mkdir), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT}, + + /* File operations */ + + {SMB_VFS_OP(ads_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_stat), SMB_VFS_OP_STAT, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_lstat), SMB_VFS_OP_LSTAT, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_chown), SMB_VFS_OP_CHOWN, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_chdir), SMB_VFS_OP_CHDIR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_utime), SMB_VFS_OP_UTIME, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_readlink), SMB_VFS_OP_READLINK, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_link), SMB_VFS_OP_LINK, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_mknod), SMB_VFS_OP_MKNOD, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_realpath), SMB_VFS_OP_REALPATH, SMB_VFS_LAYER_TRANSPARENT}, + + /* NT File ACL operations */ + + {SMB_VFS_OP(ads_set_nt_acl), SMB_VFS_OP_SET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT}, + + /* POSIX ACL operations */ + + {SMB_VFS_OP(ads_chmod_acl), SMB_VFS_OP_CHMOD_ACL, SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(ads_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_sys_acl_delete_def_file), SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, SMB_VFS_LAYER_TRANSPARENT}, +#ifdef ADS_NEW_MODULE + /* EA operations. */ + {SMB_VFS_OP(ads_getxattr), SMB_VFS_OP_GETXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_lgetxattr), SMB_VFS_OP_LGETXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_fgetxattr), SMB_VFS_OP_FGETXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_listxattr), SMB_VFS_OP_LISTXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_llistxattr), SMB_VFS_OP_LLISTXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_removexattr), SMB_VFS_OP_REMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_lremovexattr), SMB_VFS_OP_LREMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_fremovexattr), SMB_VFS_OP_FREMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_setxattr), SMB_VFS_OP_SETXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_lsetxattr), SMB_VFS_OP_LSETXATTR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(ads_fsetxattr), SMB_VFS_OP_FSETXATTR, SMB_VFS_LAYER_TRANSPARENT}, +#endif + /* ADS operations */ + {SMB_VFS_OP(ads_listads), SMB_VFS_OP_LISTADS, SMB_VFS_LAYER_TRANSPARENT}, + + {NULL, SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} +}; + +#ifdef ADS_NEW_MODULE + +#if 0 +NTSTATUS vfs_ads_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "ads", ads_op_tuples); +} +#endif + +NTSTATUS vfs_ads_init(void) +{ + DEBUG(3, ("ADS: vfs_ads_init\n")); + return NT_STATUS_OK; +} + + +NTSTATUS init_module(void) +{ + DEBUG(3, ("ADS: init_module\n" )); + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "ads", ads_op_tuples); +} + +#else +/* VFS initialisation function. Return vfs_op_tuple array back to SAMBA. */ +vfs_op_tuple *vfs_init(int *vfs_version, struct vfs_ops *def_vfs_ops,struct smb_vfs_handle_struct *vfs_handle) +{ + *vfs_version = SMB_VFS_INTERFACE_VERSION; + memcpy(&default_vfs_ops, def_vfs_ops, sizeof(struct vfs_ops)); + + ads_handle = vfs_handle; + DEBUG(3, ("ADS: vfs module loaded\n")); + return ads_op_tuples; +} + +/* VFS finalization function. */ +void vfs_done(connection_struct *conn) +{ + DEBUG(3, ("ADS: vfs module unloaded\n")); +} + +#endif