blob: 1f540ef13428c7afacb99ae9cc6a7331b6964d88 [file] [log] [blame] [edit]
package jnr.posix.windows;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.text.NumberFormat;
import jnr.posix.DummyPOSIXHandler;
import jnr.posix.FileStat;
import jnr.posix.POSIX;
import jnr.posix.POSIXFactory;
import jnr.posix.WindowsPOSIX;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class WindowsFileTest {
private static POSIX posix;
@BeforeClass
public static void setUpClass() throws Exception {
posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true);
}
private class Pair {
public File base;
public File leaf;
public Pair(File base, File leaf) {
this.base = base;
this.leaf = leaf;
}
public void cleanup() {
cleanup(base);
}
public void cleanup(File node) {
if (node.isDirectory()) {
File[] files = node.listFiles();
if (files != null) {
for(File file: files) {
cleanup(file);
}
}
}
node.delete();
}
}
// FIXME: This is a broken method since it does not delete any of the generated dirs.
private static final String DIR_NAME = "0123456789";
private Pair makeLongPath() throws IOException {
File tmp = Files.createTempDirectory("temp" + Long.toHexString(System.nanoTime())).toFile();
StringBuilder buf = new StringBuilder(DIR_NAME);
for (int i = 0; i < 30; i++) {
buf.append(DIR_NAME).append('/');
}
File tmp2 = new File(tmp, buf.toString());
tmp2.mkdirs();
return new Pair(tmp, tmp2);
}
@Test
public void testLowercaseDriveLetter() throws Throwable {
// FIXME: Not all systems have a C drive but nearly all do
FileStat st = posix.stat("c:/");
assertTrue(st.dev() == 2);
assertTrue(st.rdev() == 2);
}
@Test
public void testFakeUIDGUID() throws Throwable {
File f = File.createTempFile("stat", null);
try {
FileStat st = posix.stat(f.getAbsolutePath());
assertTrue(st.uid() == 0);
assertTrue(st.gid() == 0);
} finally {
f.delete();
}
}
@Test
public void testExecutableSuffixesAreExecutable() throws Throwable {
File f = File.createTempFile("stat", ".exe");
try {
FileStat st = posix.stat(f.getAbsolutePath());
assertEquals("100755", Integer.toOctalString(st.mode()));
assertTrue(st.isExecutable());
} finally {
f.delete();
}
f = File.createTempFile("STAT", ".EXE");
try {
FileStat st = posix.stat(f.getAbsolutePath());
assertEquals("100755", Integer.toOctalString(st.mode()));
assertTrue(st.isExecutable());
} finally {
f.delete();
}
}
@Test
public void testBlocksAndBlockSizeReturn() throws Throwable {
File f = File.createTempFile("stat", null);
try {
FileStat st = posix.stat(f.getAbsolutePath());
assertTrue(st.blocks() == -1);
assertTrue(st.blockSize() == -1);
} finally {
f.delete();
}
}
@Test
public void testLongFileRegular() throws Throwable {
Pair pair = makeLongPath();
String path = pair.leaf.getAbsolutePath();
try {
FileStat st = posix.stat(path);
assertNotNull("posix.stat failed", st);
FileStat stat = posix.allocateStat();
int result = posix.stat(path, stat);
assertNotNull("posix.stat failed", stat);
assertEquals(0, result);
} finally {
pair.cleanup();
}
}
@Test
public void testLongFileUNC() throws Throwable {
Pair pair = makeLongPath();
String absolutePath = pair.leaf.getAbsolutePath();
char letter = absolutePath.charAt(0);
String path = absolutePath.replace(absolutePath.substring(0,2), "\\\\localhost\\" + letter + "$");
try {
FileStat st = posix.stat(path);
assertNotNull("posix.stat failed", st);
FileStat stat = posix.allocateStat();
int result = posix.stat(path, stat);
assertNotNull("posix.stat failed", stat);
assertEquals(0, result);
} finally {
pair.cleanup();
}
}
@Test
public void statUNCFile() throws Throwable {
File f = File.createTempFile("stat", null);
String absolutePath = f.getAbsolutePath();
char letter = absolutePath.charAt(0);
String path = absolutePath.replace(absolutePath.substring(0,2), "\\\\localhost\\" + letter + "$");
try {
FileStat st = posix.stat(path);
assertNotNull("posix.stat failed", st);
FileStat stat = posix.allocateStat();
int result = posix.stat(path, stat);
assertNotNull("posix.stat failed", stat);
assertEquals(0, result);
} finally {
f.delete();
}
}
@Test
public void unlinkTestWindows() throws Throwable {
File tmp = File.createTempFile("unlinkTest", "tmp");
RandomAccessFile raf = new RandomAccessFile(tmp, "rw");
raf.write("hello".getBytes());
// Windows won't allow you to delete open files, so we must
// close the handle before trying to delete it. Unfortunately,
// this also means we're unable to write to the handle afterwards
// as we do with the non-Windows test.
raf.close();
int res = posix.unlink(tmp.getCanonicalPath());
assertEquals(0, res);
assertFalse(tmp.exists());
}
@Test
public void testFindFirstFile() throws Throwable {
File f = File.createTempFile("stat", null);
try {
POSIX posix = POSIXFactory.getNativePOSIX();
FileStat stat = posix.allocateStat();
int result = ((WindowsPOSIX) posix).findFirstFile(f.getAbsolutePath(), stat);
assertEquals(0, result);
assertTrue(stat.isFile());
} finally {
f.delete();
}
}
@Test
public void testFindFirstFileBogusFile() throws Throwable {
POSIX posix = POSIXFactory.getNativePOSIX();
FileStat stat = posix.allocateStat();
int result = ((WindowsPOSIX) posix).findFirstFile("sdjfhjfsdfhdsdfhsdj", stat);
assertTrue(result < 0);
}
@Test
public void utimensatWindows() throws Throwable {
File file = File.createTempFile("utimensat", null);
try {
FileStat fileStat = posix.stat(file.getPath());
long atimeSeconds = fileStat.atime() + 1;
long mtimeSeconds = fileStat.mtime() - 1;
// Windows precision is 100 ns
long atimeNanoSeconds = 123456700;
long mtimeNanoSeconds = 987654300;
// dirfd is ignored when passing an absolute path
// flag can be used to update symlinks
posix.utimensat(0,
file.getAbsolutePath(),
new long[]{atimeSeconds, atimeNanoSeconds},
new long[]{mtimeSeconds, mtimeNanoSeconds},
0);
fileStat = posix.stat(file.getPath());
assertEquals("access time should be updated", atimeSeconds, fileStat.atime());
assertEquals("modification time should be updated", mtimeSeconds, fileStat.mtime());
} finally {
file.delete();
}
}
@Test
public void utimensatWindowsCurrentTime() throws Throwable {
File file = File.createTempFile("file", null);
try {
FileStat fileStat = posix.stat(file.getPath());
long atimeSeconds = fileStat.atime();
long mtimeSeconds = fileStat.mtime();
long atimeSecondsInPast = atimeSeconds - 1000;
long mtimeSecondsInPast = mtimeSeconds - 1000;
posix.utimensat(0,
file.getAbsolutePath(),
new long[]{atimeSecondsInPast, 0},
new long[]{mtimeSecondsInPast, 0}, 0);
fileStat = posix.stat(file.getPath());
assertEquals("access time should be updated", fileStat.atime(), atimeSecondsInPast);
assertEquals("modification time should be updated", fileStat.mtime(), mtimeSecondsInPast);
posix.utimensat(0, file.getAbsolutePath(), null, null, 0);
fileStat = posix.stat(file.getPath());
assertTrue("access time should be updated to current time",
timeWithinRange(fileStat.atime(), atimeSeconds, 10));
assertTrue("modification time should be updated to current time",
timeWithinRange(fileStat.mtime(), mtimeSeconds, 10));
} finally {
file.delete();
}
}
@Test
public void utimenWindowsCurrentTime() throws Throwable {
File file = File.createTempFile("file", null);
try {
FileStat fileStat = posix.stat(file.getPath());
long atimeSeconds = fileStat.atime();
long mtimeSeconds = fileStat.mtime();
long atimeSecondsInPast = atimeSeconds - 1000;
long mtimeSecondsInPast = mtimeSeconds - 1000;
posix.utimes(file.getAbsolutePath(),
new long[]{atimeSecondsInPast, 0},
new long[]{mtimeSecondsInPast, 0});
fileStat = posix.stat(file.getPath());
assertEquals("access time should be updated",
fileStat.atime(), atimeSecondsInPast);
assertEquals("modification time should be updated",
fileStat.mtime(), mtimeSecondsInPast);
posix.utimes(file.getAbsolutePath(), null, null);
fileStat = posix.stat(file.getPath());
assertTrue("access time should be updated to current time",
timeWithinRange(fileStat.atime(), atimeSeconds, 10));
assertTrue("modification time should be updated to current time",
timeWithinRange(fileStat.mtime(), mtimeSeconds, 10));
} finally {
file.delete();
}
}
private boolean timeWithinRange(long actual, long expected, long precision) {
return actual > (expected - precision) && actual < (expected + precision);
}
}