Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

VFS recycle bin

0 views
Skip to first unread message

Juergen Hasch

unread,
Feb 25, 2002, 4:56:23 PM2/25/02
to

--------------Boundary-00=_J2Z3IB0YGV84MKN3OFDU
Content-Type: text/plain;
charset="iso-8859-15"
Content-Transfer-Encoding: 8bit

Hi,

I converted Brandon Stone's recycle bin patch into a VFS module.
It seems to work, but it's not perfect. Don't use it on
production machines :-)

The recycle bin can be configured with the file /etc/samba/recycle_bin.conf:
[ recycle bin ]
name = .recycle
maxsize = 100000
exclude = .tmp.temp.o
excludedir = /tmp/temp/

It's hardcoded for now because vfs_option doesn't seem to be implemented.
You can set the name of the trashcan, the maximum file size being saved,
filename extensions and directories which shouldn't be saved.
In my case all *.tmp, *.temp and *.o files will get deleted directly.
Also files in /tmp and /temp get deleted directly.

I have a question to the VFS experts. When I try to use
the function default_vfs_ops.stat() smbd crashes, so I am
using stat() directly. Why is this, especially because I have a
simpler version of the recycle bin where it works ?

Also, can I use pm_process() to read my configuration file
(I do it right now) or is this "out of spec" ?

...Juergen

--------------Boundary-00=_J2Z3IB0YGV84MKN3OFDU
Content-Type: text/x-csrc;
charset="iso-8859-15";
name="recycle_bin.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="recycle_bin.c"

/*
* Recycle bin VFS module for samba.
*
* Copyright (C) Juergen Hasch, 2002
* Based on Recycle Bin patch from Brandon Stone
* and VFS example module by Tim Potter
*
* 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>

#ifndef SYSLOG_FACILITY
#define SYSLOG_FACILITY LOG_USER
#endif

#ifndef SYSLOG_PRIORITY
#define SYSLOG_PRIORITY LOG_NOTICE
#endif

#ifndef PARAMCONF
#define PARAMCONF "/etc/samba/recycle_bin.conf"
#endif

static int in_section=0;

fstring conf_file; // configuration file name
fstring recycle_bin; // name of the recycle bin directory
fstring mode; // not implemented...
fstring exclude; // which files to exclude
fstring exclude_dir; // which directories to exclude
SMB_BIG_UINT max_size; // maximum file size to be saved

static struct vfs_ops default_vfs_ops;

static BOOL do_parameter(char *pszParmName, char *pszParmValue)
{
if (!in_section)
return True;

if (StrCaseCmp("name",pszParmName)==0) {
fstrcpy(recycle_bin,pszParmValue);
} else if (StrCaseCmp("mode",pszParmName)==0) {
fstrcpy(mode,pszParmValue);
} else if (StrCaseCmp("maxsize",pszParmName)==0) {
max_size = strtoul(pszParmValue,NULL,10);
} else if (StrCaseCmp("exclude",pszParmName)==0) {
fstrcpy(exclude,pszParmValue);
} else if (StrCaseCmp("excludedir",pszParmName)==0) {
fstrcpy(exclude_dir,pszParmValue);
}
return True;
}

static BOOL do_section(char *pszSectionName)
{
if (StrCaseCmp("recycle bin",pszSectionName)==0)
in_section = 1;
else
in_section = 0;

return True;
}

/*******************************************************************
Check if a file exists
********************************************************************/
BOOL local_file_exist(connection_struct *conn, const char *fname)
{
pstring fullname;
struct stat stat_buf;

pstrcpy(fullname,conn->origpath);
pstrcat(fullname, "/");
pstrcat(fullname, fname);

if (stat(fullname,&stat_buf) == -1)
return False;
return(S_ISREG(stat_buf.st_mode));

}

/*******************************************************************
Check if a directory exists.
********************************************************************/
BOOL local_directory_exist(connection_struct *conn,char *dname)
{
return vfs_directory_exist(conn,dname,NULL);
}

/*******************************************************************
returns the size in bytes of the named file
********************************************************************/
SMB_OFF_T local_get_file_size(connection_struct *conn,const char *file_name)
{
pstring fullname;
struct stat stat_buf;

pstrcpy(fullname,conn->origpath);
pstrcat(fullname, "/");
pstrcat(fullname, file_name);

stat_buf.st_size = 0;

if(stat(fullname,&stat_buf) == -1)
return (SMB_OFF_T)-1;
return(stat_buf.st_size);
}

