mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
C: implement file IO in Windows
This commit is contained in:
parent
fe6e796637
commit
6e71fa7e87
|
@ -19,4 +19,8 @@ public interface VirtualFileSystem {
|
||||||
String getUserDir();
|
String getUserDir();
|
||||||
|
|
||||||
VirtualFile getFile(String path);
|
VirtualFile getFile(String path);
|
||||||
|
|
||||||
|
boolean isWindows();
|
||||||
|
|
||||||
|
String canonicalize(String path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,31 @@ public class CFileSystem implements VirtualFileSystem {
|
||||||
return entry.get();
|
return entry.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWindows() {
|
||||||
|
return isWindowsNative();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String canonicalize(String path) {
|
||||||
|
if (!isWindows()) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
char[] pathChars = path.toCharArray();
|
||||||
|
Address resultPtr = Memory.malloc(Address.sizeOf());
|
||||||
|
int resultSize = canonicalizeNative(pathChars, pathChars.length, resultPtr);
|
||||||
|
Address result = resultPtr.getAddress();
|
||||||
|
Memory.free(resultPtr);
|
||||||
|
if (resultSize < 0) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
char[] chars = new char[resultSize];
|
||||||
|
Memory.memcpy(Address.ofData(chars), result, chars.length * 2);
|
||||||
|
Memory.free(result);
|
||||||
|
return new String(chars);
|
||||||
|
}
|
||||||
|
|
||||||
static class Entry extends WeakReference<CVirtualFile> {
|
static class Entry extends WeakReference<CVirtualFile> {
|
||||||
String path;
|
String path;
|
||||||
|
|
||||||
|
@ -87,6 +112,10 @@ public class CFileSystem implements VirtualFileSystem {
|
||||||
@Unmanaged
|
@Unmanaged
|
||||||
public static native int homeDirectory(Address resultPtr);
|
public static native int homeDirectory(Address resultPtr);
|
||||||
|
|
||||||
|
@Import(name = "teavm_file_tempDirectory")
|
||||||
|
@Unmanaged
|
||||||
|
public static native int tempDirectory(Address resultPtr);
|
||||||
|
|
||||||
@Import(name = "teavm_file_workDirectory")
|
@Import(name = "teavm_file_workDirectory")
|
||||||
@Unmanaged
|
@Unmanaged
|
||||||
static native int workDirectory(Address resultPtr);
|
static native int workDirectory(Address resultPtr);
|
||||||
|
@ -170,4 +199,12 @@ public class CFileSystem implements VirtualFileSystem {
|
||||||
@Import(name = "teavm_file_write")
|
@Import(name = "teavm_file_write")
|
||||||
@Unmanaged
|
@Unmanaged
|
||||||
static native int write(long file, byte[] data, int offset, int count);
|
static native int write(long file, byte[] data, int offset, int count);
|
||||||
|
|
||||||
|
@Import(name = "teavm_file_isWindows")
|
||||||
|
@Unmanaged
|
||||||
|
static native boolean isWindowsNative();
|
||||||
|
|
||||||
|
@Import(name = "teavm_file_canonicalize")
|
||||||
|
@Unmanaged
|
||||||
|
static native int canonicalizeNative(char[] name, int nameSize, Address resultPtr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,4 +35,14 @@ public class InMemoryVirtualFileSystem implements VirtualFileSystem {
|
||||||
public void setUserDir(String userDir) {
|
public void setUserDir(String userDir) {
|
||||||
this.userDir = userDir;
|
this.userDir = userDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWindows() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String canonicalize(String path) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,10 +31,10 @@ import org.teavm.classlib.java.util.TRandom;
|
||||||
public class TFile implements Serializable, Comparable<TFile> {
|
public class TFile implements Serializable, Comparable<TFile> {
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
public static final char separatorChar = '/';
|
public static final char separatorChar = fs().isWindows() ? '\\' : '/';
|
||||||
public static final String separator = "/";
|
public static final String separator = String.valueOf(separatorChar);
|
||||||
public static final char pathSeparatorChar = ':';
|
public static final char pathSeparatorChar = fs().isWindows() ? ';' : ':';
|
||||||
public static final String pathSeparator = ":";
|
public static final String pathSeparator = String.valueOf(pathSeparatorChar);
|
||||||
|
|
||||||
private static int counter;
|
private static int counter;
|
||||||
|
|
||||||
|
@ -56,7 +56,13 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
public TFile(URI uri) {
|
public TFile(URI uri) {
|
||||||
// check pre-conditions
|
// check pre-conditions
|
||||||
checkURI(uri);
|
checkURI(uri);
|
||||||
this.path = fixSlashes(uri.getPath());
|
String path = uri.getPath();
|
||||||
|
if (fs().isWindows() && path.startsWith("/") && path.length() >= 4) {
|
||||||
|
if (isDriveLetter(path.charAt(1)) && path.charAt(2) == ':' && path.charAt(3) == '/') {
|
||||||
|
path = path.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.path = fixSlashes(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkURI(URI uri) {
|
private void checkURI(URI uri) {
|
||||||
|
@ -134,9 +140,8 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
if (path.charAt(0) != separatorChar) {
|
if (path.charAt(0) != separatorChar) {
|
||||||
result.append(separator);
|
result.append(separator);
|
||||||
}
|
}
|
||||||
} else if (path.charAt(0) == separatorChar) {
|
} if (fs().isWindows() && path.charAt(0) == separatorChar) {
|
||||||
result.append(result.substring(0, length - 2));
|
result.setLength(3);
|
||||||
|
|
||||||
}
|
}
|
||||||
result.append(path);
|
result.append(path);
|
||||||
|
|
||||||
|
@ -148,7 +153,22 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAbsolute() {
|
public boolean isAbsolute() {
|
||||||
return !path.isEmpty() && path.charAt(0) == separatorChar;
|
return isAbsolutePath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAbsolutePath(String path) {
|
||||||
|
if (fs().isWindows()) {
|
||||||
|
if (path.length() < 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isDriveLetter(path.charAt(0)) && path.charAt(1) == ':' && path.charAt(2) == '\\';
|
||||||
|
} else {
|
||||||
|
return !path.isEmpty() && path.charAt(0) == separatorChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isDriveLetter(char c) {
|
||||||
|
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDirectory() {
|
public boolean isDirectory() {
|
||||||
|
@ -166,7 +186,7 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCanonicalPath() throws IOException {
|
public String getCanonicalPath() throws IOException {
|
||||||
return getCanonicalPathImpl();
|
return fs().canonicalize(getCanonicalPathImpl());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCanonicalPathImpl() {
|
private String getCanonicalPathImpl() {
|
||||||
|
@ -179,7 +199,7 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int[] sepLocations = new int[numSeparators];
|
int[] sepLocations = new int[numSeparators];
|
||||||
int rootLoc = 0;
|
int rootLoc = fs().isWindows() ? 2 : 0;
|
||||||
char[] newResult = new char[result.length() + 1];
|
char[] newResult = new char[result.length() + 1];
|
||||||
int newLength = 0;
|
int newLength = 0;
|
||||||
int lastSlash = 0;
|
int lastSlash = 0;
|
||||||
|
@ -206,7 +226,7 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sepLocations[++lastSlash] = newLength;
|
sepLocations[++lastSlash] = newLength;
|
||||||
newResult[newLength++] = (byte) separatorChar;
|
newResult[newLength++] = separatorChar;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (result.charAt(i) == '.') {
|
if (result.charAt(i) == '.') {
|
||||||
|
@ -236,12 +256,11 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
|
|
||||||
public String getParent() {
|
public String getParent() {
|
||||||
int length = path.length();
|
int length = path.length();
|
||||||
int firstInPath = 0;
|
|
||||||
int index = path.lastIndexOf(separatorChar);
|
int index = path.lastIndexOf(separatorChar);
|
||||||
if (index == -1 || path.charAt(length - 1) == separatorChar) {
|
if (index == -1 || path.charAt(length - 1) == separatorChar) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (path.indexOf(separatorChar) == index && path.charAt(firstInPath) == separatorChar) {
|
if (path.indexOf(separatorChar) == index && (isAbsolutePath(path) || index == 0)) {
|
||||||
return path.substring(0, index + 1);
|
return path.substring(0, index + 1);
|
||||||
}
|
}
|
||||||
return path.substring(0, index);
|
return path.substring(0, index);
|
||||||
|
@ -392,13 +411,13 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
public boolean mkdirs() {
|
public boolean mkdirs() {
|
||||||
String path = getCanonicalPathImpl();
|
String path = getCanonicalPathImpl();
|
||||||
|
|
||||||
int i = path.indexOf('/');
|
int i = path.indexOf(separatorChar);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
while (i < path.length()) {
|
while (i < path.length()) {
|
||||||
int next = path.indexOf('/', i);
|
int next = path.indexOf(separatorChar, i);
|
||||||
if (next < 0) {
|
if (next < 0) {
|
||||||
next = path.length();
|
next = path.length();
|
||||||
}
|
}
|
||||||
|
@ -464,7 +483,7 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
// Directories must end with a slash
|
// Directories must end with a slash
|
||||||
name = new StringBuilder(name.length() + 1).append(name).append('/').toString();
|
name = new StringBuilder(name.length() + 1).append(name).append('/').toString();
|
||||||
}
|
}
|
||||||
if (separatorChar != '/') { // Must convert slashes.
|
if (fs().isWindows()) { // Must convert slashes.
|
||||||
name = name.replace(separatorChar, '/');
|
name = name.replace(separatorChar, '/');
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
|
@ -516,12 +535,14 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
if (!(obj instanceof TFile)) {
|
if (!(obj instanceof TFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return path.equals(((File) obj).getPath());
|
return fs().isWindows()
|
||||||
|
? path.equalsIgnoreCase(((File) obj).getPath())
|
||||||
|
: path.equals(((File) obj).getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return path.hashCode();
|
return fs().isWindows() ? path.toLowerCase().hashCode() : path.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -534,11 +555,18 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
int length = origPath.length();
|
int length = origPath.length();
|
||||||
int newLength = 0;
|
int newLength = 0;
|
||||||
|
|
||||||
|
if (fs().isWindows() && length == 3) {
|
||||||
|
if (isDriveLetter(origPath.charAt(0)) && origPath.charAt(1) == ':'
|
||||||
|
&& (origPath.charAt(2) == '/' || origPath.charAt(2) == '\\')) {
|
||||||
|
return origPath.substring(0, 2) + "\\";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
boolean foundSlash = false;
|
boolean foundSlash = false;
|
||||||
char[] newPath = origPath.toCharArray();
|
char[] newPath = origPath.toCharArray();
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
char pathChar = newPath[i];
|
char pathChar = newPath[i];
|
||||||
if (pathChar == '/') {
|
if (pathChar == '/' || pathChar == separatorChar) {
|
||||||
if (!foundSlash || i == uncIndex) {
|
if (!foundSlash || i == uncIndex) {
|
||||||
newPath[newLength++] = separatorChar;
|
newPath[newLength++] = separatorChar;
|
||||||
foundSlash = true;
|
foundSlash = true;
|
||||||
|
@ -548,7 +576,7 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
foundSlash = false;
|
foundSlash = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (foundSlash && (newLength > uncIndex + 1 || newLength == 2 && newPath[0] != separatorChar)) {
|
if (foundSlash && (newLength > uncIndex + 1 || newLength == 2 && newPath[0] != '/')) {
|
||||||
newLength--;
|
newLength--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,4 +616,12 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
}
|
}
|
||||||
return new TFile(path).getParentFile().findVirtualFile();
|
return new TFile(path).getParentFile().findVirtualFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isRoot(String path) {
|
||||||
|
if (fs().isWindows()) {
|
||||||
|
return path.length() == 3 && isAbsolutePath(path);
|
||||||
|
} else {
|
||||||
|
return path.equals("/");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,9 @@ public class TFileInputStream extends InputStream {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
|
if (accessor != null) {
|
||||||
|
accessor.close();
|
||||||
|
}
|
||||||
accessor = null;
|
accessor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Enumeration;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||||
import org.teavm.classlib.PlatformDetector;
|
import org.teavm.classlib.PlatformDetector;
|
||||||
|
import org.teavm.classlib.fs.VirtualFileSystemProvider;
|
||||||
import org.teavm.classlib.fs.c.CFileSystem;
|
import org.teavm.classlib.fs.c.CFileSystem;
|
||||||
import org.teavm.classlib.impl.c.Memory;
|
import org.teavm.classlib.impl.c.Memory;
|
||||||
import org.teavm.classlib.java.io.TConsole;
|
import org.teavm.classlib.java.io.TConsole;
|
||||||
|
@ -154,13 +155,22 @@ public final class TSystem extends TObject {
|
||||||
defaults.put("file.separator", "/");
|
defaults.put("file.separator", "/");
|
||||||
defaults.put("path.separator", ":");
|
defaults.put("path.separator", ":");
|
||||||
defaults.put("line.separator", lineSeparator());
|
defaults.put("line.separator", lineSeparator());
|
||||||
defaults.put("java.io.tmpdir", "/tmp");
|
defaults.put("java.io.tmpdir", getTempDir());
|
||||||
defaults.put("java.vm.version", "1.8");
|
defaults.put("java.vm.version", "1.8");
|
||||||
defaults.put("user.home", getHomeDir());
|
defaults.put("user.home", getHomeDir());
|
||||||
properties = new Properties(defaults);
|
properties = new Properties(defaults);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getTempDir() {
|
||||||
|
if (!PlatformDetector.isC()) {
|
||||||
|
return "/tmp";
|
||||||
|
}
|
||||||
|
Address resultPtr = Memory.malloc(Address.sizeOf());
|
||||||
|
int length = CFileSystem.tempDirectory(resultPtr);
|
||||||
|
return VirtualFileSystemProvider.getInstance().canonicalize(toJavaString(resultPtr, length));
|
||||||
|
}
|
||||||
|
|
||||||
private static String getHomeDir() {
|
private static String getHomeDir() {
|
||||||
if (!PlatformDetector.isC()) {
|
if (!PlatformDetector.isC()) {
|
||||||
return "/";
|
return "/";
|
||||||
|
@ -168,6 +178,10 @@ public final class TSystem extends TObject {
|
||||||
|
|
||||||
Address resultPtr = Memory.malloc(Address.sizeOf());
|
Address resultPtr = Memory.malloc(Address.sizeOf());
|
||||||
int length = CFileSystem.homeDirectory(resultPtr);
|
int length = CFileSystem.homeDirectory(resultPtr);
|
||||||
|
return VirtualFileSystemProvider.getInstance().canonicalize(toJavaString(resultPtr, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toJavaString(Address resultPtr, int length) {
|
||||||
Address result = resultPtr.getAddress();
|
Address result = resultPtr.getAddress();
|
||||||
Memory.free(resultPtr);
|
Memory.free(resultPtr);
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,8 @@ public final class CodeGeneratorUtil {
|
||||||
}
|
}
|
||||||
} else if (value instanceof Boolean) {
|
} else if (value instanceof Boolean) {
|
||||||
writer.print((Boolean) value ? "1" : "0");
|
writer.print((Boolean) value ? "1" : "0");
|
||||||
|
} else if (value instanceof Character) {
|
||||||
|
writeIntValue(writer, (char) value);
|
||||||
} else if (value instanceof ValueType) {
|
} else if (value instanceof ValueType) {
|
||||||
includes.includeType((ValueType) value);
|
includes.includeType((ValueType) value);
|
||||||
writer.print("&").print(context.getNames().forClassInstance((ValueType) value));
|
writer.print("&").print(context.getNames().forClassInstance((ValueType) value));
|
||||||
|
|
|
@ -58,6 +58,17 @@ int32_t teavm_file_workDirectory(char16_t** result) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_tempDirectory(char16_t** result) {
|
||||||
|
static const char16_t tmp[] = u"/tmp";
|
||||||
|
*result = malloc(sizeof(tmp));
|
||||||
|
int32_t i = 0;
|
||||||
|
while (string[i] != 0) {
|
||||||
|
copy[i] = string[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t teavm_file_isFile(char16_t* name, int32_t nameSize) {
|
int32_t teavm_file_isFile(char16_t* name, int32_t nameSize) {
|
||||||
struct stat s;
|
struct stat s;
|
||||||
char* mbName = teavm_char16ToMb(name, nameSize);
|
char* mbName = teavm_char16ToMb(name, nameSize);
|
||||||
|
@ -306,4 +317,318 @@ int32_t teavm_file_write(int64_t file, int8_t* data, int32_t offset, int32_t siz
|
||||||
return (int32_t) fwrite(data + offset, 1, size, handle);
|
return (int32_t) fwrite(data + offset, 1, size, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
int32_t teavm_file_isWindows() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_canonicalize(char16_t* path, int32_t pathSize, char16_t** result) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
static int32_t teavm_readEnv(char16_t** result, WCHAR const * name) {
|
||||||
|
DWORD size = GetEnvironmentVariableW(name, 0, 0);
|
||||||
|
char16_t *javaChars = size ? malloc(sizeof(char16_t) * size) : 0;
|
||||||
|
*result = javaChars;
|
||||||
|
return size ? GetEnvironmentVariableW(name, javaChars, size) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_homeDirectory(char16_t** result) {
|
||||||
|
return teavm_readEnv(result, L"USERPROFILE");
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_tempDirectory(char16_t** result) {
|
||||||
|
return teavm_readEnv(result, L"TMP");
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_workDirectory(char16_t** result) {
|
||||||
|
DWORD size = GetCurrentDirectoryW(0, 0);
|
||||||
|
char16_t *javaChars = malloc(sizeof(char16_t) * size);
|
||||||
|
*result = javaChars;
|
||||||
|
return GetCurrentDirectoryW(size, javaChars);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WCHAR* teavm_file_convertPath(char16_t* string, int32_t size) {
|
||||||
|
WCHAR *copy = malloc(sizeof(WCHAR) * (size + 1));
|
||||||
|
for (size_t i = 0; i != size; i++) {
|
||||||
|
char16_t c = string[i];
|
||||||
|
copy[i] = c == '/' ? '\\' : c;
|
||||||
|
}
|
||||||
|
copy[size] = 0;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD teavm_file_getAttributes(char16_t* name, int32_t nameSize) {
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
int attributes = GetFileAttributesW(nativeName);
|
||||||
|
free(nativeName);
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_isFile(char16_t* name, int32_t nameSize) {
|
||||||
|
DWORD attributes = teavm_file_getAttributes(name, nameSize);
|
||||||
|
return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_isDir(char16_t* name, int32_t nameSize) {
|
||||||
|
DWORD attributes = teavm_file_getAttributes(name, nameSize);
|
||||||
|
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t teavm_file_checkExistingFileAccess(char16_t* name, int32_t nameSize, DWORD desiredAccess) {
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
HANDLE fileHandle = CreateFileW(nativeName, desiredAccess, FILE_SHARE_READ, 0, OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
int32_t result = fileHandle != INVALID_HANDLE_VALUE;
|
||||||
|
if (fileHandle != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_canRead(char16_t* name, int32_t nameSize) {
|
||||||
|
return teavm_file_checkExistingFileAccess(name, nameSize, GENERIC_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_canWrite(char16_t* name, int32_t nameSize) {
|
||||||
|
return teavm_file_checkExistingFileAccess(name, nameSize, GENERIC_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_createDirectory(char16_t* name, int32_t nameSize) {
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
int32_t result = CreateDirectoryW(nativeName, NULL);
|
||||||
|
free(nativeName);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_createFile(char16_t* name, int32_t nameSize) {
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
HANDLE fileHandle = CreateFileW(nativeName, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
int32_t result = 2;
|
||||||
|
free(nativeName);
|
||||||
|
|
||||||
|
if (fileHandle != INVALID_HANDLE_VALUE) {
|
||||||
|
result = GetLastError() == ERROR_ALREADY_EXISTS ? 1 : 0;
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_delete(char16_t* name, int32_t nameSize) {
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
int attributes = GetFileAttributesW(nativeName);
|
||||||
|
int32_t result;
|
||||||
|
if (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||||
|
result = RemoveDirectoryW(nativeName);
|
||||||
|
} else {
|
||||||
|
result = DeleteFileW(nativeName);
|
||||||
|
}
|
||||||
|
free(nativeName);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_rename(char16_t* name, int32_t nameSize, char16_t* newName, int32_t newNameSize) {
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
WCHAR* nativeNewName = teavm_file_convertPath(newName, newNameSize);
|
||||||
|
int32_t result = MoveFileW(nativeName, nativeNewName);
|
||||||
|
free(nativeName);
|
||||||
|
free(nativeNewName);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_setReadonly(char16_t* name, int32_t nameSize, int32_t readonly) {
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
int attributes = GetFileAttributesW(nativeName);
|
||||||
|
if (attributes == INVALID_FILE_ATTRIBUTES) {
|
||||||
|
free(nativeName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (readonly) {
|
||||||
|
attributes |= FILE_ATTRIBUTE_READONLY;
|
||||||
|
} else {
|
||||||
|
attributes &= ~FILE_ATTRIBUTE_READONLY;
|
||||||
|
}
|
||||||
|
BOOL status = SetFileAttributesW(nativeName, attributes);
|
||||||
|
free(nativeName);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t teavm_file_lastModified(char16_t* name, int32_t nameSize) {
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
FILETIME modified;
|
||||||
|
HANDLE fileHandle = CreateFileW(nativeName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
free(nativeName);
|
||||||
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL status = GetFileTime(fileHandle, NULL, NULL, &modified);
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
|
||||||
|
if (!status) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int64_t t = modified.dwLowDateTime | ((uint64_t) modified.dwHighDateTime << 32);
|
||||||
|
return (t - teavm_unixTimeOffset) / 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_setLastModified(char16_t* name, int32_t nameSize, int64_t lastModified) {
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
|
||||||
|
HANDLE fileHandle = CreateFileW(nativeName, GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
free(nativeName);
|
||||||
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILETIME modified;
|
||||||
|
int64_t t = lastModified * 10000 + teavm_unixTimeOffset;
|
||||||
|
|
||||||
|
modified.dwLowDateTime = (DWORD) (t & 0xFFFFFFFF);
|
||||||
|
modified.dwHighDateTime = (DWORD) ((t >> 32) & 0xFFFFFFFF);
|
||||||
|
BOOL status = SetFileTime(fileHandle, NULL, NULL, &modified);
|
||||||
|
CloseHandle(fileHandle);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_length(char16_t* name, int32_t nameSize) {
|
||||||
|
WIN32_FILE_ATTRIBUTE_DATA fileAttributeData;
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
int attributes = GetFileAttributesExW(nativeName, GetFileExInfoStandard, &fileAttributeData);
|
||||||
|
free(nativeName);
|
||||||
|
return fileAttributeData.nFileSizeLow;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t teavm_file_open(char16_t* name, int32_t nameSize, int32_t mode) {
|
||||||
|
int32_t readable = (mode & 1) != 0;
|
||||||
|
int32_t writable = (mode & 2) != 0;
|
||||||
|
int32_t append = (mode & 4) != 0;
|
||||||
|
|
||||||
|
DWORD creationDisposition = writable ? OPEN_ALWAYS : OPEN_EXISTING;
|
||||||
|
DWORD desiredAccess = (readable ? GENERIC_READ : 0) | (writable ? GENERIC_WRITE : 0);
|
||||||
|
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
HANDLE fileHandle = CreateFileW(nativeName, desiredAccess, 0, 0, creationDisposition, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
free(nativeName);
|
||||||
|
|
||||||
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writable) {
|
||||||
|
if (append) {
|
||||||
|
SetFilePointer(fileHandle, 0, 0, FILE_END);
|
||||||
|
} else {
|
||||||
|
SetFilePointer(fileHandle, 0, 0, FILE_BEGIN);
|
||||||
|
SetEndOfFile(fileHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int64_t) fileHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_close(int64_t file) {
|
||||||
|
return file ? CloseHandle((HANDLE) file) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_flush(int64_t file) {
|
||||||
|
return FlushFileBuffers((HANDLE) file);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_seek(int64_t file, int32_t where, int32_t offset) {
|
||||||
|
return SetFilePointer((HANDLE) file, offset, 0, where);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_tell(int64_t file) {
|
||||||
|
return SetFilePointer((HANDLE) file, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_read(int64_t file, int8_t* data, int32_t offset, int32_t size) {
|
||||||
|
DWORD numRead = 0;
|
||||||
|
DWORD result = ReadFile((HANDLE) file, data + offset, size, &numRead, 0);
|
||||||
|
return result ? numRead : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_write(int64_t file, int8_t* data, int32_t offset, int32_t size) {
|
||||||
|
DWORD numWritten = 0;
|
||||||
|
DWORD result = WriteFile((HANDLE) file, data + offset, size, &numWritten, 0);
|
||||||
|
return result ? numWritten : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_isWindows() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TeaVM_StringList* teavm_file_addToList(TeaVM_StringList* strings, char16_t* data) {
|
||||||
|
int32_t size = wcslen(data);
|
||||||
|
WCHAR* copy = malloc(size * sizeof(char16_t));
|
||||||
|
memcpy(copy, data, size * sizeof(char16_t));
|
||||||
|
return teavm_appendString(strings, copy, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TeaVM_StringList* teavm_file_listFiles(char16_t* name, int32_t nameSize) {
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(name, nameSize);
|
||||||
|
WCHAR* pattern = malloc((nameSize + 3) * sizeof(WCHAR));
|
||||||
|
memcpy(pattern, nativeName, nameSize * sizeof(WCHAR));
|
||||||
|
free(nativeName);
|
||||||
|
pattern[nameSize] = '\\';
|
||||||
|
pattern[nameSize + 1] = '*';
|
||||||
|
pattern[nameSize + 2] = 0;
|
||||||
|
|
||||||
|
WIN32_FIND_DATAW fileData;
|
||||||
|
HANDLE handle = FindFirstFileW(pattern, &fileData);
|
||||||
|
free(pattern);
|
||||||
|
if (handle == INVALID_HANDLE_VALUE) {
|
||||||
|
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||||
|
return teavm_appendString(NULL, NULL, 0);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TeaVM_StringList *strings = teavm_appendString(NULL, NULL, 0);
|
||||||
|
strings = teavm_file_addToList(strings, fileData.cFileName);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
BOOL success = FindNextFileW(handle, &fileData);
|
||||||
|
if (!success) {
|
||||||
|
if (GetLastError() == ERROR_NO_MORE_FILES) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
teavm_disposeStringList(strings);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strings = teavm_file_addToList(strings, fileData.cFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
FindClose(handle);
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t teavm_file_canonicalize(char16_t* path, int32_t pathSize, char16_t** result) {
|
||||||
|
WCHAR* nativeName = teavm_file_convertPath(path, pathSize);
|
||||||
|
WCHAR buffer[256];
|
||||||
|
WCHAR* longBuffer;
|
||||||
|
DWORD actualSize = GetLongPathNameW(nativeName, buffer, 256);
|
||||||
|
longBuffer = malloc(sizeof(WCHAR) * actualSize);
|
||||||
|
if (actualSize == 0) {
|
||||||
|
free(nativeName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (actualSize >= 256) {
|
||||||
|
actualSize = GetLongPathNameW(nativeName, longBuffer, actualSize);
|
||||||
|
} else {
|
||||||
|
memcpy(longBuffer, buffer, actualSize * 2);
|
||||||
|
}
|
||||||
|
free(nativeName);
|
||||||
|
*result = longBuffer;
|
||||||
|
return actualSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -85,6 +85,16 @@ void teavm_beforeInit() {
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
teavm_queueTimer = CreateEvent(NULL, TRUE, FALSE, TEXT("TeaVM_eventQueue"));
|
teavm_queueTimer = CreateEvent(NULL, TRUE, FALSE, TEXT("TeaVM_eventQueue"));
|
||||||
|
|
||||||
|
SYSTEMTIME unixEpochStart = {
|
||||||
|
.wYear = 1970,
|
||||||
|
.wMonth = 1,
|
||||||
|
.wDayOfWeek = 3,
|
||||||
|
.wDay = 1
|
||||||
|
};
|
||||||
|
FILETIME fileTimeStart;
|
||||||
|
SystemTimeToFileTime(&unixEpochStart, &fileTimeStart);
|
||||||
|
teavm_unixTimeOffset = fileTimeStart.dwLowDateTime | ((uint64_t) fileTimeStart.dwHighDateTime << 32);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,30 +182,15 @@ void teavm_initHeap(int64_t heapSize) {
|
||||||
teavm_gc_availableBytes = heapSize;
|
teavm_gc_availableBytes = heapSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SYSTEMTIME teavm_unixEpochStart = {
|
int64_t teavm_unixTimeOffset;
|
||||||
.wYear = 1970,
|
|
||||||
.wMonth = 1,
|
|
||||||
.wDayOfWeek = 3,
|
|
||||||
.wDay = 1,
|
|
||||||
.wHour = 0,
|
|
||||||
.wMinute = 0,
|
|
||||||
.wSecond = 0,
|
|
||||||
.wMilliseconds = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
int64_t teavm_currentTimeMillis() {
|
int64_t teavm_currentTimeMillis() {
|
||||||
SYSTEMTIME time;
|
SYSTEMTIME time;
|
||||||
FILETIME fileTime;
|
FILETIME fileTime;
|
||||||
GetSystemTime(&time);
|
GetSystemTime(&time);
|
||||||
SystemTimeToFileTime(&time, &fileTime);
|
SystemTimeToFileTime(&time, &fileTime);
|
||||||
|
|
||||||
FILETIME fileTimeStart;
|
|
||||||
SystemTimeToFileTime(&teavm_unixEpochStart, &fileTimeStart);
|
|
||||||
|
|
||||||
uint64_t current = fileTime.dwLowDateTime | ((uint64_t) fileTime.dwHighDateTime << 32);
|
uint64_t current = fileTime.dwLowDateTime | ((uint64_t) fileTime.dwHighDateTime << 32);
|
||||||
uint64_t start = fileTimeStart.dwLowDateTime | ((uint64_t) fileTimeStart.dwHighDateTime << 32);
|
return (int64_t) ((current - teavm_unixTimeOffset) / 10000);
|
||||||
|
|
||||||
return (int64_t) ((current - start) / 10000);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -339,4 +339,9 @@ extern int32_t teavm_file_flush(int64_t);
|
||||||
extern int32_t teavm_file_seek(int64_t, int32_t, int32_t);
|
extern int32_t teavm_file_seek(int64_t, int32_t, int32_t);
|
||||||
extern int32_t teavm_file_tell(int64_t);
|
extern int32_t teavm_file_tell(int64_t);
|
||||||
extern int32_t teavm_file_read(int64_t, int8_t*, int32_t, int32_t);
|
extern int32_t teavm_file_read(int64_t, int8_t*, int32_t, int32_t);
|
||||||
extern int32_t teavm_file_write(int64_t, int8_t*, int32_t, int32_t);
|
extern int32_t teavm_file_write(int64_t, int8_t*, int32_t, int32_t);
|
||||||
|
extern int32_t teavm_file_isWindows();
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
extern int64_t teavm_unixTimeOffset;
|
||||||
|
#endif
|
|
@ -30,6 +30,8 @@ import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
@ -225,7 +227,7 @@ public class FileTest {
|
||||||
File file = new File(root, "/dir/file");
|
File file = new File(root, "/dir/file");
|
||||||
assertEquals("Assert 1: wrong path result ", path.getPath(), file.getPath());
|
assertEquals("Assert 1: wrong path result ", path.getPath(), file.getPath());
|
||||||
if (File.separatorChar == '\\') {
|
if (File.separatorChar == '\\') {
|
||||||
assertTrue("Assert 1.1: path not absolute ", new File("\\\\\\a\b").isAbsolute());
|
assertTrue("Assert 1.1: path not absolute ", new File("c:\\\\\\a\b").isAbsolute());
|
||||||
} else {
|
} else {
|
||||||
assertFalse("Assert 1.1: path absolute ", new File("\\\\\\a\b").isAbsolute());
|
assertFalse("Assert 1.1: path absolute ", new File("\\\\\\a\b").isAbsolute());
|
||||||
}
|
}
|
||||||
|
@ -474,23 +476,6 @@ public class FileTest {
|
||||||
|
|
||||||
// Test for creating a file that already exists.
|
// Test for creating a file that already exists.
|
||||||
assertFalse("File Already Exists, createNewFile Should Return False.", f2.createNewFile());
|
assertFalse("File Already Exists, createNewFile Should Return False.", f2.createNewFile());
|
||||||
|
|
||||||
// Test create an illegal file
|
|
||||||
String sep = File.separator;
|
|
||||||
f1 = new File(sep + "..");
|
|
||||||
try {
|
|
||||||
f1.createNewFile();
|
|
||||||
fail("should throw IOE");
|
|
||||||
} catch (IOException e) {
|
|
||||||
// expected;
|
|
||||||
}
|
|
||||||
f1 = new File(sep + "a" + sep + ".." + sep + ".." + sep);
|
|
||||||
try {
|
|
||||||
f1.createNewFile();
|
|
||||||
fail("should throw IOE");
|
|
||||||
} catch (IOException e) {
|
|
||||||
// expected;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -925,8 +910,6 @@ public class FileTest {
|
||||||
assertEquals("Wrong parent test 3a", "d:directory", f1.getParent());
|
assertEquals("Wrong parent test 3a", "d:directory", f1.getParent());
|
||||||
f1 = new File("d:/");
|
f1 = new File("d:/");
|
||||||
assertNull("Wrong parent test 4a", f1.getParent());
|
assertNull("Wrong parent test 4a", f1.getParent());
|
||||||
f1 = new File("d:directory");
|
|
||||||
assertEquals("Wrong parent test 5a", "d:", f1.getParent());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1029,11 +1012,6 @@ public class FileTest {
|
||||||
assertTrue(new File("f:\\").isAbsolute());
|
assertTrue(new File("f:\\").isAbsolute());
|
||||||
assertFalse(new File("f:").isAbsolute());
|
assertFalse(new File("f:").isAbsolute());
|
||||||
assertFalse(new File("K:").isAbsolute());
|
assertFalse(new File("K:").isAbsolute());
|
||||||
assertTrue(new File("\\\\").isAbsolute());
|
|
||||||
assertTrue(new File("\\\\\\").isAbsolute());
|
|
||||||
assertTrue(new File("\\\\hello").isAbsolute());
|
|
||||||
assertFalse(new File("\\").isAbsolute());
|
|
||||||
assertFalse(new File("/").isAbsolute());
|
|
||||||
} else {
|
} else {
|
||||||
File f = new File("/test");
|
File f = new File("/test");
|
||||||
File f1 = new File("\\test");
|
File f1 = new File("\\test");
|
||||||
|
@ -1092,10 +1070,6 @@ public class FileTest {
|
||||||
lastModifiedTime = f.lastModified();
|
lastModifiedTime = f.lastModified();
|
||||||
assertEquals("LastModified Time Incorrect", 315550800000L, lastModifiedTime);
|
assertEquals("LastModified Time Incorrect", 315550800000L, lastModifiedTime);
|
||||||
f.delete();
|
f.delete();
|
||||||
|
|
||||||
// Regression for HARMONY-2146
|
|
||||||
f = new File("/../");
|
|
||||||
assertTrue(f.lastModified() > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1143,7 +1117,8 @@ public class FileTest {
|
||||||
|
|
||||||
String[] files = { "mtzz1.xx", "mtzz2.xx", "mtzz3.yy", "mtzz4.yy" };
|
String[] files = { "mtzz1.xx", "mtzz2.xx", "mtzz3.yy", "mtzz4.yy" };
|
||||||
try {
|
try {
|
||||||
assertEquals("Method list() Should Have Returned An Array Of Length 0.", 0, dir.list().length);
|
assertEquals("Method list() Should Have Returned An Array Of Length 0.", Collections.emptyList(),
|
||||||
|
Arrays.asList(dir.list()));
|
||||||
|
|
||||||
File file = new File(dir, "notADir.tst");
|
File file = new File(dir, "notADir.tst");
|
||||||
try {
|
try {
|
||||||
|
@ -1254,7 +1229,6 @@ public class FileTest {
|
||||||
assertEquals("Incorrect Number Of Files Returned.", 3, flist.length);
|
assertEquals("Incorrect Number Of Files Returned.", 3, flist.length);
|
||||||
|
|
||||||
// Test to make sure that listFiles can read hidden files.
|
// Test to make sure that listFiles can read hidden files.
|
||||||
boolean onUnix = File.separatorChar == '/';
|
|
||||||
boolean onWindows = File.separatorChar == '\\';
|
boolean onWindows = File.separatorChar == '\\';
|
||||||
if (!isTeaVM() && onWindows) {
|
if (!isTeaVM() && onWindows) {
|
||||||
files[3] = "4.tst";
|
files[3] = "4.tst";
|
||||||
|
@ -1264,8 +1238,7 @@ public class FileTest {
|
||||||
Runtime r = Runtime.getRuntime();
|
Runtime r = Runtime.getRuntime();
|
||||||
Process p = r.exec("attrib +h \"" + f.getPath() + "\"");
|
Process p = r.exec("attrib +h \"" + f.getPath() + "\"");
|
||||||
p.waitFor();
|
p.waitFor();
|
||||||
}
|
} else {
|
||||||
if (onUnix) {
|
|
||||||
files[3] = ".4.tst";
|
files[3] = ".4.tst";
|
||||||
File f = new File(dir, ".4.tst");
|
File f = new File(dir, ".4.tst");
|
||||||
FileOutputStream fos = new FileOutputStream(f);
|
FileOutputStream fos = new FileOutputStream(f);
|
||||||
|
@ -1622,7 +1595,7 @@ public class FileTest {
|
||||||
StringBuilder sb2 = new StringBuilder(dir + File.separator);
|
StringBuilder sb2 = new StringBuilder(dir + File.separator);
|
||||||
|
|
||||||
// Test make a long path
|
// Test make a long path
|
||||||
while (dir.getCanonicalPath().length() < 256 - longDirName.length()) {
|
while (dir.getCanonicalPath().length() < 200 - longDirName.length()) {
|
||||||
sb.append(longDirName + File.separator);
|
sb.append(longDirName + File.separator);
|
||||||
dir = new File(sb.toString());
|
dir = new File(sb.toString());
|
||||||
assertTrue("mkdir failed", dir.mkdir());
|
assertTrue("mkdir failed", dir.mkdir());
|
||||||
|
@ -1630,16 +1603,16 @@ public class FileTest {
|
||||||
dir.deleteOnExit();
|
dir.deleteOnExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (dir.getCanonicalPath().length() < 256) {
|
while (dir.getCanonicalPath().length() < 200) {
|
||||||
sb.append(0);
|
sb.append(0);
|
||||||
dir = new File(sb.toString());
|
dir = new File(sb.toString());
|
||||||
assertTrue("mkdir " + dir.getCanonicalPath().length() + " failed", dir.mkdir());
|
assertTrue("mkdir " + dir.getCanonicalPath() + " failed", dir.mkdir());
|
||||||
assertTrue("mkdir " + dir.getCanonicalPath().length() + " worked but exists check failed", dir.exists());
|
assertTrue("mkdir " + dir.getCanonicalPath().length() + " worked but exists check failed", dir.exists());
|
||||||
dir.deleteOnExit();
|
dir.deleteOnExit();
|
||||||
}
|
}
|
||||||
dir = new File(sb2.toString());
|
dir = new File(sb2.toString());
|
||||||
// Test make many paths
|
// Test make many paths
|
||||||
while (dir.getCanonicalPath().length() < 256) {
|
while (dir.getCanonicalPath().length() < 200) {
|
||||||
sb2.append(0);
|
sb2.append(0);
|
||||||
dir = new File(sb2.toString());
|
dir = new File(sb2.toString());
|
||||||
assertTrue("mkdir " + dir.getCanonicalPath().length() + " failed", dir.mkdir());
|
assertTrue("mkdir " + dir.getCanonicalPath().length() + " failed", dir.mkdir());
|
||||||
|
@ -1776,7 +1749,7 @@ public class FileTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setReadOnly() throws IOException, InterruptedException {
|
public void setReadOnly() throws IOException {
|
||||||
File f1 = null;
|
File f1 = null;
|
||||||
File f2 = null;
|
File f2 = null;
|
||||||
try {
|
try {
|
||||||
|
@ -1794,7 +1767,6 @@ public class FileTest {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Expected
|
// Expected
|
||||||
}
|
}
|
||||||
Runtime r = Runtime.getRuntime();
|
|
||||||
|
|
||||||
// Assert is flawed because canWrite does not work.
|
// Assert is flawed because canWrite does not work.
|
||||||
// assertTrue("File f2 Is Set To ReadOnly." , f2.canWrite());
|
// assertTrue("File f2 Is Set To ReadOnly." , f2.canWrite());
|
||||||
|
@ -1815,14 +1787,16 @@ public class FileTest {
|
||||||
// Expected
|
// Expected
|
||||||
}
|
}
|
||||||
|
|
||||||
f2.setReadOnly();
|
if (File.separatorChar == '/') {
|
||||||
assertTrue("File f2 Did Not Delete", f2.delete());
|
f2.setReadOnly();
|
||||||
// Similarly, trying to delete a read-only directory should succeed
|
assertTrue("File f2 Did Not Delete", f2.delete());
|
||||||
f2 = new File(tempDirectory, "deltestdir");
|
// Similarly, trying to delete a read-only directory should succeed
|
||||||
f2.mkdir();
|
f2 = new File(tempDirectory, "deltestdir");
|
||||||
f2.setReadOnly();
|
f2.mkdir();
|
||||||
assertTrue("Directory f2 Did Not Delete", f2.delete());
|
f2.setReadOnly();
|
||||||
assertTrue("Directory f2 Did Not Delete", !f2.exists());
|
assertTrue("Directory f2 Did Not Delete", f2.delete());
|
||||||
|
assertTrue("Directory f2 Did Not Delete", !f2.exists());
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (f1 != null) {
|
if (f1 != null) {
|
||||||
f1.delete();
|
f1.delete();
|
||||||
|
|
|
@ -279,7 +279,6 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
||||||
success = runInJvm(child, notifier, expectedExceptions);
|
success = runInJvm(child, notifier, expectedExceptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (success && outputDir != null) {
|
if (success && outputDir != null) {
|
||||||
int[] configurationIndex = new int[] { 0 };
|
int[] configurationIndex = new int[] { 0 };
|
||||||
List<Consumer<Boolean>> onSuccess = new ArrayList<>();
|
List<Consumer<Boolean>> onSuccess = new ArrayList<>();
|
||||||
|
|
|
@ -38,7 +38,7 @@ class TestRunner {
|
||||||
public void init() {
|
public void init() {
|
||||||
latch = new CountDownLatch(numThreads);
|
latch = new CountDownLatch(numThreads);
|
||||||
for (int i = 0; i < numThreads; ++i) {
|
for (int i = 0; i < numThreads; ++i) {
|
||||||
new Thread(() -> {
|
Thread thread = new Thread(() -> {
|
||||||
strategy.beforeThread();
|
strategy.beforeThread();
|
||||||
while (!stopped || !taskQueue.isEmpty()) {
|
while (!stopped || !taskQueue.isEmpty()) {
|
||||||
Runnable task;
|
Runnable task;
|
||||||
|
@ -53,7 +53,10 @@ class TestRunner {
|
||||||
}
|
}
|
||||||
strategy.afterThread();
|
strategy.afterThread();
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}).start();
|
});
|
||||||
|
thread.setDaemon(true);
|
||||||
|
thread.setName("teavm-test-runner-" + i);
|
||||||
|
thread.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,4 +16,8 @@ file(GLOB_RECURSE CMAKE_BUILD_SOURCES ${CMAKE_BINARY_DIR}/**.c)
|
||||||
list(REMOVE_ITEM TEAVM_GEN_SOURCES ${PROJECT_SOURCE_DIR}/all.c ${CMAKE_BUILD_SOURCES})
|
list(REMOVE_ITEM TEAVM_GEN_SOURCES ${PROJECT_SOURCE_DIR}/all.c ${CMAKE_BUILD_SOURCES})
|
||||||
add_executable(run_test ${TEAVM_GEN_SOURCES})
|
add_executable(run_test ${TEAVM_GEN_SOURCES})
|
||||||
|
|
||||||
target_link_libraries(run_test m rt)
|
if (WIN32)
|
||||||
|
target_link_libraries(run_test)
|
||||||
|
else()
|
||||||
|
target_link_libraries(run_test m rt)
|
||||||
|
endif()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user