svn commit: samba r18319 - in branches/SAMBA_4_0/source: ntvfs/posix torture/raw

tridge at samba.org tridge at samba.org
Sun Sep 10 07:24:42 GMT 2006


Author: tridge
Date: 2006-09-10 07:24:41 +0000 (Sun, 10 Sep 2006)
New Revision: 18319

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=18319

Log:

fixed the directory search resume code on IRIX

The problem was twofold:

  1) irix returns 64 bit numbers in telldir(). The protocol uses a 32
     bit resume key. We now cope with this properly using the code in
     pvfs_list_seek_ofs().

  2) irix returns 0xFFFFFFFF from telldir() for the last entry in the
     directory. When added to DIR_OFFSET_BASE this became
     DIR_OFFSET_DOTDOT which meant an infinite loop!

Modified:
   branches/SAMBA_4_0/source/ntvfs/posix/pvfs_dirlist.c
   branches/SAMBA_4_0/source/ntvfs/posix/pvfs_rename.c
   branches/SAMBA_4_0/source/ntvfs/posix/pvfs_search.c
   branches/SAMBA_4_0/source/ntvfs/posix/pvfs_unlink.c
   branches/SAMBA_4_0/source/ntvfs/posix/vfs_posix.h
   branches/SAMBA_4_0/source/torture/raw/search.c


Changeset:
Modified: branches/SAMBA_4_0/source/ntvfs/posix/pvfs_dirlist.c
===================================================================
--- branches/SAMBA_4_0/source/ntvfs/posix/pvfs_dirlist.c	2006-09-10 03:58:00 UTC (rev 18318)
+++ branches/SAMBA_4_0/source/ntvfs/posix/pvfs_dirlist.c	2006-09-10 07:24:41 UTC (rev 18319)
@@ -45,11 +45,15 @@
 	uint32_t name_cache_index;
 };
 
+/* these three numbers are chosen to minimise the chances of a bad
+   interaction with the OS value for 'end of directory'. On IRIX
+   telldir() returns 0xFFFFFFFF at the end of a directory, and that
+   caused an infinite loop with the original values of 0,1,2
+*/
 #define DIR_OFFSET_DOT    0
 #define DIR_OFFSET_DOTDOT 1
-#define DIR_OFFSET_BASE   2
+#define DIR_OFFSET_BASE   0x80000002
 
-
 /*
   a special directory listing case where the pattern has no wildcard. We can just do a single stat()
   thus avoiding the more expensive directory scan
@@ -140,7 +144,7 @@
 	dir->pvfs = pvfs;
 	dir->no_wildcard = False;
 	dir->end_of_search = False;
-	dir->offset = 0;
+	dir->offset = DIR_OFFSET_DOT;
 	dir->name_cache = talloc_zero_array(dir, 
 					    struct name_cache_entry, 
 					    NAME_CACHE_SIZE);
@@ -173,7 +177,7 @@
 /* 
    return the next entry
 */
