vfs_shadow_copy.c - suggested patch

Nadav Danieli nadavd at exanet.com
Sun Jan 23 15:48:47 GMT 2005


Hello all,

The first thing that catches the eye is that a whole dir is read every
time the vfs opendir is called. Is there a good reason for this?
I do not have a file system with real snapshots (yet,) so I tried it
with just copies of the share root hierarchy, with the client installed
on a w2k machine.
It was working fine for files on the share root, but did not for sub
dirs and files.
Analyzing the packets on the wire shows, query path info requests with
level file network open info.
for directories: \sub-dir\<shadow dir>
for files: \sub-dir\<shadow dir>\file
Then open/readir for view/restore.
Attached the suggested patch. Tested with w2k client only.
Comments are most welcome.

Nadav


-------------- next part --------------
--- modules/vfs_shadow_copy.c.orig	2005-01-23 16:20:06.000000000 +0200
+++ modules/vfs_shadow_copy.c.new	2005-01-23 17:01:45.000000000 +0200
@@ -56,11 +56,31 @@
 #define SHADOW_COPY_PREFIX "@GMT-"
 #define SHADOW_COPY_SAMPLE "@GMT-2004.02.18-15.44.00"
 
-typedef struct {
-	int pos;
-	int num;
-	struct dirent *dirs;
-} shadow_copy_Dir;
+static BOOL shadow_copy_convert_name(const char *name, pstring shadow_name)
+{
+	const int prefixlen = sizeof(SHADOW_COPY_SAMPLE) - 1;
+	const char *s = name;
+	while ((s = strstr(s, SHADOW_COPY_PREFIX)) != NULL) {
+		if (s && (s == name || s[-1] == '/') && (s[prefixlen] == '/' || s[prefixlen] == '\0')) {
+			char *tmp;
+			if (s == name) // share root, no need for conversion
+				return False;
+			tmp = strncpy(shadow_name, s, prefixlen);
+			tmp += prefixlen;
+			*tmp++ = '/';
+			strncpy(tmp, name, s-name);
+			tmp += s-name;
+			if (s[prefixlen] == '\0') {
+				tmp[-1] = '\0';
+			} else {
+				strncpy(tmp, &s[prefixlen+1], sizeof(pstring) - (tmp - shadow_name));
+			}
+			return True;
+		}
+		s += sizeof(SHADOW_COPY_PREFIX) - 1;
+	}
+	return False;
+}
 
 static BOOL shadow_copy_match_name(const char *name)
 {
@@ -74,72 +94,26 @@
 
 static DIR *shadow_copy_opendir(vfs_handle_struct *handle, connection_struct *conn, const char *fname)
 {
-	shadow_copy_Dir *dirp;
-	DIR *p = SMB_VFS_NEXT_OPENDIR(handle,conn,fname);
-
-	if (!p) {
-		DEBUG(0,("shadow_copy_opendir: SMB_VFS_NEXT_OPENDIR() failed for [%s]\n",fname));
-		return NULL;
-	}
-
-	dirp = (shadow_copy_Dir *)malloc(sizeof(shadow_copy_Dir));
-	if (!dirp) {
-		DEBUG(0,("shadow_copy_opendir: Out of memory\n"));
-		SMB_VFS_NEXT_CLOSEDIR(handle,conn,p);
-		return NULL;
-	}
-
-	ZERO_STRUCTP(dirp);
-
-	while (True) {
-		struct dirent *d;
-		struct dirent *r;
-
-
-		d = SMB_VFS_NEXT_READDIR(handle, conn, p);
-		if (d == NULL) {
-			break;
-		}
-
-		if (shadow_copy_match_name(d->d_name)) {
-			DEBUG(8,("shadow_copy_opendir: hide [%s]\n",d->d_name));
-			continue;
-		}
-
-		DEBUG(10,("shadow_copy_opendir: not hide [%s]\n",d->d_name));
-
-		r = (struct dirent *)Realloc(dirp->dirs,(dirp->num+1)*sizeof(struct dirent));
-		if (!r) {
-			DEBUG(0,("shadow_copy_opendir: Out of memory\n"));
-			break;
-		}
-
-		dirp->dirs = r;
-		dirp->dirs[dirp->num++] = *d;
+	pstring shadow_name;
+	if (shadow_copy_convert_name(fname, shadow_name)) {
+		DEBUG(10,("shadow_copy_opendir: [%s] converted to [%s]\n", fname, shadow_name));
+		fname = shadow_name;
 	}
-
-	SMB_VFS_NEXT_CLOSEDIR(handle,conn,p);
-	return((DIR *)dirp);
+	return SMB_VFS_NEXT_OPENDIR(handle,conn,fname);
 }
 
 struct dirent *shadow_copy_readdir(vfs_handle_struct *handle, connection_struct *conn, DIR *_dirp)
 {
-	shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp;
-
-	if (dirp->pos < dirp->num) {
-		return &(dirp->dirs[dirp->pos++]);
-	}
-
-	return NULL;
-}
-
-int shadow_copy_closedir(vfs_handle_struct *handle, connection_struct *conn, DIR *_dirp)
-{
-	shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp;
-
-	SAFE_FREE(dirp);
- 
-	return 0;	
+	struct dirent *d;
+	BOOL ignore;
+	do {
+		d = SMB_VFS_NEXT_READDIR(handle, conn, _dirp);
+		ignore = d ? shadow_copy_match_name(d->d_name) : False;
+		if (ignore) {
+			DEBUG(10,("shadow_copy_readdir: ignore [%s]\n",d->d_name));
+		}
+	} while ((d != NULL) && ignore);
+	return d;
 }
 
 static int shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle, files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, BOOL labels)
@@ -194,15 +168,37 @@
 	return 0;
 }
 
