1 | /* |
2 | |
3 | Derby - Class org.apache.derby.impl.io.DirFile |
4 | |
5 | Copyright 2004 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | |
21 | package org.apache.derby.impl.io; |
22 | |
23 | import org.apache.derby.io.StorageFile; |
24 | import org.apache.derby.io.StorageRandomAccessFile; |
25 | |
26 | import org.apache.derby.iapi.services.sanity.SanityManager; |
27 | |
28 | import java.io.File; |
29 | import java.io.InputStream; |
30 | import java.io.OutputStream; |
31 | import java.io.FileOutputStream; |
32 | import java.io.FileInputStream; |
33 | import java.io.IOException; |
34 | import java.io.FileNotFoundException; |
35 | import java.io.RandomAccessFile; |
36 | import java.net.MalformedURLException; |
37 | import java.net.URL; |
38 | |
39 | /** |
40 | * This class provides a disk based implementation of the StorageFile interface. It is used by the |
41 | * database engine to access persistent data and transaction logs under the directory (default) subsubprotocol. |
42 | */ |
43 | class DirFile extends File implements StorageFile |
44 | { |
45 | |
46 | /** |
47 | * Construct a DirFile from a path name. |
48 | * |
49 | * @param path The path name. |
50 | */ |
51 | DirFile( String path) |
52 | { |
53 | super( path); |
54 | } |
55 | |
56 | /** |
57 | * Construct a DirFile from a directory name and a file name. |
58 | * |
59 | * @param directoryName The directory part of the path name. |
60 | * @param fileName The name of the file within the directory. |
61 | */ |
62 | DirFile( String directoryName, String fileName) |
63 | { |
64 | super( directoryName, fileName); |
65 | } |
66 | |
67 | /** |
68 | * Construct a DirFile from a directory name and a file name. |
69 | * |
70 | * @param directoryName The directory part of the path name. |
71 | * @param fileName The name of the file within the directory. |
72 | */ |
73 | DirFile( DirFile directoryName, String fileName) |
74 | { |
75 | super( (File) directoryName, fileName); |
76 | } |
77 | |
78 | /** |
79 | * Get the name of the parent directory if this name includes a parent. |
80 | * |
81 | * @return An StorageFile denoting the parent directory of this StorageFile, if it has a parent, null if |
82 | * it does not have a parent. |
83 | */ |
84 | public StorageFile getParentDir() |
85 | { |
86 | String parent = getParent(); |
87 | if( parent == null) |
88 | return null; |
89 | return new DirFile( parent); |
90 | } |
91 | |
92 | /** |
93 | * Get the name of the directory of temporary files. |
94 | * |
95 | * @return The abstract name of the temp directory; |
96 | */ |
97 | static StorageFile getTempDir() throws IOException |
98 | { |
99 | File temp = File.createTempFile("derby", "tmp"); |
100 | StorageFile parent = new DirFile( temp.getParent()); |
101 | temp.delete(); |
102 | |
103 | return parent; |
104 | } // End of getTempDir |
105 | |
106 | /** |
107 | * Creates an output stream from a file name. |
108 | * |
109 | * @return an output stream suitable for writing to the file. |
110 | * |
111 | * @exception FileNotFoundException if the file exists but is a directory |
112 | * rather than a regular file, does not exist but cannot be created, or |
113 | * cannot be opened for any other reason. |
114 | */ |
115 | public OutputStream getOutputStream( ) throws FileNotFoundException |
116 | { |
117 | return new FileOutputStream( (File) this); |
118 | } |
119 | |
120 | /** |
121 | * Creates an output stream from a file name. |
122 | * |
123 | * @param append If true then data will be appended to the end of the file, if it already exists. |
124 | * If false and a normal file already exists with this name the file will first be truncated |
125 | * to zero length. |
126 | * |
127 | * @return an output stream suitable for writing to the file. |
128 | * |
129 | * @exception FileNotFoundException if the file exists but is a directory |
130 | * rather than a regular file, does not exist but cannot be created, or |
131 | * cannot be opened for any other reason. |
132 | */ |
133 | public OutputStream getOutputStream( final boolean append) throws FileNotFoundException |
134 | { |
135 | return new FileOutputStream( getPath(), append); |
136 | } |
137 | |
138 | /** |
139 | * Creates an input stream from a file name. |
140 | * |
141 | * @return an input stream suitable for reading from the file. |
142 | * |
143 | * @exception FileNotFoundException if the file is not found. |
144 | */ |
145 | public InputStream getInputStream( ) throws FileNotFoundException |
146 | { |
147 | return new FileInputStream( (File) this); |
148 | } |
149 | |
150 | /** |
151 | * Get an exclusive lock. This is used to ensure that two or more JVMs do not open the same database |
152 | * at the same time. |
153 | * |
154 | * |
155 | * @return EXCLUSIVE_FILE_LOCK_NOT_AVAILABLE if the lock cannot be acquired because it is already held.<br> |
156 | * EXCLUSIVE_FILE_LOCK if the lock was successfully acquired.<br> |
157 | * NO_FILE_LOCK_SUPPORT if the system does not support exclusive locks.<br> |
158 | */ |
159 | public synchronized int getExclusiveFileLock() |
160 | { |
161 | if (exists()) |
162 | { |
163 | delete(); |
164 | } |
165 | try |
166 | { |
167 | //Just create an empty file |
168 | RandomAccessFile lockFileOpen = new RandomAccessFile( (File) this, "rw"); |
169 | lockFileOpen.getFD().sync( ); |
170 | lockFileOpen.close(); |
171 | }catch(IOException ioe) |
172 | { |
173 | // do nothing - it may be read only medium, who knows what the |
174 | // problem is |
175 | if (SanityManager.DEBUG) |
176 | { |
177 | SanityManager.THROWASSERT("Unable to create Exclusive Lock File " + getPath()); |
178 | } |
179 | } |
180 | |
181 | return NO_FILE_LOCK_SUPPORT; |
182 | } // end of getExclusiveFileLock |
183 | |
184 | /** |
185 | * Release the resource associated with an earlier acquired exclusive lock |
186 | * |
187 | * @see #getExclusiveFileLock |
188 | */ |
189 | public synchronized void releaseExclusiveFileLock() |
190 | { |
191 | if( exists()) |
192 | { |
193 | delete(); |
194 | } |
195 | } // End of releaseExclusiveFileLock |
196 | |
197 | /** |
198 | * Get a random access (read/write) file. |
199 | * |
200 | * @param mode "r", "rw", "rws", or "rwd". The "rws" and "rwd" modes specify |
201 | * that the data is to be written to persistent store, consistent with the |
202 | * java.io.RandomAccessFile class ("synchronized" with the persistent |
203 | * storage, in the file system meaning of the word "synchronized"). However |
204 | * the implementation is not required to implement the "rws" or "rwd" |
205 | * modes. The implementation may treat "rws" and "rwd" as "rw". It is up to |
206 | * the user of this interface to call the StorageRandomAccessFile.sync |
207 | * method. If the "rws" or "rwd" modes are supported and the |
208 | * RandomAccessFile was opened in "rws" or "rwd" mode then the |
209 | * implementation of StorageRandomAccessFile.sync need not do anything. |
210 | * |
211 | * @return an object that can be used for random access to the file. |
212 | * |
213 | * @exception IllegalArgumentException if the mode argument is not equal to one of "r", "rw". |
214 | * @exception FileNotFoundException if the file exists but is a directory rather than a regular |
215 | * file, or cannot be opened or created for any other reason . |
216 | */ |
217 | public StorageRandomAccessFile getRandomAccessFile( String mode) throws FileNotFoundException |
218 | { |
219 | // Assume that modes "rws" and "rwd" are not supported. |
220 | if( "rws".equals( mode) || "rwd".equals( mode)) |
221 | mode = "rw"; |
222 | return new DirRandomAccessFile( (File) this, mode); |
223 | } // end of getRandomAccessFile |
224 | |
225 | /** |
226 | * Rename the file denoted by this name. Note that StorageFile objects are immutable. This method |
227 | * renames the underlying file, it does not change this StorageFile object. The StorageFile object denotes the |
228 | * same name as before, however the exists() method will return false after the renameTo method |
229 | * executes successfully. |
230 | * |
231 | *<p>It is not specified whether this method will succeed if a file already exists under the new name. |
232 | * |
233 | * @param newName the new name. |
234 | * |
235 | * @return <b>true</b> if the rename succeeded, <b>false</b> if not. |
236 | */ |
237 | public boolean renameTo( StorageFile newName) |
238 | { |
239 | return super.renameTo( (File) newName); |
240 | } |
241 | |
242 | /** |
243 | * Deletes the named file and, if it is a directory, all the files and directories it contains. |
244 | * |
245 | * @return <b>true</b> if the named file or directory is successfully deleted, <b>false</b> if not |
246 | */ |
247 | public boolean deleteAll() |
248 | { |
249 | if( !exists()) |
250 | return false; |
251 | if( isDirectory()) |
252 | { |
253 | String[] childList = super.list(); |
254 | String parentName = getPath(); |
255 | for( int i = 0; i < childList.length; i++) |
256 | { |
257 | if( childList[i].equals( ".") || childList[i].equals( "..")) |
258 | continue; |
259 | DirFile child = new DirFile( parentName, childList[i]); |
260 | if( ! child.deleteAll()) |
261 | return false; |
262 | } |
263 | } |
264 | return delete(); |
265 | } // end of deleteAll |
266 | |
267 | /** |
268 | * @see org.apache.derby.io.StorageFile#getURL() |
269 | */ |
270 | public URL getURL() throws MalformedURLException { |
271 | |
272 | return toURL(); |
273 | } |
274 | } |