< prev index next >

src/java.base/unix/classes/java/io/UnixFileSystem.java

Print this page

  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 java.io;
 27 
 28 import java.util.Properties;
 29 
 30 import jdk.internal.util.StaticProperty;
 31 import sun.security.action.GetPropertyAction;
 32 
 33 
 34 class UnixFileSystem extends FileSystem {
 35 
 36     private final char slash;
 37     private final char colon;
 38     private final String javaHome;
 39     private final String userDir;
 40 
 41     public UnixFileSystem() {
 42         Properties props = GetPropertyAction.privilegedGetProperties();
 43         slash = props.getProperty("file.separator").charAt(0);
 44         colon = props.getProperty("path.separator").charAt(0);
 45         javaHome = StaticProperty.javaHome();
 46         userDir = StaticProperty.userDir();
 47         cache = useCanonCaches ? new ExpiringCache() : null;
 48         javaHomePrefixCache = useCanonPrefixCache ? new ExpiringCache() : null;
 49     }
 50 
 51 
 52     /* -- Normalization and construction -- */
 53 

150             sm.checkPropertyAccess("user.dir");
151         }
152         return resolve(userDir, f.getPath());
153     }
154 
155     // Caches for canonicalization results to improve startup performance.
156     // The first cache handles repeated canonicalizations of the same path
157     // name. The prefix cache handles repeated canonicalizations within the
158     // same directory, and must not create results differing from the true
159     // canonicalization algorithm in canonicalize_md.c. For this reason the
160     // prefix cache is conservative and is not used for complex path names.
161     private final ExpiringCache cache;
162     // On Unix symlinks can jump anywhere in the file system, so we only
163     // treat prefixes in java.home as trusted and cacheable in the
164     // canonicalization algorithm
165     private final ExpiringCache javaHomePrefixCache;
166 
167     @Override
168     public String canonicalize(String path) throws IOException {
169         if (!useCanonCaches) {
170             return canonicalize0(path);




171         } else {
172             String res = cache.get(path);
173             if (res == null) {
174                 String dir = null;
175                 String resDir;
176                 if (useCanonPrefixCache) {
177                     // Note that this can cause symlinks that should
178                     // be resolved to a destination directory to be
179                     // resolved to the directory they're contained in
180                     dir = parentOrNull(path);
181                     if (dir != null) {
182                         resDir = javaHomePrefixCache.get(dir);
183                         if (resDir != null) {
184                             // Hit only in prefix cache; full path is canonical
185                             String filename = path.substring(1 + dir.length());
186                             res = resDir + slash + filename;
187                             cache.put(dir + slash + filename, res);
188                         }
189                     }
190                 }
191                 if (res == null) {
192                     res = canonicalize0(path);




193                     cache.put(path, res);
194                     if (useCanonPrefixCache &&
195                         dir != null && dir.startsWith(javaHome)) {
196                         resDir = parentOrNull(res);
197                         // Note that we don't allow a resolved symlink
198                         // to elsewhere in java.home to pollute the
199                         // prefix cache (java.home prefix cache could
200                         // just as easily be a set at this point)
201                         if (resDir != null && resDir.equals(dir)) {
202                             File f = new File(res);
203                             if (f.exists() && !f.isDirectory()) {
204                                 javaHomePrefixCache.put(dir, resDir);
205                             }
206                         }
207                     }
208                 }
209             }
210             return res;
211         }
212     }

239                 }
240                 if (idx == 0 ||
241                     idx >= last - 1 ||
242                     path.charAt(idx - 1) == sep) {
243                     // Punt on pathnames containing adjacent slashes
244                     // toward the end
245                     return null;
246                 }
247                 return path.substring(0, idx);
248             } else {
249                 ++nonDotCount;
250                 adjacentDots = 0;
251             }
252             --idx;
253         }
254         return null;
255     }
256 
257     /* -- Attribute accessors -- */
258 
259     public native int getBooleanAttributes0(File f);
260 
261     @Override
262     public int getBooleanAttributes(File f) {
263         int rv = getBooleanAttributes0(f);





264         return rv | isHidden(f);
265     }
266 
267     @Override
268     public boolean hasBooleanAttributes(File f, int attributes) {
269         int rv = getBooleanAttributes0(f);





270         if ((attributes & BA_HIDDEN) != 0) {
271             rv |= isHidden(f);
272         }
273         return (rv & attributes) == attributes;
274     }
275 
276     private static int isHidden(File f) {
277         return f.getName().startsWith(".") ? BA_HIDDEN : 0;
278     }
279 
280     @Override
281     public native boolean checkAccess(File f, int access);







