summaryrefslogtreecommitdiffstats
path: root/examples/VFS/recycle.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/VFS/recycle.c')
-rw-r--r--examples/VFS/recycle.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/examples/VFS/recycle.c b/examples/VFS/recycle.c
new file mode 100644
index 00000000000..ed89e59abf3
--- /dev/null
+++ b/examples/VFS/recycle.c
@@ -0,0 +1,222 @@
+/*
+ * Auditing VFS module for samba. Log selected file operations to syslog
+ * facility.
+ *
+ * Copyright (C) 2001, Brandon Stone, Amherst College, <bbstone@amherst.edu>.
+ * Copyright (C) 2002, Jeremy Allison - modified to make a VFS module.
+ * Copyright (C) 2002, Alexander Bokovoy - cascaded VFS adoption,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#include <syslog.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <errno.h>
+#include <string.h>
+#include <includes.h>
+#include <vfs.h>
+
+/* VFS operations */
+
+static struct vfs_ops default_vfs_ops; /* For passthrough operation */
+static struct smb_vfs_handle_struct *recycle_handle;
+static int recycle_unlink(connection_struct *, const char *);
+static int recycle_connect(struct connection_struct *conn, const char *service, const char *user);
+static void recycle_disconnect(struct connection_struct *conn);
+
+static vfs_op_tuple recycle_ops[] = {
+
+ /* Disk operations */
+
+ {recycle_connect, SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_OPAQUE},
+ {recycle_disconnect, SMB_VFS_OP_DISCONNECT, SMB_VFS_LAYER_OPAQUE},
+
+ /* File operations */
+
+ {recycle_unlink, SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_OPAQUE},
+
+ {NULL, SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+/* VFS initialisation function. Return initialised 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));
+
+ /* Remember vfs_id for storing private information at connect */
+ recycle_handle = vfs_handle;
+
+ return recycle_ops;
+}
+
+/* VFS finalization function. */
+void vfs_done(connection_struct *conn)
+{
+ DEBUG(3,("vfs_done_recycle: called for connection %p\n",conn));
+}
+
+static int recycle_connect(struct connection_struct *conn, const char *service, const char *user)
+{
+ fstring recycle_bin;
+
+ DEBUG(3,("recycle_connect: called for service %s as user %s\n", service, user));
+
+ fstrcpy(recycle_bin, (const char *)lp_parm_string(lp_servicename(SNUM(conn)),"vfs","recycle bin"));
+ if (!*recycle_bin) {
+ DEBUG(3,("recycle_connect: No options listed (vfs:recycle bin).\n" ));
+ return 0; /* No options. */
+ }
+
+ DEBUG(3,("recycle_connect: recycle name is %s\n", recycle_bin ));
+
+ recycle_handle->data = (void *)strdup(recycle_bin);
+ return 0;
+}
+
+static void recycle_disconnect(struct connection_struct *conn)
+{
+ SAFE_FREE(recycle_handle->data);
+}
+
+static BOOL recycle_XXX_exist(connection_struct *conn, const char *dname, BOOL isdir)
+{
+ SMB_STRUCT_STAT st;
+
+ if (default_vfs_ops.stat(conn,dname,&st) != 0)
+ return(False);
+
+ if (isdir)
+ return S_ISDIR(st.st_mode) ? True : False;
+ else
+ return S_ISREG(st.st_mode) ? True : False;
+}
+
+static BOOL recycle_directory_exist(connection_struct *conn, const char *dname)
+{
+ return recycle_XXX_exist(conn, dname, True);
+}
+
+static BOOL recycle_file_exist(connection_struct *conn, const char *fname)
+{
+ return recycle_XXX_exist(conn, fname, False);
+}
+
+static SMB_OFF_T recycle_get_file_size(connection_struct *conn, const char *fname)
+{
+ SMB_STRUCT_STAT st;
+
+ if (default_vfs_ops.stat(conn,fname,&st) != 0)
+ return (SMB_OFF_T)-1;
+
+ return(st.st_size);
+}
+
+/********************************************************************
+ Check if file should be recycled
+*********************************************************************/
+
+static int recycle_unlink(connection_struct *conn, const char *inname)
+{
+ fstring recycle_bin;
+ pstring fname;
+ char *base, *ext;
+ pstring bin;
+ int i=1, len, addlen;
+ int dir_mask=0770;
+ SMB_BIG_UINT dfree,dsize,bsize;
+
+ *recycle_bin = '\0';
+ pstrcpy(fname, inname);
+
+ if (recycle_handle->data)
+ fstrcpy(recycle_bin, (const char *)recycle_handle->data);
+
+ if(!*recycle_bin) {
+ DEBUG(3, ("recycle bin: share parameter not set, purging %s...\n", fname));
+ return default_vfs_ops.unlink(conn,fname);
+ }
+
+ if(recycle_get_file_size(conn, fname) == 0) {
+ DEBUG(3, ("recycle bin: file %s is empty, purging...\n", fname));
+ return default_vfs_ops.unlink(conn,fname);
+ }
+
+ base = strrchr(fname, '/');
+ pstrcpy(bin, recycle_bin);
+ pstrcat(bin, "/");
+
+ if(base == NULL) {
+ ext = strrchr(fname, '.');
+ pstrcat(bin, fname);
+ } else {
+ ext = strrchr(base, '.');
+ pstrcat(bin, base+1);
+ }
+ DEBUG(3, ("recycle bin: base %s, ext %s, fname %s, bin %s\n", base, ext, fname, bin));
+
+ if(strcmp(fname,bin) == 0) {
+ DEBUG(3, ("recycle bin: file %s exists, purging...\n", fname));
+ return default_vfs_ops.unlink(conn,fname);
+ }
+
+ len = strlen(bin);
+ if ( ext != NULL)
+ len = len - strlen(ext);
+
+ addlen = sizeof(pstring)-len-1;
+ while(recycle_file_exist(conn,bin)) {
+ slprintf(bin+len, addlen, " (Copy #%d)", i++);
+ pstrcat(bin, ext);
+ }
+
+ DEBUG(3, ("recycle bin: moving source=%s to dest=%s\n", fname, bin));
+ default_vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize);
+ if((unsigned int)dfree > 0) {
+ int ret;
+ if(!recycle_directory_exist(conn,recycle_bin)) {
+ DEBUG(3, ("recycle bin: directory %s nonexistant, creating...\n", recycle_bin));
+ if (default_vfs_ops.mkdir(conn,recycle_bin,dir_mask) == -1) {
+ DEBUG(3, ("recycle bin: unable to create directory %s. Error was %s\n",
+ recycle_bin, strerror(errno) ));
+ }
+ }
+ DEBUG(3, ("recycle bin: move %s -> %s\n", fname, bin));
+
+ ret = default_vfs_ops.rename(conn, fname, bin);
+ if (ret == -1) {
+ DEBUG(3, ("recycle bin: move error %d (%s)\n", errno, strerror(errno) ));
+ DEBUG(3, ("recycle bin: move failed, purging...\n"));
+ return default_vfs_ops.unlink(conn,fname);
+ }
+ return ret;
+ } else {
+ DEBUG(3, ("recycle bin: move failed, purging...\n"));
+ return default_vfs_ops.unlink(conn,fname);
+ }
+}