-const char *pvfs_list_next(struct pvfs_dir *dir, uint_t *ofs)
+const char *pvfs_list_next(struct pvfs_dir *dir, off_t *ofs)
 {
 	struct dirent *de;
 	enum protocol_types protocol = dir->pvfs->ntvfs->ctx->protocol;
@@ -190,7 +194,7 @@
 	   not return them first in a directory, but windows client
 	   may assume that these entries always appear first */
 	if (*ofs == DIR_OFFSET_DOT) {
-		(*ofs)++;
+		(*ofs) = DIR_OFFSET_DOTDOT;
 		dir->offset = *ofs;
 		if (ms_fnmatch(dir->pattern, ".", protocol) == 0) {
 			dcache_add(dir, ".");
@@ -199,7 +203,7 @@
 	}
 
 	if (*ofs == DIR_OFFSET_DOTDOT) {
-		(*ofs)++;
+		(*ofs) = DIR_OFFSET_BASE;
 		dir->offset = *ofs;
 		if (ms_fnmatch(dir->pattern, "..", protocol) == 0) {
 			dcache_add(dir, "..");
@@ -254,7 +258,7 @@
 /*
   return True if end of search has been reached
 */
-BOOL pvfs_list_eos(struct pvfs_dir *dir, uint_t ofs)
+BOOL pvfs_list_eos(struct pvfs_dir *dir, off_t ofs)
 {
 	return dir->end_of_search;
 }
@@ -262,11 +266,13 @@
 /*
   seek to the given name
 */
-NTSTATUS pvfs_list_seek(struct pvfs_dir *dir, const char *name, uint_t *ofs)
+NTSTATUS pvfs_list_seek(struct pvfs_dir *dir, const char *name, off_t *ofs)
 {
 	struct dirent *de;
 	int i;
 
+	dir->end_of_search = False;
+
 	if (ISDOT(name)) {
 		dir->offset = DIR_OFFSET_DOTDOT;
 		*ofs = dir->offset;
@@ -309,7 +315,68 @@
 	return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 }
 
+/*
+  seek to the given offset
+*/
+NTSTATUS pvfs_list_seek_ofs(struct pvfs_dir *dir, uint32_t resume_key, off_t *ofs)
+{
+	struct dirent *de;
+	int i;
 
+	dir->end_of_search = False;
+
+	if (resume_key == DIR_OFFSET_DOT) {
+		*ofs = DIR_OFFSET_DOTDOT;
+		return NT_STATUS_OK;
+	}
+
+	if (resume_key == DIR_OFFSET_DOTDOT) {
+		*ofs = DIR_OFFSET_BASE;
+		return NT_STATUS_OK;
+	}
+
+	if (resume_key == DIR_OFFSET_BASE) {
+		rewinddir(dir->dir);
+		if ((de=readdir(dir->dir)) == NULL) {
+			dir->end_of_search = True;
+			return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+		}
+		*ofs = telldir(dir->dir) + DIR_OFFSET_BASE;
+		dir->offset = *ofs;
+		return NT_STATUS_OK;
+	}
+
+	for (i=dir->name_cache_index;i>=0;i--) {
+		struct name_cache_entry *e = &dir->name_cache[i];
+		if (resume_key == (uint32_t)e->offset) {
+			*ofs = e->offset;
+			return NT_STATUS_OK;
+		}
+	}
+	for (i=NAME_CACHE_SIZE-1;i>dir->name_cache_index;i--) {
+		struct name_cache_entry *e = &dir->name_cache[i];
+		if (resume_key == (uint32_t)e->offset) {
+			*ofs = e->offset;
+			return NT_STATUS_OK;
+		}
+	}
+
+	rewinddir(dir->dir);
+
+	while ((de = readdir(dir->dir))) {
+		dir->offset = telldir(dir->dir) + DIR_OFFSET_BASE;
+		if (resume_key == (uint32_t)dir->offset) {
+			*ofs = dir->offset;
+			return NT_STATUS_OK;
+		}
+	}
+
+	dir->end_of_search = True;
+
+	return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+
 /*
   see if a directory is empty
 */

Modified: branches/SAMBA_4_0/source/ntvfs/posix/pvfs_rename.c
===================================================================
--- branches/SAMBA_4_0/source/ntvfs/posix/pvfs_rename.c	2006-09-10 03:58:00 UTC (rev 18318)
+++ branches/SAMBA_4_0/source/ntvfs/posix/pvfs_rename.c	2006-09-10 07:24:41 UTC (rev 18319)
@@ -257,7 +257,7 @@
 {
 	struct pvfs_dir *dir;
 	NTSTATUS status;
-	uint_t ofs = 0;
+	off_t ofs = 0;
 	const char *fname, *fname2, *dir_path;
 	uint16_t attrib = ren->rename.in.attrib;
 	int total_renamed = 0;

Modified: branches/SAMBA_4_0/source/ntvfs/posix/pvfs_search.c
===================================================================
--- branches/SAMBA_4_0/source/ntvfs/posix/pvfs_search.c	2006-09-10 03:58:00 UTC (rev 18318)
+++ branches/SAMBA_4_0/source/ntvfs/posix/pvfs_search.c	2006-09-10 07:24:41 UTC (rev 18319)
@@ -75,12 +75,15 @@
 				 const char *unix_path,
 				 const char *fname, 
 				 struct pvfs_search_state *search,
-				 uint32_t dir_index,
+				 off_t dir_offset,
 				 union smb_search_data *file)
 {
 	struct pvfs_filename *name;
 	NTSTATUS status;
 	const char *shortname;
+	uint32_t dir_index = (uint32_t)dir_offset; /* truncated - see the code 
+						      in pvfs_list_seek_ofs() for 
+						      how we cope with this */
 
 	status = pvfs_resolve_partial(pvfs, file, unix_path, fname, &name);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -249,7 +252,7 @@
 	while ((*reply_count) < max_count) {
 		union smb_search_data *file;
 		const char *name;
-		uint_t ofs = search->current_index;
+		off_t ofs = search->current_index;
 
 		name = pvfs_list_next(dir, &search->current_index);
 		if (name == NULL) break;
@@ -419,10 +422,15 @@
 		return NT_STATUS_INVALID_HANDLE;
 	}
 
-	search->current_index = io->search_next.in.id.server_cookie;
-	search->last_used = time(NULL);
 	dir = search->dir;
 
+	status = pvfs_list_seek_ofs(dir, io->search_next.in.id.server_cookie, 
+				    &search->current_index);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+	search->last_used = time(NULL);
+
 	status = pvfs_search_fill(pvfs, req, max_count, search, io->generic.data_level,
 				  &reply_count, search_private, callback);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -557,24 +565,25 @@
 		/* we didn't find the search handle */
 		return NT_STATUS_INVALID_HANDLE;
 	}
-
+	
 	dir = search->dir;
+	
+	status = NT_STATUS_OK;
 
 	/* work out what type of continuation is being used */
 	if (io->t2fnext.in.last_name && *io->t2fnext.in.last_name) {
 		status = pvfs_list_seek(dir, io->t2fnext.in.last_name, &search->current_index);
-		if (!NT_STATUS_IS_OK(status)) {
-			if (io->t2fnext.in.resume_key) {
-				search->current_index = io->t2fnext.in.resume_key;
-			} else {
-				return status;
-			}
+		if (!NT_STATUS_IS_OK(status) && io->t2fnext.in.resume_key) {
+			status = pvfs_list_seek_ofs(dir, io->t2fnext.in.resume_key, 
+						    &search->current_index);
 		}
-	} else if (io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE) {
-		/* plain continue - nothing to do */
-	} else {
-		search->current_index = io->t2fnext.in.resume_key;
+	} else if (!(io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE)) {
+		status = pvfs_list_seek_ofs(dir, io->t2fnext.in.resume_key, 
+					    &search->current_index);
 	}
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
 
 	search->num_ea_names = io->t2fnext.in.num_names;
 	search->ea_names = io->t2fnext.in.ea_names;

Modified: branches/SAMBA_4_0/source/ntvfs/posix/pvfs_unlink.c
===================================================================
--- branches/SAMBA_4_0/source/ntvfs/posix/pvfs_unlink.c	2006-09-10 03:58:00 UTC (rev 18318)
+++ branches/SAMBA_4_0/source/ntvfs/posix/pvfs_unlink.c	2006-09-10 07:24:41 UTC (rev 18319)
@@ -130,7 +130,7 @@
 	uint32_t total_deleted=0;
 	struct pvfs_filename *name;
 	const char *fname;
-	uint_t ofs;
+	off_t ofs;
 
 	/* resolve the cifs name to a posix name */
 	status = pvfs_resolve_name(pvfs, req, unl->unlink.in.pattern, 

Modified: branches/SAMBA_4_0/source/ntvfs/posix/vfs_posix.h
===================================================================
--- branches/SAMBA_4_0/source/ntvfs/posix/vfs_posix.h	2006-09-10 03:58:00 UTC (rev 18318)
+++ branches/SAMBA_4_0/source/ntvfs/posix/vfs_posix.h	2006-09-10 07:24:41 UTC (rev 18319)
@@ -183,7 +183,7 @@
 	struct pvfs_search_state *prev, *next;
 	struct pvfs_state *pvfs;
 	uint16_t handle;
-	uint_t current_index;
+	off_t current_index;
 	uint16_t search_attrib;
 	uint16_t must_attrib;
 	struct pvfs_dir *dir;

Modified: branches/SAMBA_4_0/source/torture/raw/search.c
===================================================================
--- branches/SAMBA_4_0/source/torture/raw/search.c	2006-09-10 03:58:00 UTC (rev 18318)
+++ branches/SAMBA_4_0/source/torture/raw/search.c	2006-09-10 07:24:41 UTC (rev 18319)
@@ -203,17 +203,17 @@
 /*
   extract the name from a smb_data structure and level
 */
-static int extract_resume_key(void *data, enum smb_search_level level,
-			      enum smb_search_data_level data_level)
+static uint32_t extract_resume_key(void *data, enum smb_search_level level,
+				   enum smb_search_data_level data_level)
 {
 	int i;
 	for (i=0;i<ARRAY_SIZE(levels);i++) {
 		if (level == levels[i].level &&
 		    data_level == levels[i].data_level) {
-			return (int)*(uint32_t *)(levels[i].resume_key_offset + (char *)data);
+			return *(uint32_t *)(levels[i].resume_key_offset + (char *)data);
 		}
 	}
-	return -1;
+	return 0;
 }
 
 /* find a level in the table by name */
@@ -604,7 +604,7 @@
 			case CONT_RESUME_KEY:
 				io2.t2fnext.in.resume_key = extract_resume_key(&result->list[result->count-1],
 									       io2.t2fnext.level, io2.t2fnext.data_level);
-				if (io2.t2fnext.in.resume_key <= 0) {
+				if (io2.t2fnext.in.resume_key == 0) {
 					printf("Server does not support resume by key for level %s\n",
 					       level_name(io2.t2fnext.level, io2.t2fnext.data_level));
 					return NT_STATUS_NOT_SUPPORTED;



More information about the samba-cvs mailing list