282 
283     @Override
284     public native long getLastModifiedTime(File f);







285 
286     @Override
287     public native long getLength(File f);







288 
289     @Override
290     public native boolean setPermission(File f, int access, boolean enable, boolean owneronly);







291 
292     /* -- File operations -- */
293 
294     @Override
295     public native boolean createFileExclusively(String path)
296         throws IOException;






297 
298     @Override
299     public boolean delete(File f) {
300         // Keep canonicalization caches in sync after file deletion
301         // and renaming operations. Could be more clever than this
302         // (i.e., only remove/update affected entries) but probably
303         // not worth it since these entries expire after 30 seconds
304         // anyway.
305         if (useCanonCaches) {
306             cache.clear();
307         }
308         if (useCanonPrefixCache) {
309             javaHomePrefixCache.clear();
310         }
311         return delete0(f);




312     }
313     private native boolean delete0(File f);
314 
315     @Override
316     public native String[] list(File f);







317 
318     @Override
319     public native boolean createDirectory(File f);







320 
321     @Override
322     public boolean rename(File f1, File f2) {
323         // Keep canonicalization caches in sync after file deletion
324         // and renaming operations. Could be more clever than this
325         // (i.e., only remove/update affected entries) but probably
326         // not worth it since these entries expire after 30 seconds
327         // anyway.
328         if (useCanonCaches) {
329             cache.clear();
330         }
331         if (useCanonPrefixCache) {
332             javaHomePrefixCache.clear();
333         }
334         return rename0(f1, f2);




335     }
336     private native boolean rename0(File f1, File f2);
337 
338     @Override
339     public native boolean setLastModifiedTime(File f, long time);







340 
341     @Override
342     public native boolean setReadOnly(File f);







343 
344     /* -- Filesystem interface -- */
345 
346     @Override
347     public File[] listRoots() {
348         try {
349             @SuppressWarnings("removal")
350             SecurityManager security = System.getSecurityManager();
351             if (security != null) {
352                 security.checkRead("/");
353             }
354             return new File[] { new File("/") };
355         } catch (SecurityException x) {
356             return new File[0];
357         }
358     }
359 
360     /* -- Disk usage -- */
361 
362     @Override
363     public native long getSpace(File f, int t);







364 
365     /* -- Basic infrastructure -- */
366 
367     private native long getNameMax0(String path);
368 
369     @Override
370     public int getNameMax(String path) {
371         long nameMax = getNameMax0(path);
372         if (nameMax > Integer.MAX_VALUE) {
373             nameMax = Integer.MAX_VALUE;
374         }
375         return (int)nameMax;
376     }
377 
378     @Override
379     public int compare(File f1, File f2) {
380         return f1.getPath().compareTo(f2.getPath());
381     }
382 
383     @Override

  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 java.io;
 27 
 28 import java.util.Properties;
 29 import jdk.internal.misc.Blocker;
 30 import jdk.internal.util.StaticProperty;
 31 import sun.security.action.GetPropertyAction;
 32 

 33 class UnixFileSystem extends FileSystem {
 34 
 35     private final char slash;
 36     private final char colon;
 37     private final String javaHome;
 38     private final String userDir;
 39 
 40     public UnixFileSystem() {
 41         Properties props = GetPropertyAction.privilegedGetProperties();
 42         slash = props.getProperty("file.separator").charAt(0);
 43         colon = props.getProperty("path.separator").charAt(0);
 44         javaHome = StaticProperty.javaHome();
 45         userDir = StaticProperty.userDir();
 46         cache = useCanonCaches ? new ExpiringCache() : null;
 47         javaHomePrefixCache = useCanonPrefixCache ? new ExpiringCache() : null;
 48     }
 49 
 50 
 51     /* -- Normalization and construction -- */
 52 

149             sm.checkPropertyAccess("user.dir");
150         }
151         return resolve(userDir, f.getPath());
152     }
153 
154     // Caches for canonicalization results to improve startup performance.
155     // The first cache handles repeated canonicalizations of the same path
156     // name. The prefix cache handles repeated canonicalizations within the
157     // same directory, and must not create results differing from the true
158     // canonicalization algorithm in canonicalize_md.c. For this reason the
159     // prefix cache is conservative and is not used for complex path names.
160     private final ExpiringCache cache;
161     // On Unix symlinks can jump anywhere in the file system, so we only
162     // treat prefixes in java.home as trusted and cacheable in the
163     // canonicalization algorithm
164     private final ExpiringCache javaHomePrefixCache;
165 
166     @Override
167     public String canonicalize(String path) throws IOException {
168         if (!useCanonCaches) {
169             if (Thread.currentThread().isVirtual()) {
170                 return Blocker.managedBlock(() -> canonicalize0(path));
171             } else {
172                 return canonicalize0(path);
173             }
174         } else {
175             String res = cache.get(path);
176             if (res == null) {
177                 String dir = null;
178                 String resDir;
179                 if (useCanonPrefixCache) {
180                     // Note that this can cause symlinks that should
181                     // be resolved to a destination directory to be
182                     // resolved to the directory they're contained in
183                     dir = parentOrNull(path);
184                     if (dir != null) {
185                         resDir = javaHomePrefixCache.get(dir);
186                         if (resDir != null) {
187                             // Hit only in prefix cache; full path is canonical
188                             String filename = path.substring(1 + dir.length());
189                             res = resDir + slash + filename;
190                             cache.put(dir + slash + filename, res);
191                         }
192                     }
193                 }
194                 if (res == null) {
195                     if (Thread.currentThread().isVirtual()) {
196                         res = Blocker.managedBlock(() -> canonicalize0(path));
197                     } else {
198                         res = canonicalize0(path);
199                     }
200                     cache.put(path, res);
201                     if (useCanonPrefixCache &&
202                         dir != null && dir.startsWith(javaHome)) {
203                         resDir = parentOrNull(res);
204                         // Note that we don't allow a resolved symlink
205                         // to elsewhere in java.home to pollute the
206                         // prefix cache (java.home prefix cache could
207                         // just as easily be a set at this point)
208                         if (resDir != null && resDir.equals(dir)) {
209                             File f = new File(res);
210                             if (f.exists() && !f.isDirectory()) {
211                                 javaHomePrefixCache.put(dir, resDir);
212                             }
213                         }
214                     }
215                 }
216             }
217             return res;
218         }
219     }

