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 
26 package sun.nio.fs;
27 
28 import java.nio.file.attribute.*;
29 import java.util.concurrent.TimeUnit;
30 import java.util.Set;
31 import java.util.HashSet;
32 
33 /**
34  * Unix implementation of PosixFileAttributes.
35  */
36 
37 class UnixFileAttributes
38     implements PosixFileAttributes
39 {
40     private int     st_mode;
41     private long    st_ino;
42     private long    st_dev;
43     private long    st_rdev;
44     private int     st_nlink;
45     private int     st_uid;
46     private int     st_gid;
47     private long    st_size;
48     private long    st_atime_sec;
49     private long    st_atime_nsec;
50     private long    st_mtime_sec;
51     private long    st_mtime_nsec;
52     private long    st_ctime_sec;
53     private long    st_ctime_nsec;
54     private long    st_birthtime_sec;
55 
56     // created lazily
57     private volatile UserPrincipal owner;
58     private volatile GroupPrincipal group;
59     private volatile UnixFileKey key;
60 
UnixFileAttributes()61     private UnixFileAttributes() {
62     }
63 
64     // get the UnixFileAttributes for a given file
get(UnixPath path, boolean followLinks)65     static UnixFileAttributes get(UnixPath path, boolean followLinks)
66         throws UnixException
67     {
68         UnixFileAttributes attrs = new UnixFileAttributes();
69         if (followLinks) {
70             UnixNativeDispatcher.stat(path, attrs);
71         } else {
72             UnixNativeDispatcher.lstat(path, attrs);
73         }
74         return attrs;
75     }
76 
77     // get the UnixFileAttributes for an open file
get(int fd)78     static UnixFileAttributes get(int fd) throws UnixException {
79         UnixFileAttributes attrs = new UnixFileAttributes();
80         UnixNativeDispatcher.fstat(fd, attrs);
81         return attrs;
82     }
83 
84     // get the UnixFileAttributes for a given file, relative to open directory
get(int dfd, UnixPath path, boolean followLinks)85     static UnixFileAttributes get(int dfd, UnixPath path, boolean followLinks)
86         throws UnixException
87     {
88         UnixFileAttributes attrs = new UnixFileAttributes();
89         int flag = (followLinks) ? 0 : UnixConstants.AT_SYMLINK_NOFOLLOW;
90         UnixNativeDispatcher.fstatat(dfd, path.asByteArray(), flag, attrs);
91         return attrs;
92     }
93 
94     // package-private
isSameFile(UnixFileAttributes attrs)95     boolean isSameFile(UnixFileAttributes attrs) {
96         return ((st_ino == attrs.st_ino) && (st_dev == attrs.st_dev));
97     }
98 
99     // package-private
mode()100     int mode()  { return st_mode; }
ino()101     long ino()  { return st_ino; }
dev()102     long dev()  { return st_dev; }
rdev()103     long rdev() { return st_rdev; }
nlink()104     int nlink() { return st_nlink; }
uid()105     int uid()   { return st_uid; }
gid()106     int gid()   { return st_gid; }
107 
toFileTime(long sec, long nsec)108     private static FileTime toFileTime(long sec, long nsec) {
109         if (nsec == 0) {
110             return FileTime.from(sec, TimeUnit.SECONDS);
111         } else {
112             // truncate to microseconds to avoid overflow with timestamps
113             // way out into the future. We can re-visit this if FileTime
114             // is updated to define a from(secs,nsecs) method.
115             long micro = sec*1000000L + nsec/1000L;
116             return FileTime.from(micro, TimeUnit.MICROSECONDS);
117         }
118     }
119 
ctime()120     FileTime ctime() {
121         return toFileTime(st_ctime_sec, st_ctime_nsec);
122     }
123 
isDevice()124     boolean isDevice() {
125         int type = st_mode & UnixConstants.S_IFMT;
126         return (type == UnixConstants.S_IFCHR ||
127                 type == UnixConstants.S_IFBLK  ||
128                 type == UnixConstants.S_IFIFO);
129     }
130 
131     @Override
lastModifiedTime()132     public FileTime lastModifiedTime() {
133         return toFileTime(st_mtime_sec, st_mtime_nsec);
134     }
135 
136     @Override
lastAccessTime()137     public FileTime lastAccessTime() {
138         return toFileTime(st_atime_sec, st_atime_nsec);
139     }
140 
141     @Override
creationTime()142     public FileTime creationTime() {
143         if (UnixNativeDispatcher.birthtimeSupported()) {
144             return FileTime.from(st_birthtime_sec, TimeUnit.SECONDS);
145         } else {
146             // return last modified when birth time not supported
147             return lastModifiedTime();
148         }
149     }
150 
151     @Override
isRegularFile()152     public boolean isRegularFile() {
153        return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFREG);
154     }
155 
156     @Override
isDirectory()157     public boolean isDirectory() {
158         return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR);
159     }
160 
161     @Override
isSymbolicLink()162     public boolean isSymbolicLink() {
163         return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFLNK);
164     }
165 
166     @Override
isOther()167     public boolean isOther() {
168         int type = st_mode & UnixConstants.S_IFMT;
169         return (type != UnixConstants.S_IFREG &&
170                 type != UnixConstants.S_IFDIR &&
171                 type != UnixConstants.S_IFLNK);
172     }
173 
174     @Override
size()175     public long size() {
176         return st_size;
177     }
178 
179     @Override
fileKey()180     public UnixFileKey fileKey() {
181         if (key == null) {
182             synchronized (this) {
183                 if (key == null) {
184                     key = new UnixFileKey(st_dev, st_ino);
185                 }
186             }
187         }
188         return key;
189     }
190 
191     @Override
owner()192     public UserPrincipal owner() {
193         if (owner == null) {
194             synchronized (this) {
195                 if (owner == null) {
196                     owner = UnixUserPrincipals.fromUid(st_uid);
197                 }
198             }
199         }
200         return owner;
201     }
202 
203     @Override
group()204     public GroupPrincipal group() {
205         if (group == null) {
206             synchronized (this) {
207                 if (group == null) {
208                     group = UnixUserPrincipals.fromGid(st_gid);
209                 }
210             }
211         }
212         return group;
213     }
214 
215     @Override
permissions()216     public Set<PosixFilePermission> permissions() {
217         int bits = (st_mode & UnixConstants.S_IAMB);
218         HashSet<PosixFilePermission> perms = new HashSet<>();
219 
220         if ((bits & UnixConstants.S_IRUSR) > 0)
221             perms.add(PosixFilePermission.OWNER_READ);
222         if ((bits & UnixConstants.S_IWUSR) > 0)
223             perms.add(PosixFilePermission.OWNER_WRITE);
224         if ((bits & UnixConstants.S_IXUSR) > 0)
225             perms.add(PosixFilePermission.OWNER_EXECUTE);
226 
227         if ((bits & UnixConstants.S_IRGRP) > 0)
228             perms.add(PosixFilePermission.GROUP_READ);
229         if ((bits & UnixConstants.S_IWGRP) > 0)
230             perms.add(PosixFilePermission.GROUP_WRITE);
231         if ((bits & UnixConstants.S_IXGRP) > 0)
232             perms.add(PosixFilePermission.GROUP_EXECUTE);
233 
234         if ((bits & UnixConstants.S_IROTH) > 0)
235             perms.add(PosixFilePermission.OTHERS_READ);
236         if ((bits & UnixConstants.S_IWOTH) > 0)
237             perms.add(PosixFilePermission.OTHERS_WRITE);
238         if ((bits & UnixConstants.S_IXOTH) > 0)
239             perms.add(PosixFilePermission.OTHERS_EXECUTE);
240 
241         return perms;
242     }
243 
244     // wrap this object with BasicFileAttributes object to prevent leaking of
245     // user information
asBasicFileAttributes()246     BasicFileAttributes asBasicFileAttributes() {
247         return UnixAsBasicFileAttributes.wrap(this);
248     }
249 
250     // unwrap BasicFileAttributes to get the underlying UnixFileAttributes
251     // object. Returns null is not wrapped.
toUnixFileAttributes(BasicFileAttributes attrs)252     static UnixFileAttributes toUnixFileAttributes(BasicFileAttributes attrs) {
253         if (attrs instanceof UnixFileAttributes)
254             return (UnixFileAttributes)attrs;
255         if (attrs instanceof UnixAsBasicFileAttributes) {
256             return ((UnixAsBasicFileAttributes)attrs).unwrap();
257         }
258         return null;
259     }
260 
261     // wrap a UnixFileAttributes object as a BasicFileAttributes
262     private static class UnixAsBasicFileAttributes implements BasicFileAttributes {
263         private final UnixFileAttributes attrs;
264 
UnixAsBasicFileAttributes(UnixFileAttributes attrs)265         private UnixAsBasicFileAttributes(UnixFileAttributes attrs) {
266             this.attrs = attrs;
267         }
268 
wrap(UnixFileAttributes attrs)269         static UnixAsBasicFileAttributes wrap(UnixFileAttributes attrs) {
270             return new UnixAsBasicFileAttributes(attrs);
271         }
272 
unwrap()273         UnixFileAttributes unwrap() {
274             return attrs;
275         }
276 
277         @Override
lastModifiedTime()278         public FileTime lastModifiedTime() {
279             return attrs.lastModifiedTime();
280         }
281         @Override
lastAccessTime()282         public FileTime lastAccessTime() {
283             return attrs.lastAccessTime();
284         }
285         @Override
creationTime()286         public FileTime creationTime() {
287             return attrs.creationTime();
288         }
289         @Override
isRegularFile()290         public boolean isRegularFile() {
291             return attrs.isRegularFile();
292         }
293         @Override
isDirectory()294         public boolean isDirectory() {
295             return attrs.isDirectory();
296         }
297         @Override
isSymbolicLink()298         public boolean isSymbolicLink() {
299             return attrs.isSymbolicLink();
300         }
301         @Override
isOther()302         public boolean isOther() {
303             return attrs.isOther();
304         }
305         @Override
size()306         public long size() {
307             return attrs.size();
308         }
309         @Override
fileKey()310         public Object fileKey() {
311             return attrs.fileKey();
312         }
313     }
314 }
315