[PATCH] vfs_recycle: printf-style templates + more
Peter Stamfest
peter at stamfest.at
Sun Jan 29 07:41:24 GMT 2006
Hello,
On Sat, 28 Jan 2006, Gerald (Jerry) Carter wrote:
> Peter Stamford's wrote:
^^^^^^^^
How has that happened?
>> Here is a patch that adds some features to the vfs_recycle module I
>> wanted for a long time (I'm using a similar patch since 3.0.10):
>
> Thanks Peter. Could you please resend it as an attachment so
> that the diff isn't munged?
Interesting, that shouldn't have happened. Gotta check my pine config.
Sorry for that noise.
Find it attached.
peter
-------------- next part --------------
diff -ur org/samba-3.0.21a/source/configure.in samba-3.0.21a/source/configure.in
--- org/samba-3.0.21a/source/configure.in Wed Dec 14 13:45:51 2005
+++ samba-3.0.21a/source/configure.in Sat Jan 28 08:12:25 2006
@@ -746,6 +746,7 @@
AC_CHECK_HEADERS(sys/sysmacros.h security/_pam_macros.h dlfcn.h)
AC_CHECK_HEADERS(sys/syslog.h syslog.h execinfo.h)
AC_CHECK_HEADERS(langinfo.h locale.h)
+AC_CHECK_HEADERS(printf.h)
AC_CHECK_HEADERS(rpcsvc/yp_prot.h,,,[[
#if HAVE_RPC_RPC_H
@@ -1959,6 +1960,29 @@
fi
# end utmp details
+AC_CACHE_CHECK([for reorderable format specifiers],samba_cv_have_reorderable_format,[
+AC_TRY_RUN([
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+int
+main ()
+{
+ char c[80] = "";
+ sprintf(c, "%2\$d %1\$s", "1", 2);
+ return strcmp(c, "2 1") == 0 ? 0 : 1;
+}
+],
+samba_cv_have_reorderable_format=yes,samba_cv_have_reorderable_format=no,samba_cv_have_reorderable_format=cross)
+])
+
+if test x"$samba_cv_have_reorderable_format" = x"yes"; then
+ AC_DEFINE(HAVE_REORDERABLE_FORMAT,1,[Whether the host libc supports reorderable format specifiers])
+fi
+
+AC_CHECK_FUNCS(parse_printf_format)
ICONV_LOCATION=standard
LOOK_DIRS="/usr /usr/local /sw /opt"
diff -ur org/samba-3.0.21a/source/modules/vfs_recycle.c samba-3.0.21a/source/modules/vfs_recycle.c
--- org/samba-3.0.21a/source/modules/vfs_recycle.c Tue Dec 20 16:28:38 2005
+++ samba-3.0.21a/source/modules/vfs_recycle.c Sat Jan 28 16:23:41 2006
@@ -7,6 +7,8 @@
* Copyright (C) 2002, Juergen Hasch - added some options.
* Copyright (C) 2002, Simo Sorce
* Copyright (C) 2002, Stefan (metze) Metzmacher
+ * Copyright (C) 2005-2006, Peter Stamfest - added template support and
+ * per-directory recycle bins
*
* 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
@@ -24,6 +26,11 @@
*/
#include "includes.h"
+#ifdef HAVE_PARSE_PRINTF_FORMAT
+#ifdef HAVE_PRINTF_H
+#include "printf.h"
+#endif
+#endif
#define ALLOC_CHECK(ptr, label) do { if ((ptr) == NULL) { DEBUG(0, ("recycle.bin: out of memory!\n")); errno = ENOMEM; goto label; } } while(0)
@@ -32,6 +39,13 @@
#undef DBGC_CLASS
#define DBGC_CLASS vfs_recycle_debug_level
+/* PSt: This is actually redundant - keep it as an example */
+#ifdef HAVE_REORDERABLE_FORMAT
+#define DEFAULT_TEMPLATE "Copy #%1$d of %2$s%3$s%4$s"
+#else
+#define DEFAULT_TEMPLATE "Copy #%d of %s%s%s"
+#endif
+
static int recycle_connect(vfs_handle_struct *handle, connection_struct *conn, const char *service, const char *user);
static void recycle_disconnect(vfs_handle_struct *handle, connection_struct *conn);
static int recycle_unlink(vfs_handle_struct *handle, connection_struct *conn, const char *name);
@@ -76,6 +90,57 @@
return tmp_str;
}
+
+static const char *recycle_template(vfs_handle_struct *handle)
+{
+ const char *template_str = NULL;
+ size_t r;
+ int argtypes[6]; /* at least one more than the number of
+ format specifiers we support */
+
+ template_str = lp_parm_const_string(SNUM(handle->conn), "recycle", "template", DEFAULT_TEMPLATE);
+
+ DEBUG(0, ("recycle: template = %s\n", template_str));
+
+#ifdef HAVE_PARSE_PRINTF_FORMAT
+ r = parse_printf_format(template_str, sizeof(argtypes) / sizeof(argtypes[0]),
+ argtypes);
+ if ((r > 0 && argtypes[0] != PA_INT) ||
+ (r > 1 && argtypes[1] != PA_STRING) ||
+ (r > 2 && argtypes[2] != PA_STRING) ||
+ (r > 3 && argtypes[3] != PA_STRING) ||
+ (r > 4)) {
+ DEBUG(0, ("recycle: invalid template (more than 4 arguments or wrong argument types in printf-style format string '%s' - using default '%s')\n",
+ template_str, DEFAULT_TEMPLATE));
+ return DEFAULT_TEMPLATE;
+ }
+#endif
+
+ return template_str;
+}
+
+static BOOL recycle_in_tree(vfs_handle_struct *handle)
+{
+ BOOL ret;
+
+ ret = lp_parm_bool(SNUM(handle->conn), "recycle", "intree", False);
+
+ DEBUG(10, ("recycle_bin: intree = %s\n", ret?"True":"False"));
+
+ return ret;
+}
+
+static int recycle_maxiter(vfs_handle_struct *handle)
+{
+ int maxiter;
+
+ maxiter = lp_parm_int(SNUM(handle->conn), "recycle", "maxiter", 0);
+
+ DEBUG(10, ("recycle: maxiter = %d\n", maxiter));
+
+ return maxiter;
+}
+
static BOOL recycle_keep_dir_tree(vfs_handle_struct *handle)
{
BOOL ret;
@@ -181,6 +246,7 @@
return dirmode;
}
+
static BOOL recycle_directory_exist(vfs_handle_struct *handle, const char *dname)
{
SMB_STRUCT_STAT st;
@@ -357,12 +423,18 @@
char *path_name = NULL;
char *temp_name = NULL;
char *final_name = NULL;
- const char *base;
+ const char *base = NULL;
+ char *basebase = NULL;
+ char *midext = NULL;
+ char *finext = NULL;
+ char *c;
char *repository = NULL;
+ const char *template_str = NULL;
int i = 1;
int maxsize;
+ int maxiter;
SMB_OFF_T file_size; /* space_avail; */
- BOOL exist;
+ BOOL exist, flag;
int rc = -1;
repository = alloc_sub_conn(conn, recycle_repository(handle));
@@ -377,13 +449,6 @@
goto done;
}
- /* we don't recycle the recycle bin... */
- if (strncmp(file_name, repository, strlen(repository)) == 0) {
- DEBUG(3, ("recycle: File is within recycling bin, unlinking ...\n"));
- rc = SMB_VFS_NEXT_UNLINK(handle, conn, file_name);
- goto done;
- }
-
file_size = recycle_get_file_size(handle, file_name);
/* it is wrong to purge filenames only because they are empty imho
* --- simo
@@ -418,10 +483,11 @@
}
*/
- /* extract filename and path */
+ /* extract filename, path and other parts */
base = strrchr(file_name, '/');
if (base == NULL) {
- base = file_name;
+ basebase = SMB_STRDUP(file_name);
+ ALLOC_CHECK(basebase, done);
path_name = SMB_STRDUP("/");
ALLOC_CHECK(path_name, done);
}
@@ -430,6 +496,8 @@
ALLOC_CHECK(path_name, done);
path_name[base - file_name] = '\0';
base++;
+ basebase = SMB_STRDUP(base);
+ ALLOC_CHECK(basebase, done);
}
DEBUG(10, ("recycle: fname = %s\n", file_name)); /* original filename with path */
@@ -452,13 +520,92 @@
goto done;
}
+ /* we don't recycle the recycle bin... */
+
+ flag = False;
+ if (recycle_in_tree(handle) == True) {
+ /* With in-tree recycling, the repository path would
+ be a sub-path of the entire path_name. This can
+ mean several things:
+
+ - repository is equal to the path_name
+ - repository matches at the beginning of path_name
+ - repository matches at the end of path_name
+ - repository matches somewhere in the middle of path_name
+
+ For the last three cases we must also check that a
+ directory separator comes immediately before and/or after
+ the matched portion of path_name.
+
+ NOTE: We have to do this in a loop, as it could be
+ the case that we have several matches for the same
+ repository, but for the first match the additional
+ checks would not be true.
+
+ Example: repository = ".recycle"
+
+ bla/a.recycler/blub/xy -> no recycle bin
+ bla/a.recycler/blub/.recycle/xy -> recycle bin
+
+ FIXME: I doubt that this works for Multi-Byte characters
+ */
+
+ c = path_name;
+ while (c != NULL) {
+ char *d;
+
+ c = strstr(c, repository);
+ if (c == NULL) {
+ break;
+ }
+ d = c + strlen(repository);
+ if ( ((c == path_name) || ((c != path_name) && *(c - 1) == '/')) &&
+ (*d == '/' || *d == 0)) {
+ flag = True;
+ break;
+ }
+ c++;
+ }
+ } else {
+ if (strncmp(path_name, repository, strlen(repository)) == 0) {
+ c = path_name + strlen(repository);
+ flag = (*c == 0 || *c == '/');
+ }
+ }
+
+ if (flag) {
+ DEBUG(3, ("recycle: File is within recycling bin, unlinking ...\n"));
+ rc = SMB_VFS_NEXT_UNLINK(handle, conn, file_name);
+ goto done;
+ }
+
if (recycle_keep_dir_tree(handle) == True) {
asprintf(&temp_name, "%s/%s", repository, path_name);
+ } else if (recycle_in_tree(handle) == True) {
+ asprintf(&temp_name, "%s/%s", path_name, repository);
} else {
temp_name = SMB_STRDUP(repository);
}
ALLOC_CHECK(temp_name, done);
+ c = strrchr(basebase, '.');
+ finext = SMB_STRDUP(c == NULL ? "" : c);
+ ALLOC_CHECK(finext, done);
+ if (c) {
+ *c = 0; /* this actually sets the end if midext */
+ }
+
+ c = strchr(basebase, '.');
+ midext = SMB_STRDUP(c == NULL ? "" : c);
+ ALLOC_CHECK(midext, done);
+ if (c) {
+ *c = 0; /* this finally sets basebase */
+ }
+
+ DEBUG(10, ("recycle: basebase = %s\n", basebase)); /* base without extensions */
+ DEBUG(10, ("recycle: midext = %s\n", midext)); /* middle extension(s) */
+ DEBUG(10, ("recycle: finext = %s\n", finext)); /* last extension */
+
exist = recycle_directory_exist(handle, temp_name);
if (exist) {
DEBUG(10, ("recycle: Directory already exists\n"));
@@ -485,11 +632,32 @@
}
}
+ template_str = recycle_template(handle);
+
/* rename file we move to recycle bin */
i = 1;
- while (recycle_file_exist(handle, final_name)) {
+ maxiter = recycle_maxiter(handle);
+ while (recycle_file_exist(handle, final_name) &&
+ (maxiter == 0 || i <= maxiter)) {
+ char *t = NULL;
+
+ /* variable position format/type meaning */
+ /* i 1 integer running number */
+ /* basebase 2 string The base name of the deleted file (excluding extension) */
+ /* ext 3 string The part including and behind the last dot in the base name */
+ /* allext 4 string The part including and behind the first dot in the base name */
+
+ /* NOTE: If more or other argument-types get
+ introduced, then recycle_template must also be
+ changed to check for proper types and number of
+ arguments */
+ asprintf(&t, template_str, i++, basebase, midext, finext);
+ ALLOC_CHECK(t, done);
+
SAFE_FREE(final_name);
- asprintf(&final_name, "%s/Copy #%d of %s", temp_name, i++, base);
+ asprintf(&final_name, "%s/%s", temp_name, t);
+ SAFE_FREE(t);
+ ALLOC_CHECK(final_name, done);
}
DEBUG(10, ("recycle: Moving %s to %s\n", file_name, final_name));
@@ -505,6 +673,9 @@
recycle_do_touch(handle, final_name, recycle_touch_mtime(handle));
done:
+ SAFE_FREE(finext);
+ SAFE_FREE(midext);
+ SAFE_FREE(basebase);
SAFE_FREE(path_name);
SAFE_FREE(temp_name);
SAFE_FREE(final_name);
More information about the samba-technical
mailing list