Make UnixFileSystem Y2K38-ready.
In addition to being unable to represent Unix times that don't fit an int, the current storage format is unnecessarily complex. Instead, use a single long field with milliseconds since the Unix epoch, which takes up the same amount of space but is safe for the next ~200 million years.
PiperOrigin-RevId: 680948657
Change-Id: I84546f3463ed5a174c0ebd34e6bb4d4fe9bdbdaa
diff --git a/src/main/java/com/google/devtools/build/lib/unix/FileStatus.java b/src/main/java/com/google/devtools/build/lib/unix/FileStatus.java
index 3182e2e..e21f280 100644
--- a/src/main/java/com/google/devtools/build/lib/unix/FileStatus.java
+++ b/src/main/java/com/google/devtools/build/lib/unix/FileStatus.java
@@ -14,57 +14,43 @@
package com.google.devtools.build.lib.unix;
/**
- * <p>Equivalent to UNIX's "struct stat", a FileStatus instance contains
- * various bits of metadata about a directory entry.
+ * Equivalent to UNIX's "struct stat", a FileStatus instance contains various bits of metadata about
+ * a directory entry.
*
- * <p>The Java SDK provides access to some but not all of the information
- * available via the stat(2) and lstat(2) syscalls, but often requires that
- * multiple calls be made to obtain it. By reifying stat buffers as Java
- * objects and providing a wrapper around the stat/lstat calls, we give client
- * applications access to the richer file metadata and enable a reduction in
- * the number of system calls, which is critical for high-performance tools.
+ * <p>The Java SDK provides access to some but not all of the information available via the stat(2)
+ * and lstat(2) syscalls, but often requires that multiple calls be made to obtain it. By reifying
+ * stat buffers as Java objects and providing a wrapper around the stat/lstat calls, we give client
+ * applications access to the richer file metadata and enable a reduction in the number of system
+ * calls, which is critical for high-performance tools.
*
- * <p>This class is optimized for memory usage. Operations that are not yet
- * required for any client are intentionally unimplemented to save space.
- * Currently, we only support these fields: st_mode, st_size, st_atime,
- * st_atimensec, st_mtime, st_mtimensec, st_ctime, st_ctimensec, st_dev, st_ino.
- * Methods that require other fields throw UnsupportedOperationException.
+ * <p>This class is optimized for memory usage. Fields not required by Bazel are omitted.
*/
public class FileStatus {
- private final int st_mode;
- private final int st_atime; // (unsigned)
- private final int st_atimensec; // (unsigned)
- private final int st_mtime; // (unsigned)
- private final int st_mtimensec; // (unsigned)
- private final int st_ctime; // (unsigned)
- private final int st_ctimensec; // (unsigned)
- private final long st_size;
- private final int st_dev;
- private final long st_ino;
+ private final int mode;
+ private final long atime; // milliseconds since Unix epoch
+ private final long mtime; // milliseconds since Unix epoch
+ private final long ctime; // milliseconds since Unix epoch
+ private final long size;
+ private final int dev;
+ private final long ino;
- /**
- * Constructs a FileStatus instance. (Called only from JNI code.)
- */
- protected FileStatus(int st_mode, int st_atime, int st_atimensec, int st_mtime, int st_mtimensec,
- int st_ctime, int st_ctimensec, long st_size, int st_dev, long st_ino) {
- this.st_mode = st_mode;
- this.st_atime = st_atime;
- this.st_atimensec = st_atimensec;
- this.st_mtime = st_mtime;
- this.st_mtimensec = st_mtimensec;
- this.st_ctime = st_ctime;
- this.st_ctimensec = st_ctimensec;
- this.st_size = st_size;
- this.st_dev = st_dev;
- this.st_ino = st_ino;
+ /** Constructs a FileStatus instance. (Called only from ErrnoFileStatus and JNI code.) */
+ protected FileStatus(int mode, long atime, long mtime, long ctime, long size, int dev, long ino) {
+ this.mode = mode;
+ this.atime = atime;
+ this.mtime = mtime;
+ this.ctime = ctime;
+ this.size = size;
+ this.dev = dev;
+ this.ino = ino;
}
/**
* Returns the device number of this inode.
*/
public int getDeviceNumber() {
- return st_dev;
+ return dev;
}
/**
@@ -72,19 +58,19 @@
* a given device.
*/
public long getInodeNumber() {
- return st_ino;
+ return ino;
}
/**
* Returns true iff this file is a regular file.
*/
public boolean isRegularFile() {
- return (st_mode & S_IFMT) == S_IFREG;
+ return (mode & S_IFMT) == S_IFREG;
}
/** Returns true iff this file is a directory. */
public boolean isDirectory() {
- return (st_mode & S_IFMT) == S_IFDIR;
+ return (mode & S_IFMT) == S_IFDIR;
}
public static boolean isDirectory(int rawType) {
@@ -94,7 +80,7 @@
/** Returns true iff this file is a symbolic link. */
public boolean isSymbolicLink() {
- return (st_mode & S_IFMT) == S_IFLNK;
+ return (mode & S_IFMT) == S_IFLNK;
}
public static boolean isSymbolicLink(int rawType) {
@@ -106,42 +92,40 @@
* Returns true iff this file is a character device.
*/
public boolean isCharacterDevice() {
- return (st_mode & S_IFMT) == S_IFCHR;
+ return (mode & S_IFMT) == S_IFCHR;
}
/**
* Returns true iff this file is a block device.
*/
public boolean isBlockDevice() {
- return (st_mode & S_IFMT) == S_IFBLK;
+ return (mode & S_IFMT) == S_IFBLK;
}
- /**
- * Returns true iff this file is a FIFO.
- */
- public boolean isFIFO() {
- return (st_mode & S_IFMT) == S_IFIFO;
+ /** Returns true iff this file is a FIFO. */
+ public boolean isFifo() {
+ return (mode & S_IFMT) == S_IFIFO;
}
/**
* Returns true iff this file is a UNIX-domain socket.
*/
public boolean isSocket() {
- return (st_mode & S_IFMT) == S_IFSOCK;
+ return (mode & S_IFMT) == S_IFSOCK;
}
/**
* Returns true iff this file has its "set UID" bit set.
*/
public boolean isSetUserId() {
- return (st_mode & S_ISUID) != 0;
+ return (mode & S_ISUID) != 0;
}
/**
* Returns true iff this file has its "set GID" bit set.
*/
public boolean isSetGroupId() {
- return (st_mode & S_ISGID) != 0;
+ return (mode & S_ISGID) != 0;
}
/**
@@ -149,78 +133,46 @@
* explanation.
*/
public boolean isSticky() {
- return (st_mode & S_ISVTX) != 0;
+ return (mode & S_ISVTX) != 0;
}
/**
- * Returns the user/group/other permissions part of the mode bits (i.e.
- * st_mode masked with 0777), interpreted according to longstanding UNIX
- * tradition.
+ * Returns the user/group/other permissions part of the mode bits (i.e. mode masked with 0777),
+ * interpreted according to longstanding UNIX tradition.
*/
public int getPermissions() {
- return st_mode & S_IRWXA;
+ return mode & S_IRWXA;
}
/**
* Returns the total size, in bytes, of this file.
*/
public long getSize() {
- return st_size;
+ return size;
}
- /**
- * Returns the last access time of this file (seconds since UNIX epoch).
- */
+ /** Returns the last access time of this file (milliseconds since UNIX epoch). */
public long getLastAccessTime() {
- return unsignedIntToLong(st_atime);
+ return atime;
}
- /**
- * Returns the fractional part of the last access time of this file (nanoseconds).
- */
- public long getFractionalLastAccessTime() {
- return unsignedIntToLong(st_atimensec);
- }
-
- /**
- * Returns the last modified time of this file (seconds since UNIX epoch).
- */
+ /** Returns the last modified time of this file (milliseconds since UNIX epoch). */
public long getLastModifiedTime() {
- return unsignedIntToLong(st_mtime);
+ return mtime;
}
- /**
- * Returns the fractional part of the last modified time of this file (nanoseconds).
- */
- public long getFractionalLastModifiedTime() {
- return unsignedIntToLong(st_mtimensec);
- }
-
- /**
- * Returns the last change time of this file (seconds since UNIX epoch).
- */
+ /** Returns the last change time of this file (milliseconds since UNIX epoch). */
public long getLastChangeTime() {
- return unsignedIntToLong(st_ctime);
- }
-
- /**
- * Returns the fractional part of the last change time of this file (nanoseconds).
- */
- public long getFractionalLastChangeTime() {
- return unsignedIntToLong(st_ctimensec);
+ return ctime;
}
////////////////////////////////////////////////////////////////////////
@Override
public String toString() {
- return String.format("FileStatus(mode=0%06o,size=%d,mtime=%d)",
- st_mode, st_size, st_mtime);
- }
-
- @Override
- public int hashCode() {
- return st_mode;
+ return String.format(
+ "FileStatus(mode=0%06o,atime=%d,mtime=%d,ctime=%d,size=%d,device=%d,ino=%d)",
+ mode, atime, mtime, ctime, size, dev, ino);
}
////////////////////////////////////////////////////////////////////////
@@ -261,10 +213,6 @@
public static final int S_IEXEC = 00111; // owner, group, world execute
- static long unsignedIntToLong(int i) {
- return (i & 0x7FFFFFFF) - (long) (i & 0x80000000);
- }
-
public static boolean isFile(int rawType) {
int type = rawType & S_IFMT;
return type == S_IFREG || isSpecialFile(rawType);