File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\store\fs\FilePathDisk.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.store.fs;
8
9 import java.io.File;
10 import java.io.FileInputStream;
11 import java.io.FileNotFoundException;
12 import java.io.FileOutputStream;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.OutputStream;
16 import java.io.RandomAccessFile;
17 import java.net.URL;
18 import java.nio.ByteBuffer;
19 import java.nio.channels.FileChannel;
20 import java.nio.channels.FileLock;
21 import java.util.ArrayList;
22 import java.util.List;
23 import org.h2.constant.ErrorCode;
24 import org.h2.constant.SysProperties;
25 import org.h2.message.DbException;
26 import org.h2.util.IOUtils;
27 import org.h2.util.New;
28 import org.h2.util.Utils;
29
30 /**
31 * This file system stores files on disk.
32 * This is the most common file system.
33 */
34 public class FilePathDisk extends FilePath {
35
36 private static final String CLASSPATH_PREFIX = "classpath:";
37
38 public FilePathDisk getPath(String path) {
39 FilePathDisk p = new FilePathDisk();
40 p.name = translateFileName(path);
41 return p;
42 }
43
44 public long size() {
45 return new File(name).length();
46 }
47
48 /**
49 * Translate the file name to the native format. This will replace '\' with
50 * '/' and expand the home directory ('~').
51 *
52 * @param fileName the file name
53 * @return the native file name
54 */
55 protected static String translateFileName(String fileName) {
56 fileName = fileName.replace('\\', '/');
57 if (fileName.startsWith("file:")) {
58 fileName = fileName.substring("file:".length());
59 }
60 return expandUserHomeDirectory(fileName);
61 }
62
63 /**
64 * Expand '~' to the user home directory. It is only be expanded if the '~'
65 * stands alone, or is followed by '/' or '\'.
66 *
67 * @param fileName the file name
68 * @return the native file name
69 */
70 public static String expandUserHomeDirectory(String fileName) {
71 if (fileName.startsWith("~") && (fileName.length() == 1 || fileName.startsWith("~/"))) {
72 String userDir = SysProperties.USER_HOME;
73 fileName = userDir + fileName.substring(1);
74 }
75 return fileName;
76 }
77
78 public void moveTo(FilePath newName) {
79 File oldFile = new File(name);
80 File newFile = new File(newName.name);
81 if (oldFile.getAbsolutePath().equals(newFile.getAbsolutePath())) {
82 return;
83 }
84 if (!oldFile.exists()) {
85 throw DbException.get(ErrorCode.FILE_RENAME_FAILED_2,
86 name + " (not found)",
87 newName.name);
88 }
89 if (newFile.exists()) {
90 throw DbException.get(ErrorCode.FILE_RENAME_FAILED_2,
91 new String[] { name, newName + " (exists)" });
92 }
93 for (int i = 0; i < SysProperties.MAX_FILE_RETRY; i++) {
94 IOUtils.trace("rename", name + " >" + newName, null);
95 boolean ok = oldFile.renameTo(newFile);
96 if (ok) {
97 return;
98 }
99 wait(i);
100 }
101 throw DbException.get(ErrorCode.FILE_RENAME_FAILED_2, new String[]{name, newName.name});
102 }
103
104 private static void wait(int i) {
105 if (i == 8) {
106 System.gc();
107 }
108 try {
109 // sleep at most 256 ms
110 long sleep = Math.min(256, i * i);
111 Thread.sleep(sleep);
112 } catch (InterruptedException e) {
113 // ignore
114 }
115 }
116
117 public boolean createFile() {
118 File file = new File(name);
119 for (int i = 0; i < SysProperties.MAX_FILE_RETRY; i++) {
120 try {
121 return file.createNewFile();
122 } catch (IOException e) {
123 // 'access denied' is really a concurrent access problem
124 wait(i);
125 }
126 }
127 return false;
128 }
129
130 public boolean exists() {
131 return new File(name).exists();
132 }
133
134 public void delete() {
135 File file = new File(name);
136 for (int i = 0; i < SysProperties.MAX_FILE_RETRY; i++) {
137 IOUtils.trace("delete", name, null);
138 boolean ok = file.delete();
139 if (ok || !file.exists()) {
140 return;
141 }
142 wait(i);
143 }
144 throw DbException.get(ErrorCode.FILE_DELETE_FAILED_1, name);
145 }
146
147 public List<FilePath> newDirectoryStream() {
148 ArrayList<FilePath> list = New.arrayList();
149 File f = new File(name);
150 try {
151 String[] files = f.list();
152 if (files != null) {
153 String base = f.getCanonicalPath();
154 if (!base.endsWith(SysProperties.FILE_SEPARATOR)) {
155 base += SysProperties.FILE_SEPARATOR;
156 }
157 for (int i = 0, len = files.length; i < len; i++) {
158 list.add(getPath(base + files[i]));
159 }
160 }
161 return list;
162 } catch (IOException e) {
163 throw DbException.convertIOException(e, name);
164 }
165 }
166
167 public boolean canWrite() {
168 return canWriteInternal(new File(name));
169 }
170
171 public boolean setReadOnly() {
172 File f = new File(name);
173 return f.setReadOnly();
174 }
175
176 public FilePathDisk toRealPath() {
177 try {
178 String fileName = new File(name).getCanonicalPath();
179 return getPath(fileName);
180 } catch (IOException e) {
181 throw DbException.convertIOException(e, name);
182 }
183 }
184
185 public FilePath getParent() {
186 String p = new File(name).getParent();
187 return p == null ? null : getPath(p);
188 }
189
190 public boolean isDirectory() {
191 return new File(name).isDirectory();
192 }
193
194 public boolean isAbsolute() {
195 return new File(name).isAbsolute();
196 }
197
198 public long lastModified() {
199 return new File(name).lastModified();
200 }
201
202 private static boolean canWriteInternal(File file) {
203 try {
204 if (!file.canWrite()) {
205 return false;
206 }
207 } catch (Exception e) {
208 // workaround for GAE which throws a
209 // java.security.AccessControlException
210 return false;
211 }
212 // File.canWrite() does not respect windows user permissions,
213 // so we must try to open it using the mode "rw".
214 // See also http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4420020
215 RandomAccessFile r = null;
216 try {
217 r = new RandomAccessFile(file, "rw");
218 return true;
219 } catch (FileNotFoundException e) {
220 return false;
221 } finally {
222 if (r != null) {
223 try {
224 r.close();
225 } catch (IOException e) {
226 // ignore
227 }
228 }
229 }
230 }
231
232 public void createDirectory() {
233 File f = new File(name);
234 if (f.exists()) {
235 if (f.isDirectory()) {
236 return;
237 }
238 throw DbException.get(ErrorCode.FILE_CREATION_FAILED_1, name + " (a file with this name already exists)");
239 }
240 File dir = new File(name);
241 for (int i = 0; i < SysProperties.MAX_FILE_RETRY; i++) {
242 if ((dir.exists() && dir.isDirectory()) || dir.mkdir()) {
243 return;
244 }
245 wait(i);
246 }
247 throw DbException.get(ErrorCode.FILE_CREATION_FAILED_1, name);
248 }
249
250 public OutputStream newOutputStream(boolean append) {
251 try {
252 File file = new File(name);
253 File parent = file.getParentFile();
254 if (parent != null) {
255 FileUtils.createDirectories(parent.getAbsolutePath());
256 }
257 FileOutputStream out = new FileOutputStream(name, append);
258 IOUtils.trace("openFileOutputStream", name, out);
259 return out;
260 } catch (IOException e) {
261 freeMemoryAndFinalize();
262 try {
263 return new FileOutputStream(name);
264 } catch (IOException e2) {
265 throw DbException.convertIOException(e, name);
266 }
267 }
268 }
269
270 public InputStream newInputStream() throws IOException {
271 int index = name.indexOf(':');
272 if (index > 1 && index < 20) {
273 // if the ':' is in position 1, a windows file access is assumed: C:.. or D:
274 // if the ':' is not at the beginning, assume its a file name with a colon
275 if (name.startsWith(CLASSPATH_PREFIX)) {
276 String fileName = name.substring(CLASSPATH_PREFIX.length());
277 if (!fileName.startsWith("/")) {
278 fileName = "/" + fileName;
279 }
280 InputStream in = getClass().getResourceAsStream(fileName);
281 if (in == null) {
282 in = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
283 }
284 if (in == null) {
285 throw new FileNotFoundException("resource " + fileName);
286 }
287 return in;
288 }
289 // otherwise an URL is assumed
290 URL url = new URL(name);
291 InputStream in = url.openStream();
292 return in;
293 }
294 FileInputStream in = new FileInputStream(name);
295 IOUtils.trace("openFileInputStream", name, in);
296 return in;
297 }
298
299 /**
300 * Call the garbage collection and run finalization. This close all files that
301 * were not closed, and are no longer referenced.
302 */
303 static void freeMemoryAndFinalize() {
304 IOUtils.trace("freeMemoryAndFinalize", null, null);
305 Runtime rt = Runtime.getRuntime();
306 long mem = rt.freeMemory();
307 for (int i = 0; i < 16; i++) {
308 rt.gc();
309 long now = rt.freeMemory();
310 rt.runFinalization();
311 if (now == mem) {
312 break;
313 }
314 mem = now;
315 }
316 }
317
318 public FileChannel open(String mode) throws IOException {
319 FileDisk f;
320 try {
321 f = new FileDisk(name, mode);
322 IOUtils.trace("open", name, f);
323 } catch (IOException e) {
324 freeMemoryAndFinalize();
325 try {
326 f = new FileDisk(name, mode);
327 } catch (IOException e2) {
328 throw e;
329 }
330 }
331 return f;
332 }
333
334 public String getScheme() {
335 return "file";
336 }
337
338 public FilePath createTempFile(String suffix, boolean deleteOnExit, boolean inTempDir)
339 throws IOException {
340 String fileName = name + ".";
341 String prefix = new File(fileName).getName();
342 File dir;
343 if (inTempDir) {
344 dir = new File(Utils.getProperty("java.io.tmpdir", "."));
345 } else {
346 dir = new File(fileName).getAbsoluteFile().getParentFile();
347 }
348 FileUtils.createDirectories(dir.getAbsolutePath());
349 while (true) {
350 File f = new File(dir, prefix + getNextTempFileNamePart(false) + suffix);
351 if (f.exists() || !f.createNewFile()) {
352 // in theory, the random number could collide
353 getNextTempFileNamePart(true);
354 continue;
355 }
356 if (deleteOnExit) {
357 try {
358 f.deleteOnExit();
359 } catch (Throwable e) {
360 // sometimes this throws a NullPointerException
361 // at java.io.DeleteOnExitHook.add(DeleteOnExitHook.java:33)
362 // we can ignore it
363 }
364 }
365 return get(f.getCanonicalPath());
366 }
367 }
368
369 }
370
371 /**
372 * Uses java.io.RandomAccessFile to access a file.
373 */
374 class FileDisk extends FileBase {
375
376 private final RandomAccessFile file;
377 private final String name;
378
379 FileDisk(String fileName, String mode) throws FileNotFoundException {
380 this.file = new RandomAccessFile(fileName, mode);
381 this.name = fileName;
382 }
383
384 public void force(boolean metaData) throws IOException {
385 String m = SysProperties.SYNC_METHOD;
386 if ("".equals(m)) {
387 // do nothing
388 } else if ("sync".equals(m)) {
389 file.getFD().sync();
390 } else if ("force".equals(m)) {
391 file.getChannel().force(true);
392 } else if ("forceFalse".equals(m)) {
393 file.getChannel().force(false);
394 } else {
395 file.getFD().sync();
396 }
397 }
398
399 public FileChannel truncate(long newLength) throws IOException {
400 if (newLength < file.length()) {
401 // some implementations actually only support truncate
402 file.setLength(newLength);
403 }
404 return this;
405 }
406
407 public synchronized FileLock tryLock(long position, long size, boolean shared) throws IOException {
408 return file.getChannel().tryLock(position, size, shared);
409 }
410
411 public void implCloseChannel() throws IOException {
412 file.close();
413 }
414
415 public long position() throws IOException {
416 return file.getFilePointer();
417 }
418
419 public long size() throws IOException {
420 return file.length();
421 }
422
423 public int read(ByteBuffer dst) throws IOException {
424 int len = file.read(dst.array(), dst.position(), dst.remaining());
425 if (len > 0) {
426 dst.position(dst.position() + len);
427 }
428 return len;
429 }
430
431 public FileChannel position(long pos) throws IOException {
432 file.seek(pos);
433 return this;
434 }
435
436 public int write(ByteBuffer src) throws IOException {
437 int len = src.remaining();
438 file.write(src.array(), src.position(), len);
439 src.position(src.position() + len);
440 return len;
441 }
442
443 public String toString() {
444 return name;
445 }
446
447 }
448