src/fuse/udcFuse/udcFuse.c 1.7

1.7 2010/01/05 00:39:06 angie
Make empty directory appear to be non-existent, so udcFuse doesn't get confused by an empty dir becoming a regular file (i.e. udcCache dir with bitmap and sparseData).
Index: src/fuse/udcFuse/udcFuse.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/fuse/udcFuse/udcFuse.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -b -B -U 4 -r1.6 -r1.7
--- src/fuse/udcFuse/udcFuse.c	20 Nov 2009 17:56:35 -0000	1.6
+++ src/fuse/udcFuse/udcFuse.c	5 Jan 2010 00:39:06 -0000	1.7
@@ -88,18 +88,28 @@
     if (dirHandle != NULL)
 	{
 	// should we make sure that there are not also subdirectories??
 	boolean gotBitmap = FALSE, gotSparse = FALSE;
+	int isEmpty = TRUE;
 	struct dirent *dirInfo;
 	while ((dirInfo = readdir(dirHandle)) != NULL)
 	    {
+	    if (sameString(dirInfo->d_name, ".") || sameString(dirInfo->d_name, ".."))
+		continue;
+	    isEmpty = FALSE;
 	    if (sameString(dirInfo->d_name, "bitmap"))
 		gotBitmap = TRUE;
 	    else if (sameString(dirInfo->d_name, "sparseData"))
 		gotSparse = TRUE;
 	    if (gotBitmap && gotSparse)
 		break;
 	    }
+	// fuse gets confused when a cache path is an empty dir, and then suddenly morphs
+	// into a regular file, as happens when old cache files are removed by the 
+	// trash cleaner but then reappear due to a new udc access.  So if empty dir,
+	// just tell fuse that it doesn't exist.
+	if (isEmpty)
+	    return -ENOENT;
 	if (gotBitmap || gotSparse)
 	    {
 	    if (gotBitmap ^ gotSparse)
 		fprintf(stderr, "...[%d] getattr: got one cache file but not the other - stale?\n",
@@ -186,8 +196,33 @@
 fprintf(stderr, "...[%d] getattr %s finish %ld\n", pid, path, clock1000());
 return ret;
 }
 
+static boolean isEmptyDir(char *udcCachePath, char *subdir)
+/* Return TRUE if subdir of path is a directory with no children. */
+{
+boolean isDir = FALSE, isEmpty = TRUE;
+char fullPath[4096];
+ERR_CATCH_START();
+safef(fullPath, sizeof(fullPath), "%s/%s", udcCachePath, subdir);
+ERR_CATCH_END("safef fullPath");
+DIR *dirHandle = opendir(fullPath);
+if (dirHandle != NULL)
+    {
+    isDir = TRUE;
+    struct dirent *dirInfo;
+    while ((dirInfo = readdir(dirHandle)) != NULL)
+	{
+	if (sameString(dirInfo->d_name, ".") || sameString(dirInfo->d_name, ".."))
+	    continue;
+	isEmpty = FALSE;
+	break;
+	}
+    closedir(dirHandle);
+    }
+return isDir && isEmpty;
+}
+
 static int udcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
 			 off_t offset, struct fuse_file_info *fi)
 /* Read the corresponding udc cache directory. */
 {
@@ -203,10 +238,17 @@
     return -errno;
     }
 struct dirent *dirInfo;
 while ((dirInfo = readdir(dirHandle)) != NULL)
+    // getattr denies the existence of empty udcCache directories because they
+    // might get bitmap and sparseData files and then we report them as regular
+    // files not directories.  Filter out components here that are empty directories:
+    if (sameString(".", dirInfo->d_name) || sameString("..", dirInfo->d_name) ||
+	!isEmptyDir(udcCachePath, dirInfo->d_name))
+	{
     if (filler(buf, dirInfo->d_name, NULL, 0))
 	break;
+	}
 int ret = closedir(dirHandle);
 fprintf(stderr, "...[%d] readdir %s finish %ld\n", pid, path, clock1000());
 return ret;
 }