+static int shadow_copy_open(vfs_handle_struct *handle, connection_struct *conn, const char *fname, int flags, mode_t mode)
+{
+	pstring shadow_name;
+	if (shadow_copy_convert_name(fname, shadow_name)) {
+		DEBUG(10,("shadow_copy_open: [%s] converted to [%s]\n", fname, shadow_name));
+		fname = shadow_name;
+	}
+	return SMB_VFS_NEXT_OPEN(handle, conn, fname, flags, mode);
+}
+
+static int shadow_copy_stat(vfs_handle_struct *handle, connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
+{
+	pstring shadow_name;
+	if (shadow_copy_convert_name(path, shadow_name)) {
+		DEBUG(10,("shadow_copy_stat: [%s] converted to [%s]\n", path, shadow_name));
+		path = shadow_name;
+	}
+    return SMB_VFS_NEXT_STAT(handle, conn, path, sbuf);
+}
+
 /* VFS operations structure */
 
 static vfs_op_tuple shadow_copy_ops[] = {
 	{SMB_VFS_OP(shadow_copy_opendir),		SMB_VFS_OP_OPENDIR,		SMB_VFS_LAYER_TRANSPARENT},
 	{SMB_VFS_OP(shadow_copy_readdir),		SMB_VFS_OP_READDIR,		SMB_VFS_LAYER_TRANSPARENT},
-	{SMB_VFS_OP(shadow_copy_closedir),		SMB_VFS_OP_CLOSEDIR,		SMB_VFS_LAYER_TRANSPARENT},
 
 	{SMB_VFS_OP(shadow_copy_get_shadow_copy_data),	SMB_VFS_OP_GET_SHADOW_COPY_DATA,SMB_VFS_LAYER_OPAQUE},
 
+	{SMB_VFS_OP(shadow_copy_open),			SMB_VFS_OP_OPEN,		SMB_VFS_LAYER_TRANSPARENT},
+	{SMB_VFS_OP(shadow_copy_stat),			SMB_VFS_OP_STAT,		SMB_VFS_LAYER_TRANSPARENT},
+	
 	{SMB_VFS_OP(NULL),				SMB_VFS_OP_NOOP,		SMB_VFS_LAYER_NOOP}
 };
 


More information about the samba-technical mailing list