Added PosixFiles.stat()

This commit is contained in:
Adam Murdoch
2013-12-07 09:27:52 +11:00
parent 242f3991f3
commit e03d3c16f3
6 changed files with 171 additions and 12 deletions

View File

@@ -71,15 +71,37 @@ Java_net_rubygrapefruit_platform_internal_jni_PosixFileFunctions_stat(JNIEnv *en
if (pathStr == NULL) {
return;
}
int retval = stat(pathStr, &fileInfo);
int retval = lstat(pathStr, &fileInfo);
free(pathStr);
if (retval != 0) {
if (retval != 0 && errno != ENOENT) {
mark_failed_with_errno(env, "could not stat file", result);
return;
}
jclass destClass = env->GetObjectClass(dest);
jfieldID modeField = env->GetFieldID(destClass, "mode", "I");
env->SetIntField(dest, modeField, 0777 & fileInfo.st_mode);
jfieldID typeField = env->GetFieldID(destClass, "type", "I");
if (retval != 0) {
env->SetIntField(dest, typeField, 4);
} else {
env->SetIntField(dest, modeField, 0777 & fileInfo.st_mode);
int type;
switch (fileInfo.st_mode & S_IFMT) {
case S_IFREG:
type = 0;
break;
case S_IFDIR:
type = 1;
break;
case S_IFLNK:
type = 2;
break;
default:
type= 3;
}
env->SetIntField(dest, typeField, type);
}
}
JNIEXPORT void JNICALL

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2012 Adam Murdoch
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.rubygrapefruit.platform;
/**
* Provides some information about a file. This is a snapshot and does not change.
*/
@ThreadSafe
public interface PosixFile {
enum Type {File, Directory, Symlink, Other, Missing}
/**
* Returns the type of this file.
*/
Type getType();
/**
* Returns the mode of this file.
*/
int getMode();
}

View File

@@ -40,7 +40,7 @@ public interface PosixFiles extends NativeIntegration {
int getMode(File path) throws NativeException;
/**
* Creates a symbolic link.
* Creates a symbolic link with given contents.
*
* @throws NativeException On failure.
*/
@@ -54,4 +54,12 @@ public interface PosixFiles extends NativeIntegration {
*/
@ThreadSafe
String readLink(File link) throws NativeException;
/**
* Returns basic information about the given file.
*
* @throws NativeException On failure.
*/
@ThreadSafe
PosixFile stat(File path) throws NativeException;
}

View File

@@ -17,12 +17,23 @@
package net.rubygrapefruit.platform.internal;
import net.rubygrapefruit.platform.NativeException;
import net.rubygrapefruit.platform.PosixFile;
import net.rubygrapefruit.platform.PosixFiles;
import net.rubygrapefruit.platform.internal.jni.PosixFileFunctions;
import java.io.File;
public class DefaultPosixFiles implements PosixFiles {
public PosixFile stat(File file) throws NativeException {
FunctionResult result = new FunctionResult();
FileStat stat = new FileStat();
PosixFileFunctions.stat(file.getPath(), stat, result);
if (result.isFailed()) {
throw new NativeException(String.format("Could not get posix file details of %s: %s", file, result.getMessage()));
}
return stat;
}
public void setMode(File file, int perms) {
FunctionResult result = new FunctionResult();
PosixFileFunctions.chmod(file.getPath(), perms, result);
@@ -32,13 +43,11 @@ public class DefaultPosixFiles implements PosixFiles {
}
public int getMode(File file) {
FunctionResult result = new FunctionResult();
FileStat stat = new FileStat();
PosixFileFunctions.stat(file.getPath(), stat, result);
if (result.isFailed()) {
throw new NativeException(String.format("Could not get UNIX mode on %s: %s", file, result.getMessage()));
PosixFile stat = stat(file);
if (stat.getType() == PosixFile.Type.Missing) {
throw new NativeException(String.format("Could not get UNIX mode on %s: file does not exist.", file));
}
return stat.mode;
return stat.getMode();
}
public String readLink(File link) throws NativeException {

View File

@@ -16,6 +16,17 @@
package net.rubygrapefruit.platform.internal;
public class FileStat {
import net.rubygrapefruit.platform.PosixFile;
public class FileStat implements PosixFile {
public int mode;
public int type;
public int getMode() {
return mode;
}
public Type getType() {
return Type.values()[type];
}
}

View File

@@ -32,6 +32,48 @@ class PosixFilesTest extends Specification {
Native.get(PosixFiles.class) == file
}
def "can get details of a file"() {
def testFile = tmpDir.newFile(fileName)
when:
def stat = file.stat(testFile)
then:
stat.type == PosixFile.Type.File
stat.mode != 0
where:
fileName << ["test.txt", "test\u03b1\u2295.txt"]
}
def "can get details of a directory"() {
def testFile = tmpDir.newFolder(fileName)
when:
def stat = file.stat(testFile)
then:
stat.type == PosixFile.Type.Directory
stat.mode != 0
where:
fileName << ["test-dir", "test\u03b1\u2295-dir"]
}
def "can get details of a missing file"() {
def testFile = new File(tmpDir.root, fileName)
when:
def stat = file.stat(testFile)
then:
stat.type == PosixFile.Type.Missing
stat.mode == 0
where:
fileName << ["test-dir", "test\u03b1\u2295-dir"]
}
def "can set mode on a file"() {
def testFile = tmpDir.newFile(fileName)
@@ -40,11 +82,26 @@ class PosixFilesTest extends Specification {
then:
file.getMode(testFile) == 0740
file.stat(testFile).mode == 0740
where:
fileName << ["test.txt", "test\u03b1\u2295.txt"]
}
def "can set mode on a directory"() {
def testFile = tmpDir.newFolder(fileName)
when:
file.setMode(testFile, 0740)
then:
file.getMode(testFile) == 0740
file.stat(testFile).mode == 0740
where:
fileName << ["test-dir", "test\u03b1\u2295-dir"]
}
def "cannot set mode on file that does not exist"() {
def testFile = new File(tmpDir.root, "unknown")
@@ -64,7 +121,7 @@ class PosixFilesTest extends Specification {
then:
NativeException e = thrown()
e.message == "Could not get UNIX mode on $testFile: could not stat file (ENOENT errno 2)"
e.message == "Could not get UNIX mode on $testFile: file does not exist."
}
def "can create symbolic link"() {
@@ -126,4 +183,21 @@ class PosixFilesTest extends Specification {
symlinkFile.file
symlinkFile.canonicalFile == testFile.canonicalFile
}
def "can get details of a symlink"() {
def testFile = new File(tmpDir.newFolder("parent"), fileName)
given:
file.symlink(testFile, "target")
when:
def stat = file.stat(testFile)
then:
stat.type == PosixFile.Type.Symlink
stat.mode != 0
where:
fileName << ["test.txt", "test\u03b1\u2295.txt"]
}
}