1 /*
2  * Copyright (c) 2009, 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 java.nio.file;
27 
28 import java.util.Set;
29 import java.util.EnumSet;
30 import java.security.SecureRandom;
31 import static java.security.AccessController.*;
32 import java.io.IOException;
33 import java.nio.file.attribute.FileAttribute;
34 import java.nio.file.attribute.PosixFilePermission;
35 import java.nio.file.attribute.PosixFilePermissions;
36 import static java.nio.file.attribute.PosixFilePermission.*;
37 import sun.security.action.GetPropertyAction;
38 
39 
40 /**
41  * Helper class to support creation of temporary files and directories with
42  * initial attributes.
43  */
44 
45 class TempFileHelper {
TempFileHelper()46     private TempFileHelper() { }
47 
48     // temporary directory location
49     private static final Path tmpdir =
50         Paths.get(doPrivileged(new GetPropertyAction("java.io.tmpdir")));
51 
52     private static final boolean isPosix =
53         FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
54 
55     // file name generation, same as java.io.File for now
56     private static final SecureRandom random = new SecureRandom();
generatePath(String prefix, String suffix, Path dir)57     private static Path generatePath(String prefix, String suffix, Path dir) {
58         long n = random.nextLong();
59         n = (n == Long.MIN_VALUE) ? 0 : Math.abs(n);
60         Path name = dir.getFileSystem().getPath(prefix + Long.toString(n) + suffix);
61         // the generated name should be a simple file name
62         if (name.getParent() != null)
63             throw new IllegalArgumentException("Invalid prefix or suffix");
64         return dir.resolve(name);
65     }
66 
67     // default file and directory permissions (lazily initialized)
68     private static class PosixPermissions {
69         static final FileAttribute<Set<PosixFilePermission>> filePermissions =
70             PosixFilePermissions.asFileAttribute(EnumSet.of(OWNER_READ, OWNER_WRITE));
71         static final FileAttribute<Set<PosixFilePermission>> dirPermissions =
72             PosixFilePermissions.asFileAttribute(EnumSet
73                 .of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE));
74     }
75 
76     /**
77      * Creates a file or directory in in the given given directory (or in the
78      * temporary directory if dir is {@code null}).
79      */
create(Path dir, String prefix, String suffix, boolean createDirectory, FileAttribute<?>[] attrs)80     private static Path create(Path dir,
81                                String prefix,
82                                String suffix,
83                                boolean createDirectory,
84                                FileAttribute<?>[] attrs)
85         throws IOException
86     {
87         if (prefix == null)
88             prefix = "";
89         if (suffix == null)
90             suffix = (createDirectory) ? "" : ".tmp";
91         if (dir == null)
92             dir = tmpdir;
93 
94         // in POSIX environments use default file and directory permissions
95         // if initial permissions not given by caller.
96         if (isPosix && (dir.getFileSystem() == FileSystems.getDefault())) {
97             if (attrs.length == 0) {
98                 // no attributes so use default permissions
99                 attrs = new FileAttribute<?>[1];
100                 attrs[0] = (createDirectory) ? PosixPermissions.dirPermissions :
101                                                PosixPermissions.filePermissions;
102             } else {
103                 // check if posix permissions given; if not use default
104                 boolean hasPermissions = false;
105                 for (int i=0; i<attrs.length; i++) {
106                     if (attrs[i].name().equals("posix:permissions")) {
107                         hasPermissions = true;
108                         break;
109                     }
110                 }
111                 if (!hasPermissions) {
112                     FileAttribute<?>[] copy = new FileAttribute<?>[attrs.length+1];
113                     System.arraycopy(attrs, 0, copy, 0, attrs.length);
114                     attrs = copy;
115                     attrs[attrs.length-1] = (createDirectory) ?
116                         PosixPermissions.dirPermissions :
117                         PosixPermissions.filePermissions;
118                 }
119             }
120         }
121 
122         // loop generating random names until file or directory can be created
123         SecurityManager sm = System.getSecurityManager();
124         for (;;) {
125             Path f;
126             try {
127                 f = generatePath(prefix, suffix, dir);
128             } catch (InvalidPathException e) {
129                 // don't reveal temporary directory location
130                 if (sm != null)
131                     throw new IllegalArgumentException("Invalid prefix or suffix");
132                 throw e;
133             }
134             try {
135                 if (createDirectory) {
136                     return Files.createDirectory(f, attrs);
137                 } else {
138                     return Files.createFile(f, attrs);
139                 }
140             } catch (SecurityException e) {
141                 // don't reveal temporary directory location
142                 if (dir == tmpdir && sm != null)
143                     throw new SecurityException("Unable to create temporary file or directory");
144                 throw e;
145             } catch (FileAlreadyExistsException e) {
146                 // ignore
147             }
148         }
149     }
150 
151     /**
152      * Creates a temporary file in the given directory, or in in the
153      * temporary directory if dir is {@code null}.
154      */
createTempFile(Path dir, String prefix, String suffix, FileAttribute<?>[] attrs)155     static Path createTempFile(Path dir,
156                                String prefix,
157                                String suffix,
158                                FileAttribute<?>[] attrs)
159         throws IOException
160     {
161         return create(dir, prefix, suffix, false, attrs);
162     }
163 
164     /**
165      * Creates a temporary directory in the given directory, or in in the
166      * temporary directory if dir is {@code null}.
167      */
createTempDirectory(Path dir, String prefix, FileAttribute<?>[] attrs)168     static Path createTempDirectory(Path dir,
169                                     String prefix,
170                                     FileAttribute<?>[] attrs)
171         throws IOException
172     {
173         return create(dir, prefix, null, true, attrs);
174     }
175 }
176