Damien Martin-Guillerez | f88f4d8 | 2015-09-25 13:56:55 +0000 | [diff] [blame] | 1 | // Copyright 2014 The Bazel Authors. All rights reserved. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | package com.google.devtools.build.lib.unix; |
| 15 | |
| 16 | /** |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 17 | * Equivalent to UNIX's "struct stat", a FileStatus instance contains various bits of metadata about |
| 18 | * a directory entry. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 19 | * |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 20 | * <p>The Java SDK provides access to some but not all of the information available via the stat(2) |
| 21 | * and lstat(2) syscalls, but often requires that multiple calls be made to obtain it. By reifying |
| 22 | * stat buffers as Java objects and providing a wrapper around the stat/lstat calls, we give client |
| 23 | * applications access to the richer file metadata and enable a reduction in the number of system |
| 24 | * calls, which is critical for high-performance tools. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 25 | * |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 26 | * <p>This class is optimized for memory usage. Fields not required by Bazel are omitted. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 27 | */ |
| 28 | public class FileStatus { |
| 29 | |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 30 | private final int mode; |
| 31 | private final long atime; // milliseconds since Unix epoch |
| 32 | private final long mtime; // milliseconds since Unix epoch |
| 33 | private final long ctime; // milliseconds since Unix epoch |
| 34 | private final long size; |
| 35 | private final int dev; |
| 36 | private final long ino; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 37 | |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 38 | /** Constructs a FileStatus instance. (Called only from ErrnoFileStatus and JNI code.) */ |
| 39 | protected FileStatus(int mode, long atime, long mtime, long ctime, long size, int dev, long ino) { |
| 40 | this.mode = mode; |
| 41 | this.atime = atime; |
| 42 | this.mtime = mtime; |
| 43 | this.ctime = ctime; |
| 44 | this.size = size; |
| 45 | this.dev = dev; |
| 46 | this.ino = ino; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | /** |
| 50 | * Returns the device number of this inode. |
| 51 | */ |
| 52 | public int getDeviceNumber() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 53 | return dev; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 54 | } |
| 55 | |
| 56 | /** |
| 57 | * Returns the number of this inode. Inode numbers are (usually) unique for |
| 58 | * a given device. |
| 59 | */ |
| 60 | public long getInodeNumber() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 61 | return ino; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 62 | } |
| 63 | |
| 64 | /** |
| 65 | * Returns true iff this file is a regular file. |
| 66 | */ |
| 67 | public boolean isRegularFile() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 68 | return (mode & S_IFMT) == S_IFREG; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 69 | } |
| 70 | |
Googler | f815bf0 | 2022-03-09 12:44:59 -0800 | [diff] [blame] | 71 | /** Returns true iff this file is a directory. */ |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 72 | public boolean isDirectory() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 73 | return (mode & S_IFMT) == S_IFDIR; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 74 | } |
| 75 | |
Googler | f815bf0 | 2022-03-09 12:44:59 -0800 | [diff] [blame] | 76 | public static boolean isDirectory(int rawType) { |
| 77 | int type = rawType & S_IFMT; |
| 78 | return type == S_IFDIR; |
| 79 | } |
| 80 | |
| 81 | /** Returns true iff this file is a symbolic link. */ |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 82 | public boolean isSymbolicLink() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 83 | return (mode & S_IFMT) == S_IFLNK; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 84 | } |
| 85 | |
Googler | f815bf0 | 2022-03-09 12:44:59 -0800 | [diff] [blame] | 86 | public static boolean isSymbolicLink(int rawType) { |
| 87 | int type = rawType & S_IFMT; |
| 88 | return type == S_IFLNK; |
| 89 | } |
| 90 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 91 | /** |
| 92 | * Returns true iff this file is a character device. |
| 93 | */ |
| 94 | public boolean isCharacterDevice() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 95 | return (mode & S_IFMT) == S_IFCHR; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 96 | } |
| 97 | |
| 98 | /** |
| 99 | * Returns true iff this file is a block device. |
| 100 | */ |
| 101 | public boolean isBlockDevice() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 102 | return (mode & S_IFMT) == S_IFBLK; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 103 | } |
| 104 | |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 105 | /** Returns true iff this file is a FIFO. */ |
| 106 | public boolean isFifo() { |
| 107 | return (mode & S_IFMT) == S_IFIFO; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | /** |
| 111 | * Returns true iff this file is a UNIX-domain socket. |
| 112 | */ |
| 113 | public boolean isSocket() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 114 | return (mode & S_IFMT) == S_IFSOCK; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 115 | } |
| 116 | |
| 117 | /** |
| 118 | * Returns true iff this file has its "set UID" bit set. |
| 119 | */ |
| 120 | public boolean isSetUserId() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 121 | return (mode & S_ISUID) != 0; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 122 | } |
| 123 | |
| 124 | /** |
| 125 | * Returns true iff this file has its "set GID" bit set. |
| 126 | */ |
| 127 | public boolean isSetGroupId() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 128 | return (mode & S_ISGID) != 0; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 129 | } |
| 130 | |
| 131 | /** |
| 132 | * Returns true iff this file has its "sticky" bit set. See UNIX manuals for |
| 133 | * explanation. |
| 134 | */ |
| 135 | public boolean isSticky() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 136 | return (mode & S_ISVTX) != 0; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 137 | } |
| 138 | |
| 139 | /** |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 140 | * Returns the user/group/other permissions part of the mode bits (i.e. mode masked with 0777), |
| 141 | * interpreted according to longstanding UNIX tradition. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 142 | */ |
| 143 | public int getPermissions() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 144 | return mode & S_IRWXA; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 145 | } |
| 146 | |
| 147 | /** |
| 148 | * Returns the total size, in bytes, of this file. |
| 149 | */ |
| 150 | public long getSize() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 151 | return size; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 152 | } |
| 153 | |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 154 | /** Returns the last access time of this file (milliseconds since UNIX epoch). */ |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 155 | public long getLastAccessTime() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 156 | return atime; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 157 | } |
| 158 | |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 159 | /** Returns the last modified time of this file (milliseconds since UNIX epoch). */ |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 160 | public long getLastModifiedTime() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 161 | return mtime; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 162 | } |
| 163 | |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 164 | /** Returns the last change time of this file (milliseconds since UNIX epoch). */ |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 165 | public long getLastChangeTime() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 166 | return ctime; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | //////////////////////////////////////////////////////////////////////// |
| 170 | |
| 171 | @Override |
| 172 | public String toString() { |
Googler | 4eba4a6 | 2024-10-01 03:49:57 -0700 | [diff] [blame] | 173 | return String.format( |
| 174 | "FileStatus(mode=0%06o,atime=%d,mtime=%d,ctime=%d,size=%d,device=%d,ino=%d)", |
| 175 | mode, atime, mtime, ctime, size, dev, ino); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 176 | } |
| 177 | |
| 178 | //////////////////////////////////////////////////////////////////////// |
| 179 | // Platform-specific details. These fields are public so that they can |
| 180 | // be used from other packages. See POSIX and/or Linux manuals for details. |
| 181 | // |
| 182 | // These need to be kept in sync with the native code and system call |
| 183 | // interface. (The unit tests ensure that.) Of course, this decoding could |
| 184 | // be done in the JNI code to ensure maximum portability, but (a) we don't |
| 185 | // expect we'll need that any time soon, and (b) that would require eager |
| 186 | // rather than on-demand bitmunging of all attributes. In any case, it's not |
| 187 | // part of the interface so it can be easily changed later if necessary. |
| 188 | |
| 189 | public static final int S_IFMT = 0170000; // mask: filetype bitfields |
| 190 | public static final int S_IFSOCK = 0140000; // socket |
| 191 | public static final int S_IFLNK = 0120000; // symbolic link |
| 192 | public static final int S_IFREG = 0100000; // regular file |
| 193 | public static final int S_IFBLK = 0060000; // block device |
| 194 | public static final int S_IFDIR = 0040000; // directory |
| 195 | public static final int S_IFCHR = 0020000; // character device |
| 196 | public static final int S_IFIFO = 0010000; // fifo |
| 197 | public static final int S_ISUID = 0004000; // set UID bit |
| 198 | public static final int S_ISGID = 0002000; // set GID bit (see below) |
| 199 | public static final int S_ISVTX = 0001000; // sticky bit (see below) |
| 200 | public static final int S_IRWXA = 00777; // mask: all permissions |
| 201 | public static final int S_IRWXU = 00700; // mask: file owner permissions |
| 202 | public static final int S_IRUSR = 00400; // owner has read permission |
| 203 | public static final int S_IWUSR = 00200; // owner has write permission |
| 204 | public static final int S_IXUSR = 00100; // owner has execute permission |
| 205 | public static final int S_IRWXG = 00070; // mask: group permissions |
| 206 | public static final int S_IRGRP = 00040; // group has read permission |
| 207 | public static final int S_IWGRP = 00020; // group has write permission |
| 208 | public static final int S_IXGRP = 00010; // group has execute permission |
| 209 | public static final int S_IRWXO = 00007; // mask: other permissions |
| 210 | public static final int S_IROTH = 00004; // others have read permission |
| 211 | public static final int S_IWOTH = 00002; // others have write permisson |
| 212 | public static final int S_IXOTH = 00001; // others have execute permission |
| 213 | |
| 214 | public static final int S_IEXEC = 00111; // owner, group, world execute |
| 215 | |
Nathan Harmata | d8b6ff2 | 2015-10-20 21:54:34 +0000 | [diff] [blame] | 216 | public static boolean isFile(int rawType) { |
| 217 | int type = rawType & S_IFMT; |
| 218 | return type == S_IFREG || isSpecialFile(rawType); |
| 219 | } |
| 220 | |
| 221 | public static boolean isSpecialFile(int rawType) { |
| 222 | int type = rawType & S_IFMT; |
| 223 | return type == S_IFSOCK || type == S_IFBLK || type == S_IFCHR || type == S_IFIFO; |
| 224 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 225 | } |