diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 9175c6e978..c851a0d75a 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -32,10 +32,13 @@ # define STAT _wstat # define STRUCT_STAT struct _stat # define MKDIR(path, mode) _wmkdir(path) +# define CHMOD(path, mode) _wchmod(path, mode) # define UNLINK _wunlink # define RENAME _wrename # define OPEN_MASK O_BINARY +# define CHECK_X_OK R_OK + # ifdef _MSC_VER # define S_ISREG(x) ((x) & _S_IFREG) # define S_ISDIR(x) ((x) & _S_IFDIR) @@ -67,11 +70,14 @@ typedef wchar_t char_t; # define STAT stat # define STRUCT_STAT struct stat # define MKDIR mkdir +# define CHMOD chmod # define CREAT creat # define UNLINK unlink # define RENAME rename # define OPEN_MASK 0 +# define CHECK_X_OK X_OK + # define GET_CHARS GetStringUTFChars # define RELEASE_CHARS ReleaseStringUTFChars @@ -442,6 +448,64 @@ Java_java_io_File_canWrite(JNIEnv* e, jclass, jstring path) return false; } +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_canExecute(JNIEnv* e, jclass, jstring path) +{ + string_t chars = getChars(e, path); + if (chars) { + int r = ACCESS(chars, CHECK_X_OK); + releaseChars(e, path, chars); + return (r == 0); + } + return false; +} + +#ifndef PLATFORM_WINDOWS +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_setExecutable(JNIEnv* e, jclass, jstring path, jboolean executable, jboolean ownerOnly) +{ + string_t chars = getChars(e, path); + if(chars) { + jboolean v; + int mask; + if(ownerOnly) { + mask = S_IXUSR; + } else { + mask = S_IXUSR | S_IXGRP | S_IXOTH; + } + + STRUCT_STAT s; + int r = STAT(chars, &s); + if(r == 0) { + int mode = s.st_mode; + if(executable) { + mode |= mask; + } else { + mode &= ~mask; + } + if(CHMOD(chars, mode) != 0) { + v = false; + } else { + v = true; + } + } else { + v = false; + } + releaseChars(e, path, chars); + return v; + } + return false; +} + +#else // ifndef PLATFORM_WINDOWS + +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_setExecutable(JNIEnv*, jclass, jstring, jboolean executable, jboolean) +{ + return executable; +} + +#endif extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_rename(JNIEnv* e, jclass, jstring old, jstring new_) diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index 9342627bd5..bfae0da9b6 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -35,6 +35,38 @@ public class File implements Serializable { this(parent.getPath() + FileSeparator + child); } + public static File createTempFile(String prefix, String suffix) { + return createTempFile(prefix, suffix, null); + } + + public static File createTempFile(String prefix, String suffix, File directory) { + if(directory == null) { + directory = new File(System.getProperty("java.io.tmpdir")); + } + if(suffix == null) { + suffix = ".tmp"; + } + File ret; + long state = System.currentTimeMillis(); + + do { + ret = generateFile(directory, prefix, state, suffix); + state *= 7; + state += 3; + } while(ret == null); + ret.createNewFile(); + return ret; + } + + private static File generateFile(File directory, String prefix, long state, String suffix) { + File ret = new File(directory, prefix + state + suffix); + if(ret.exists()) { + return null; + } else { + return ret; + } + } + private static String normalize(String path) { if ("\\".equals(FileSeparator)) { return path.replace('/', '\\'); @@ -76,6 +108,22 @@ public class File implements Serializable { public boolean canWrite() { return canWrite(path); } + + private static native boolean canExecute(String path); + + public boolean canExecute() { + return canExecute(path); + } + + private static native boolean setExecutable(String path, boolean executable, boolean ownerOnly); + + public boolean setExecutable(boolean executable) { + return setExecutable(executable, true); + } + + public boolean setExecutable(boolean executable, boolean ownerOnly) { + return setExecutable(path, executable, ownerOnly); + } public String getName() { int index = path.lastIndexOf(FileSeparator); diff --git a/makefile b/makefile index 218216f537..b83cfabad5 100755 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -MAKEFLAGS = -s +#MAKEFLAGS = -s name = avian version = 0.5 diff --git a/test/Files.java b/test/Files.java index 6bf01dadaa..7661e79018 100644 --- a/test/Files.java +++ b/test/Files.java @@ -20,10 +20,24 @@ public class Files { } } + + private static void setExecutableTestWithPermissions(boolean executable) { + File file = File.createTempFile("avian.", null); + file.setExecutable(executable); + if (executable) { + expect(file.canExecute()); + } else { + // Commented out because this will fail on Windows - both on Avian and on OpenJDK + // The implementation for Windows considers canExecute() to be the same as canRead() + // expect(!file.canExecute()); + } + } public static void main(String[] args) { isAbsoluteTest(true); isAbsoluteTest(false); + setExecutableTestWithPermissions(true); + setExecutableTestWithPermissions(false); } }