comparison src/org/tmatesoft/hg/internal/FileUtils.java @ 617:65c01508f002

Rollback support for commands that modify repository. Strategy to keep complete copy of a file being changed
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 15 May 2013 20:10:09 +0200
parents
children 7c0d2ce340b8
comparison
equal deleted inserted replaced
616:5e0313485eef 617:65c01508f002
1 /*
2 * Copyright (c) 2013 TMate Software Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * For information on how to redistribute this software under
14 * the terms of a license other than GNU General Public License
15 * contact TMate Software at support@hg4j.com
16 */
17 package org.tmatesoft.hg.internal;
18
19 import static org.tmatesoft.hg.util.LogFacility.Severity.Debug;
20
21 import java.io.Closeable;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.nio.channels.FileChannel;
27
28 import org.tmatesoft.hg.core.HgIOException;
29 import org.tmatesoft.hg.util.LogFacility;
30 import org.tmatesoft.hg.util.LogFacility.Severity;
31
32 /**
33 *
34 * @author Artem Tikhomirov
35 * @author TMate Software Ltd.
36 */
37 final class FileUtils {
38
39 private final LogFacility log;
40
41 public static void copyFile(File from, File to) throws HgIOException {
42 new FileUtils(new StreamLogFacility(Debug, true, System.err)).copy(from, to);
43 }
44
45 public FileUtils(LogFacility logFacility) {
46 log = logFacility;
47 }
48
49 public void copy(File from, File to) throws HgIOException {
50 FileInputStream fis = null;
51 FileOutputStream fos = null;
52 try {
53 fis = new FileInputStream(from);
54 fos = new FileOutputStream(to);
55 FileChannel input = fis.getChannel();
56 FileChannel output = fos.getChannel();
57 long count = input.size();
58 long pos = 0;
59 int zeroCopied = 0; // flag to prevent hang-up
60 do {
61 long c = input.transferTo(pos, count, output);
62 pos += c;
63 count -= c;
64 if (c == 0) {
65 if (++zeroCopied == 3) {
66 String m = String.format("Can't copy %s to %s, transferTo copies 0 bytes. Position: %d, bytes left:%d", from.getName(), to.getName(), pos, count);
67 throw new IOException(m);
68 }
69 } else {
70 // reset
71 zeroCopied = 0;
72 }
73 } while (count > 0);
74 fos.close();
75 fos = null;
76 fis.close();
77 fis = null;
78 } catch (IOException ex) {
79 // not in finally because I don't want to loose exception from fos.close()
80 closeQuietly(fis);
81 closeQuietly(fos);
82 String m = String.format("Failed to copy %s to %s", from.getName(), to.getName());
83 throw new HgIOException(m, ex, from);
84 }
85 }
86
87 public void closeQuietly(Closeable stream) {
88 if (stream != null) {
89 try {
90 stream.close();
91 } catch (IOException ex) {
92 // ignore
93 log.dump(getClass(), Severity.Warn, ex, "Exception while closing stream quietly");
94 }
95 }
96 }
97
98 }