Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 4 Jun 2000 00:25:50 +0930 (CST)
From:      Greg Lewis <glewis@trc.adelaide.edu.au>
To:        Rob Furphy <rcf@ox.com>
Cc:        freebsd-java@freebsd.org
Subject:   Re: can't remove directories? (Better fix)
Message-ID:  <200006031455.AAA43786@ares.trc.adelaide.edu.au>
In-Reply-To: <3937FCCD.5223CCF1@ox.com> from Rob Furphy at "Jun 2, 2000 02:28:29 pm"

next in thread | previous in thread | raw e-mail | index | archive | help
Rob Furphy wrote:
> I have made changes to your fix.  Instead of blindly trying both file
> and directory deletes on the specified path, this fix discovers
> what the path is(dir or not) and does the appropriate thing.

I like that part about it :).

> Not good with diff (and don't want to get this wrong),
> so below is the new versions of both functions.
> 
> JNIEXPORT jboolean JNICALL
> Java_java_io_UnixFileSystem_delete(JNIEnv *env, jobject this,
>                                    jobject file) {
>     jboolean rv = JNI_FALSE;
> 
>     WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
> #ifdef __FreeBSD__
>         /*
>          * Under FreeBSD remove(3) is simply an alias for unlink(2).  This
>          * is not the case on Linux and Solaris where remove() calls unlink()
>          * for files and rmdir() for directories.  Duplicate this functionality
>          * here by identifying if we have a directory or not.
>          */
>         struct stat sb;
>         if(stat(path, &sb) == 0) {
>             int fmt = sb.st_mode & S_IFMT;
> 
>             if(fmt == S_IFDIR) {
>                 if(rmdir(path) == 0) {
>                     rv = JNI_TRUE;
>                 }
>             } else {
>                 if(unlink(path) == 0) {
>                     rv = JNI_TRUE;
>                 }
>             }
> #else
>         if(remove(path) == 0) {
> #endif
>             rv = JNI_TRUE;
>         }
>     } END_PLATFORM_STRING(env, path);
>     return rv;
> }
> 
> 
> JNIEXPORT jboolean JNICALL
> Java_java_io_UnixFileSystem_deleteOnExit(JNIEnv *env, jobject this,
>                                          jobject file) {
>     WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
> #ifdef __FreeBSD__
>         /*
>         * Under FreeBSD remove(3) is simply an alias for unlink(2).  This
>         * is not the case on Linux and Solaris where remove() calls unlink()
>         * for files and rmdir() for directories.  Duplicate this functionality
>         * here by identifying if we have a directory or not.
>         */
>         struct stat sb;
>         if(stat(path, &sb) == 0) {
>             int fmt = sb.st_mode & S_IFMT;
> 
>             if(fmt == S_IFDIR) {
>                 deleteOnExit(env, path, rmdir);
>             } else {
>                 deleteOnExit(env, path, unlink);
>             }
>         }
> #else
>         deleteOnExit(env, path, remove);
> #endif
>     } END_PLATFORM_STRING(env, path);
>     return JNI_TRUE;
> }

But in this last function is the part that I think creates a problem.  To
elaborate on what I sort of mentioned last time with an example:  If I
have a File object named foo for the (plain) file "tmp/foo", say, and
I do this:

// Schedule foo for deletion, as this is currently a file, it will schedule
// a call to unlink.
foo.deleteOnExit();
// Delete foo immediately
foo.delete();
// Now recreate foo as a directory
foo.mkdir();
// Now the empty directory /tmp/foo won't get deleted on FreeBSD on exit
// (as unlink will be called) but will on Solaris and Linux.
System.exit(0);

Or thats what will happen unless I'm missing something :).  I'd propose a
modification which keeps the identification of whether to use unlink or
remove, but do so at the time when the file is being removed, instead of
when its scheduled to be removed.  Patch follows (I tested this one!).
Comments?

Index: src/freebsd/native/java/io/UnixFileSystem_md.c
===================================================================
RCS file: /data/java/JDK2/javasrc/src/freebsd/native/java/io/UnixFileSystem_md.c,v
retrieving revision 1.3
diff -u -r1.3 UnixFileSystem_md.c
--- src/freebsd/native/java/io/UnixFileSystem_md.c	2000/04/13 14:05:57	1.3
+++ src/freebsd/native/java/io/UnixFileSystem_md.c	2000/06/03 14:44:29
@@ -229,7 +229,34 @@
     return rv;
 }
 
+#ifdef __FreeBSD__
+/* Prototype */
+int unlink_or_rmdir(const char *);
+/*
+ * Under FreeBSD remove(3) is simply an alias for unlink(2).  This
+ * is not the case on Linux and Solaris where remove() calls unlink()
+ * for files and rmdir() for directories.  Duplicate this functionality
+ * here by identifying if we have a directory or not and calling the
+ * appropriate function.
+ */
+int 
+unlink_or_rmdir(const char *path) {
+    struct stat sb;
 
+    if (stat(path, &sb) == 0) {
+        int fmt = sb.st_mode & S_IFMT;
+
+        if (fmt == S_IFDIR) {
+	    return rmdir(path);
+        } else {
+	    return unlink(path);
+        }
+    }
+    return (-1);
+}
+#endif
+
+
 JNIEXPORT jboolean JNICALL
 Java_java_io_UnixFileSystem_delete(JNIEnv *env, jobject this,
 				   jobject file)
@@ -237,7 +264,11 @@
     jboolean rv = JNI_FALSE;
 
     WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+#ifdef __FreeBSD__
+	if (unlink_or_rmdir(path) == 0) {
+#else
 	if (remove(path) == 0) {
+#endif
 	    rv = JNI_TRUE;
 	}
     } END_PLATFORM_STRING(env, path);
@@ -250,7 +281,11 @@
 					 jobject file)
 {
     WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
+#ifdef __FreeBSD__
+	deleteOnExit(env, path, unlink_or_rmdir);
+#else
 	deleteOnExit(env, path, remove);
+#endif
     } END_PLATFORM_STRING(env, path);
     return JNI_TRUE;
 }
-- 
Greg Lewis 				glewis@trc.adelaide.edu.au
Computing Officer			+61 8 8303 5083
Teletraffic Research Centre


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-java" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200006031455.AAA43786>