/********************************************************************
check if file should be recycled
*********************************************************************/
static int recycle(connection_struct *conn, const char *fname)
{
char *base, *ext, *path;
pstring bin;
pstring fpath;
int i=1, len, addlen;
int dir_mask=0700;
SMB_OFF_T fsize;

SMB_BIG_UINT dfree,dsize,bsize;

if(!recycle_bin || !*recycle_bin) {
syslog(SYSLOG_PRIORITY, "share parameter not set, purging %s...\n", fname);
return default_vfs_ops.unlink(conn,fname);
}

fsize = local_get_file_size(conn,fname);

if(fsize == 0) {
syslog(SYSLOG_PRIORITY, "file %s is empty, purging...\n", fname);
return default_vfs_ops.unlink(conn,fname);
}

if(fsize > max_size) {
syslog(SYSLOG_PRIORITY, "file %s exceeds maximum recycle size \n",fname);
return default_vfs_ops.unlink(conn,fname);
}

base = strrchr(fname, '/') + 1;
pstrcpy(fpath,"/");
pstrcat(fpath,fname);
path = strrchr(fpath+1, '/') + 1 ;
*path='\0';

if(base == (char*)1) base = (char *)fname;

ext = strrchr(base, '.');
pstrcpy(bin, recycle_bin);
pstrcat(bin, "/");
pstrcat(bin, base);

/* check for exclude argument */
if (ext && strlen(ext) &&strlen(exclude) && strstr(exclude,ext)) {
syslog(SYSLOG_PRIORITY, "extension %s is excluded \n",ext);
return default_vfs_ops.unlink(conn,fname);
}

if (strlen(fpath) && strlen(exclude_dir) && strstr(exclude_dir,fpath)) {
syslog(SYSLOG_PRIORITY, "directory %s is excluded \n",fpath);
return default_vfs_ops.unlink(conn,fname);
}

if(strcmp(fname,bin) == 0) {
syslog(SYSLOG_PRIORITY, "file %s exists, purging...\n", fname);
return default_vfs_ops.unlink(conn,fname);
}

len = strlen(bin);
addlen = sizeof(pstring)-len-1;
while(local_file_exist(conn,bin)) {
slprintf(bin+len, addlen, " (Copy #%d)", i++);
pstrcat(bin, ext);
}

syslog(SYSLOG_PRIORITY, "moving source=%s to dest=%s\n", fname, bin);

default_vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize);

if((unsigned int)dfree > 0) {
syslog(SYSLOG_PRIORITY, "mdiskfree=%d\n",(int)dfree);

if(!local_directory_exist(conn,recycle_bin)) {
syslog(SYSLOG_PRIORITY, "directory %s nonexistant, creating...\n", recycle_bin);
default_vfs_ops.mkdir(conn,recycle_bin,dir_mask);
}
syslog(SYSLOG_PRIORITY, "move successful\n");
return default_vfs_ops.rename(conn, fname, bin);
} else {
syslog(SYSLOG_PRIORITY, "move failed, purging...\n");
return default_vfs_ops.unlink(conn,fname);
}
}

static int local_rmdir(struct connection_struct *conn, const char *path)
{
int result = default_vfs_ops.rmdir(conn, path);

syslog(SYSLOG_PRIORITY, "rmdir %s %s%s\n",
path,
(result < 0) ? "failed: " : "",
(result < 0) ? strerror(errno) : "");

return result;
}


static int recycle_connect(struct connection_struct *conn, const char *service, const char *user)
{
BOOL rc;

syslog(SYSLOG_PRIORITY, "connect\n");
// TODO: get conf file path from vfs options
fstrcpy(conf_file,PARAMCONF); // vfs options is not working right now, hardcode path for now

syslog(SYSLOG_PRIORITY, "using configuration file %s\n", conf_file);
// set defaults
fstrcpy(recycle_bin,".recycle"); // location of recycle bin
max_size = 99999999L; // TODO: use a sane value here
// load parameters
rc=pm_process( conf_file, do_section, do_parameter);

return (default_vfs_ops.connect(conn, service,user));
}

static void recycle_disconnect(struct connection_struct *conn)
{
syslog(SYSLOG_PRIORITY, "disconnect\n");
default_vfs_ops.disconnect(conn);
}

/* VFS initialisation function. Return initialised vfs_ops structure
back to SAMBA. */
struct vfs_ops *vfs_init(int *vfs_version, struct vfs_ops *ops)
{
*vfs_version = SMB_VFS_INTERFACE_VERSION;

openlog("smbd_recycle_bin", LOG_PID, SYSLOG_FACILITY);
syslog(SYSLOG_PRIORITY, "initialised\n");

/* Save a copy of the default ops */
default_vfs_ops = *ops;

/* Override our ones */
ops->connect = recycle_connect;
ops->disconnect = recycle_disconnect;
ops->rmdir = local_rmdir;
ops->unlink = recycle;

return(ops);
}

--------------Boundary-00=_J2Z3IB0YGV84MKN3OFDU--


0 new messages