EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.store.fs]

COVERAGE SUMMARY FOR SOURCE FILE [FilePathDisk.java]

nameclass, %method, %block, %line, %
FilePathDisk.java100% (2/2)97%  (36/37)80%  (726/910)73%  (149.1/204)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class FilePathDisk100% (1/1)96%  (25/26)79%  (597/756)70%  (118.2/168)
freeMemoryAndFinalize (): void 0%   (0/1)0%   (0/31)0%   (0/11)
canWriteInternal (File): boolean 100% (1/1)49%  (23/47)52%  (7.3/14)
open (String): FileChannel 100% (1/1)54%  (15/28)40%  (4/10)
toRealPath (): FilePathDisk 100% (1/1)65%  (11/17)50%  (2/4)
createFile (): boolean 100% (1/1)67%  (14/21)45%  (2.7/6)
newInputStream (): InputStream 100% (1/1)68%  (59/87)72%  (13/18)
createDirectory (): void 100% (1/1)77%  (33/43)67%  (6.7/10)
newOutputStream (boolean): OutputStream 100% (1/1)78%  (28/36)70%  (7/10)
moveTo (FilePath, boolean): void 100% (1/1)85%  (117/137)83%  (16.6/20)
newDirectoryStream (): List 100% (1/1)90%  (56/62)83%  (10/12)
createTempFile (String, boolean, boolean): FilePath 100% (1/1)93%  (67/72)80%  (12/15)
wait (int): void 100% (1/1)94%  (15/16)86%  (6/7)
FilePathDisk (): void 100% (1/1)100% (3/3)100% (1/1)
canWrite (): boolean 100% (1/1)100% (7/7)100% (1/1)
delete (): void 100% (1/1)100% (34/34)100% (8/8)
exists (): boolean 100% (1/1)100% (7/7)100% (1/1)
expandUserHomeDirectory (String): String 100% (1/1)100% (27/27)100% (4/4)
getParent (): FilePath 100% (1/1)100% (15/15)100% (2/2)
getPath (String): FilePathDisk 100% (1/1)100% (10/10)100% (3/3)
getScheme (): String 100% (1/1)100% (2/2)100% (1/1)
isAbsolute (): boolean 100% (1/1)100% (7/7)100% (1/1)
isDirectory (): boolean 100% (1/1)100% (7/7)100% (1/1)
lastModified (): long 100% (1/1)100% (7/7)100% (1/1)
setReadOnly (): boolean 100% (1/1)100% (9/9)100% (2/2)
size (): long 100% (1/1)100% (7/7)100% (1/1)
translateFileName (String): String 100% (1/1)100% (17/17)100% (4/4)
     
class FileDisk100% (1/1)100% (11/11)84%  (129/154)86%  (30.8/36)
force (boolean): void 100% (1/1)39%  (16/41)48%  (4.8/10)
FileDisk (String, String): void 100% (1/1)100% (18/18)100% (5/5)
implCloseChannel (): void 100% (1/1)100% (4/4)100% (2/2)
position (): long 100% (1/1)100% (4/4)100% (1/1)
position (long): FileChannel 100% (1/1)100% (6/6)100% (2/2)
read (ByteBuffer): int 100% (1/1)100% (24/24)100% (4/4)
size (): long 100% (1/1)100% (4/4)100% (1/1)
toString (): String 100% (1/1)100% (3/3)100% (1/1)
truncate (long): FileChannel 100% (1/1)100% (19/19)100% (5/5)
tryLock (long, long, boolean): FileLock 100% (1/1)100% (8/8)100% (1/1)
write (ByteBuffer): int 100% (1/1)100% (23/23)100% (4/4)

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

[all classes][org.h2.store.fs]
EMMA 2.0.5312 (C) Vladimir Roubtsov