termux-app
418 строк · 12.5 Кб
1/*
2* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*
5* This code is free software; you can redistribute it and/or modify it
6* under the terms of the GNU General Public License version 2 only, as
7* published by the Free Software Foundation. Oracle designates this
8* particular file as subject to the "Classpath" exception as provided
9* by Oracle in the LICENSE file that accompanied this code.
10*
11* This code is distributed in the hope that it will be useful, but WITHOUT
12* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14* version 2 for more details (a copy is included in the LICENSE file that
15* accompanied this code).
16*
17* You should have received a copy of the GNU General Public License version
18* 2 along with this work; if not, write to the Free Software Foundation,
19* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20*
21* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22* or visit www.oracle.com if you need additional information or have any
23* questions.
24*/
25
26package com.termux.shared.file.filesystem;
27
28import android.os.Build;
29import android.system.StructStat;
30
31import androidx.annotation.NonNull;
32
33import java.io.File;
34import java.io.FileDescriptor;
35import java.io.IOException;
36import java.util.concurrent.TimeUnit;
37import java.util.Set;
38import java.util.HashSet;
39
40/**
41* Unix implementation of PosixFileAttributes.
42* https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:libcore/ojluni/src/main/java/sun/nio/fs/UnixFileAttributes.java
43*/
44
45public class FileAttributes {
46private String filePath;
47private FileDescriptor fileDescriptor;
48
49private int st_mode;
50private long st_ino;
51private long st_dev;
52private long st_rdev;
53private long st_nlink;
54private int st_uid;
55private int st_gid;
56private long st_size;
57private long st_blksize;
58private long st_blocks;
59private long st_atime_sec;
60private long st_atime_nsec;
61private long st_mtime_sec;
62private long st_mtime_nsec;
63private long st_ctime_sec;
64private long st_ctime_nsec;
65
66// created lazily
67private volatile String owner;
68private volatile String group;
69private volatile FileKey key;
70
71private FileAttributes(String filePath) {
72this.filePath = filePath;
73}
74
75private FileAttributes(FileDescriptor fileDescriptor) {
76this.fileDescriptor = fileDescriptor;
77}
78
79// get the FileAttributes for a given file
80public static FileAttributes get(String filePath, boolean followLinks) throws IOException {
81FileAttributes fileAttributes;
82
83if (filePath == null || filePath.isEmpty())
84fileAttributes = new FileAttributes((String) null);
85else
86fileAttributes = new FileAttributes(new File(filePath).getAbsolutePath());
87
88if (followLinks) {
89NativeDispatcher.stat(filePath, fileAttributes);
90} else {
91NativeDispatcher.lstat(filePath, fileAttributes);
92}
93
94// Logger.logDebug(fileAttributes.toString());
95
96return fileAttributes;
97}
98
99// get the FileAttributes for an open file
100public static FileAttributes get(FileDescriptor fileDescriptor) throws IOException {
101FileAttributes fileAttributes = new FileAttributes(fileDescriptor);
102NativeDispatcher.fstat(fileDescriptor, fileAttributes);
103return fileAttributes;
104}
105
106public String file() {
107if (filePath != null)
108return filePath;
109else if (fileDescriptor != null)
110return fileDescriptor.toString();
111else
112return null;
113}
114
115// package-private
116public boolean isSameFile(FileAttributes attrs) {
117return ((st_ino == attrs.st_ino) && (st_dev == attrs.st_dev));
118}
119
120// package-private
121public int mode() {
122return st_mode;
123}
124
125public long blksize() {
126return st_blksize;
127}
128
129public long blocks() {
130return st_blocks;
131}
132
133public long ino() {
134return st_ino;
135}
136
137public long dev() {
138return st_dev;
139}
140
141public long rdev() {
142return st_rdev;
143}
144
145public long nlink() {
146return st_nlink;
147}
148
149public int uid() {
150return st_uid;
151}
152
153public int gid() {
154return st_gid;
155}
156
157private static FileTime toFileTime(long sec, long nsec) {
158if (nsec == 0) {
159return FileTime.from(sec, TimeUnit.SECONDS);
160} else {
161// truncate to microseconds to avoid overflow with timestamps
162// way out into the future. We can re-visit this if FileTime
163// is updated to define a from(secs,nsecs) method.
164long micro = sec * 1000000L + nsec / 1000L;
165return FileTime.from(micro, TimeUnit.MICROSECONDS);
166}
167}
168
169public FileTime lastAccessTime() {
170return toFileTime(st_atime_sec, st_atime_nsec);
171}
172
173public FileTime lastModifiedTime() {
174return toFileTime(st_mtime_sec, st_mtime_nsec);
175}
176
177public FileTime lastChangeTime() {
178return toFileTime(st_ctime_sec, st_ctime_nsec);
179}
180
181public FileTime creationTime() {
182return lastModifiedTime();
183}
184
185public boolean isRegularFile() {
186return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFREG);
187}
188
189public boolean isDirectory() {
190return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR);
191}
192
193public boolean isSymbolicLink() {
194return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFLNK);
195}
196
197public boolean isCharacter() {
198return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFCHR);
199}
200
201public boolean isFifo() {
202return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFIFO);
203}
204
205public boolean isSocket() {
206return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFSOCK);
207}
208
209public boolean isBlock() {
210return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFBLK);
211}
212
213public boolean isOther() {
214int type = st_mode & UnixConstants.S_IFMT;
215return (type != UnixConstants.S_IFREG &&
216type != UnixConstants.S_IFDIR &&
217type != UnixConstants.S_IFLNK);
218}
219
220public boolean isDevice() {
221int type = st_mode & UnixConstants.S_IFMT;
222return (type == UnixConstants.S_IFCHR ||
223type == UnixConstants.S_IFBLK ||
224type == UnixConstants.S_IFIFO);
225}
226
227public long size() {
228return st_size;
229}
230
231public FileKey fileKey() {
232if (key == null) {
233synchronized (this) {
234if (key == null) {
235key = new FileKey(st_dev, st_ino);
236}
237}
238}
239return key;
240}
241
242public String owner() {
243if (owner == null) {
244synchronized (this) {
245if (owner == null) {
246owner = Integer.toString(st_uid);
247}
248}
249}
250return owner;
251}
252
253public String group() {
254if (group == null) {
255synchronized (this) {
256if (group == null) {
257group = Integer.toString(st_gid);
258}
259}
260}
261return group;
262}
263
264public Set<FilePermission> permissions() {
265int bits = (st_mode & UnixConstants.S_IAMB);
266HashSet<FilePermission> perms = new HashSet<>();
267
268if ((bits & UnixConstants.S_IRUSR) > 0)
269perms.add(FilePermission.OWNER_READ);
270if ((bits & UnixConstants.S_IWUSR) > 0)
271perms.add(FilePermission.OWNER_WRITE);
272if ((bits & UnixConstants.S_IXUSR) > 0)
273perms.add(FilePermission.OWNER_EXECUTE);
274
275if ((bits & UnixConstants.S_IRGRP) > 0)
276perms.add(FilePermission.GROUP_READ);
277if ((bits & UnixConstants.S_IWGRP) > 0)
278perms.add(FilePermission.GROUP_WRITE);
279if ((bits & UnixConstants.S_IXGRP) > 0)
280perms.add(FilePermission.GROUP_EXECUTE);
281
282if ((bits & UnixConstants.S_IROTH) > 0)
283perms.add(FilePermission.OTHERS_READ);
284if ((bits & UnixConstants.S_IWOTH) > 0)
285perms.add(FilePermission.OTHERS_WRITE);
286if ((bits & UnixConstants.S_IXOTH) > 0)
287perms.add(FilePermission.OTHERS_EXECUTE);
288
289return perms;
290}
291
292public void loadFromStructStat(StructStat structStat) {
293this.st_mode = structStat.st_mode;
294this.st_ino = structStat.st_ino;
295this.st_dev = structStat.st_dev;
296this.st_rdev = structStat.st_rdev;
297this.st_nlink = structStat.st_nlink;
298this.st_uid = structStat.st_uid;
299this.st_gid = structStat.st_gid;
300this.st_size = structStat.st_size;
301this.st_blksize = structStat.st_blksize;
302this.st_blocks = structStat.st_blocks;
303
304if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
305this.st_atime_sec = structStat.st_atim.tv_sec;
306this.st_atime_nsec = structStat.st_atim.tv_nsec;
307this.st_mtime_sec = structStat.st_mtim.tv_sec;
308this.st_mtime_nsec = structStat.st_mtim.tv_nsec;
309this.st_ctime_sec = structStat.st_ctim.tv_sec;
310this.st_ctime_nsec = structStat.st_ctim.tv_nsec;
311} else {
312this.st_atime_sec = structStat.st_atime;
313this.st_atime_nsec = 0;
314this.st_mtime_sec = structStat.st_mtime;
315this.st_mtime_nsec = 0;
316this.st_ctime_sec = structStat.st_ctime;
317this.st_ctime_nsec = 0;
318}
319}
320
321public String getFileString() {
322return "File: `" + file() + "`";
323}
324
325public String getTypeString() {
326return "Type: `" + FileTypes.getFileType(this).getName() + "`";
327}
328
329public String getSizeString() {
330return "Size: `" + size() + "`";
331}
332
333public String getBlocksString() {
334return "Blocks: `" + blocks() + "`";
335}
336
337public String getIOBlockString() {
338return "IO Block: `" + blksize() + "`";
339}
340
341public String getDeviceString() {
342return "Device: `" + Long.toHexString(st_dev) + "`";
343}
344
345public String getInodeString() {
346return "Inode: `" + st_ino + "`";
347}
348
349public String getLinksString() {
350return "Links: `" + nlink() + "`";
351}
352
353public String getDeviceTypeString() {
354return "Device Type: `" + rdev() + "`";
355}
356
357public String getOwnerString() {
358return "Owner: `" + owner() + "`";
359}
360
361public String getGroupString() {
362return "Group: `" + group() + "`";
363}
364
365public String getPermissionString() {
366return "Permissions: `" + FilePermissions.toString(permissions()) + "`";
367}
368
369public String getAccessTimeString() {
370return "Access Time: `" + lastAccessTime() + "`";
371}
372
373public String getModifiedTimeString() {
374return "Modified Time: `" + lastModifiedTime() + "`";
375}
376
377public String getChangeTimeString() {
378return "Change Time: `" + lastChangeTime() + "`";
379}
380
381@NonNull
382@Override
383public String toString() {
384return getFileAttributesLogString(this);
385}
386
387public static String getFileAttributesLogString(final FileAttributes fileAttributes) {
388if (fileAttributes == null) return "null";
389
390StringBuilder logString = new StringBuilder();
391
392logString.append(fileAttributes.getFileString());
393
394logString.append("\n").append(fileAttributes.getTypeString());
395
396logString.append("\n").append(fileAttributes.getSizeString());
397logString.append("\n").append(fileAttributes.getBlocksString());
398logString.append("\n").append(fileAttributes.getIOBlockString());
399
400logString.append("\n").append(fileAttributes.getDeviceString());
401logString.append("\n").append(fileAttributes.getInodeString());
402logString.append("\n").append(fileAttributes.getLinksString());
403
404if (fileAttributes.isBlock() || fileAttributes.isCharacter())
405logString.append("\n").append(fileAttributes.getDeviceTypeString());
406
407logString.append("\n").append(fileAttributes.getOwnerString());
408logString.append("\n").append(fileAttributes.getGroupString());
409logString.append("\n").append(fileAttributes.getPermissionString());
410
411logString.append("\n").append(fileAttributes.getAccessTimeString());
412logString.append("\n").append(fileAttributes.getModifiedTimeString());
413logString.append("\n").append(fileAttributes.getChangeTimeString());
414
415return logString.toString();
416}
417
418}
419