246                 }
247                 if (idx == 0 ||
248                     idx >= last - 1 ||
249                     path.charAt(idx - 1) == sep) {
250                     // Punt on pathnames containing adjacent slashes
251                     // toward the end
252                     return null;
253                 }
254                 return path.substring(0, idx);
255             } else {
256                 ++nonDotCount;
257                 adjacentDots = 0;
258             }
259             --idx;
260         }
261         return null;
262     }
263 
264     /* -- Attribute accessors -- */
265 
266     private native int getBooleanAttributes0(File f);
267 
268     @Override
269     public int getBooleanAttributes(File f) {
270         int rv;
271         if (Thread.currentThread().isVirtual()) {
272             rv = Blocker.managedBlock(() -> getBooleanAttributes0(f));
273         } else {
274             rv = getBooleanAttributes0(f);
275         }
276         return rv | isHidden(f);
277     }
278 
279     @Override
280     public boolean hasBooleanAttributes(File f, int attributes) {
281         int rv;
282         if (Thread.currentThread().isVirtual()) {
283             rv = Blocker.managedBlock(() -> getBooleanAttributes0(f));
284         } else {
285             rv = getBooleanAttributes0(f);
286         }
287         if ((attributes & BA_HIDDEN) != 0) {
288             rv |= isHidden(f);
289         }
290         return (rv & attributes) == attributes;
291     }
292 
293     private static int isHidden(File f) {
294         return f.getName().startsWith(".") ? BA_HIDDEN : 0;
295     }
296 
297     @Override
298     public boolean checkAccess(File f, int access) {
299         if (Thread.currentThread().isVirtual()) {
300             return Blocker.managedBlock(() -> checkAccess0(f, access));
301         } else {
302             return checkAccess0(f, access);
303         }
304     }
305     private native boolean checkAccess0(File f, int access);
306 
307     @Override
308     public long getLastModifiedTime(File f) {
309         if (Thread.currentThread().isVirtual()) {
310             return Blocker.managedBlock(() -> getLastModifiedTime0(f));
311         } else {
312             return getLastModifiedTime0(f);
313         }
314     }
315     private native long getLastModifiedTime0(File f);
316 
317     @Override
318     public long getLength(File f) {
319         if (Thread.currentThread().isVirtual()) {
320             return Blocker.managedBlock(() -> getLength0(f));
321         } else {
322             return getLength0(f);
323         }
324     }
325     private native long getLength0(File f);
326 
327     @Override
328     public boolean setPermission(File f, int access, boolean enable, boolean owneronly) {
329         if (Thread.currentThread().isVirtual()) {
330             return Blocker.managedBlock(() -> setPermission0(f, access, enable, owneronly));
331         } else {
332             return setPermission0(f, access, enable, owneronly);
333         }
334     }
335     private native boolean setPermission0(File f, int access, boolean enable, boolean owneronly);
336 
337     /* -- File operations -- */
338 
339     @Override
340     public boolean createFileExclusively(String path) throws IOException {
341         if (Thread.currentThread().isVirtual()) {
342             return Blocker.managedBlock(() -> createFileExclusively0(path));
343         } else {
344             return createFileExclusively0(path);
345         }
346     }
347     private native boolean createFileExclusively0(String path) throws IOException;
348 
349     @Override
350     public boolean delete(File f) {
351         // Keep canonicalization caches in sync after file deletion
352         // and renaming operations. Could be more clever than this
353         // (i.e., only remove/update affected entries) but probably
354         // not worth it since these entries expire after 30 seconds
355         // anyway.
356         if (useCanonCaches) {
357             cache.clear();
358         }
359         if (useCanonPrefixCache) {
360             javaHomePrefixCache.clear();
361         }
362         if (Thread.currentThread().isVirtual()) {
363             return Blocker.managedBlock(() -> delete0(f));
364         } else {
365             return delete0(f);
366         }
367     }
368     private native boolean delete0(File f);
369 
370     @Override
371     public String[] list(File f) {
372         if (Thread.currentThread().isVirtual()) {
373             return Blocker.managedBlock(() -> list0(f));
374         } else {
375             return list0(f);
376         }
377     }
378     private native String[] list0(File f);
379 
380     @Override
381     public boolean createDirectory(File f) {
382         if (Thread.currentThread().isVirtual()) {
383             return Blocker.managedBlock(() -> createDirectory0(f));
384         } else {
385             return createDirectory0(f);
386         }
387     }
388     private native boolean createDirectory0(File f);
389 
390     @Override
391     public boolean rename(File f1, File f2) {
392         // Keep canonicalization caches in sync after file deletion
393         // and renaming operations. Could be more clever than this
394         // (i.e., only remove/update affected entries) but probably
395         // not worth it since these entries expire after 30 seconds
396         // anyway.
397         if (useCanonCaches) {
398             cache.clear();
399         }
400         if (useCanonPrefixCache) {
401             javaHomePrefixCache.clear();
402         }
403         if (Thread.currentThread().isVirtual()) {
404             return Blocker.managedBlock(() -> rename0(f1, f2));
405         } else {
406             return rename0(f1, f2);
407         }
408     }
409     private native boolean rename0(File f1, File f2);
410 
411     @Override
412     public boolean setLastModifiedTime(File f, long time) {
413         if (Thread.currentThread().isVirtual()) {
414             return Blocker.managedBlock(() -> setLastModifiedTime0(f, time));
415         } else {
416             return setLastModifiedTime0(f, time);
417         }
418     }
419     private native boolean setLastModifiedTime0(File f, long time);
420 
421     @Override
422     public boolean setReadOnly(File f) {
423         if (Thread.currentThread().isVirtual()) {
424             return Blocker.managedBlock(() -> setReadOnly0(f));
425         } else {
426             return setReadOnly0(f);
427         }
428     }
429     private native boolean setReadOnly0(File f);
430 
431     /* -- Filesystem interface -- */
432 
433     @Override
434     public File[] listRoots() {
435         try {
436             @SuppressWarnings("removal")
437             SecurityManager security = System.getSecurityManager();
438             if (security != null) {
439                 security.checkRead("/");
440             }
441             return new File[] { new File("/") };
442         } catch (SecurityException x) {
443             return new File[0];
444         }
445     }
446 
447     /* -- Disk usage -- */
448 
449     @Override
450     public long getSpace(File f, int t) {
451         if (Thread.currentThread().isVirtual()) {
452             return Blocker.managedBlock(() -> getSpace0(f, t));
453         } else {
454             return getSpace0(f, t);
455         }
456     }
457     private native long getSpace0(File f, int t);
458 
459     /* -- Basic infrastructure -- */
460 
461     private native long getNameMax0(String path);
462 
463     @Override
464     public int getNameMax(String path) {
465         long nameMax = getNameMax0(path);
466         if (nameMax > Integer.MAX_VALUE) {
467             nameMax = Integer.MAX_VALUE;
468         }
469         return (int)nameMax;
470     }
471 
472     @Override
473     public int compare(File f1, File f2) {
474         return f1.getPath().compareTo(f2.getPath());
475     }
476 
477     @Override
< prev index next >