tikhomirov@617: /* tikhomirov@617: * Copyright (c) 2013 TMate Software Ltd tikhomirov@617: * tikhomirov@617: * This program is free software; you can redistribute it and/or modify tikhomirov@617: * it under the terms of the GNU General Public License as published by tikhomirov@617: * the Free Software Foundation; version 2 of the License. tikhomirov@617: * tikhomirov@617: * This program is distributed in the hope that it will be useful, tikhomirov@617: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@617: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@617: * GNU General Public License for more details. tikhomirov@617: * tikhomirov@617: * For information on how to redistribute this software under tikhomirov@617: * the terms of a license other than GNU General Public License tikhomirov@617: * contact TMate Software at support@hg4j.com tikhomirov@617: */ tikhomirov@617: package org.tmatesoft.hg.internal; tikhomirov@617: tikhomirov@617: import static org.tmatesoft.hg.util.LogFacility.Severity.Debug; tikhomirov@617: tikhomirov@617: import java.io.Closeable; tikhomirov@617: import java.io.File; tikhomirov@617: import java.io.FileInputStream; tikhomirov@617: import java.io.FileOutputStream; tikhomirov@617: import java.io.IOException; tikhomirov@697: import java.io.InputStream; tikhomirov@617: import java.nio.channels.FileChannel; tikhomirov@617: tikhomirov@617: import org.tmatesoft.hg.core.HgIOException; tikhomirov@617: import org.tmatesoft.hg.util.LogFacility; tikhomirov@617: import org.tmatesoft.hg.util.LogFacility.Severity; tikhomirov@617: tikhomirov@617: /** tikhomirov@617: * tikhomirov@617: * @author Artem Tikhomirov tikhomirov@617: * @author TMate Software Ltd. tikhomirov@617: */ tikhomirov@619: public final class FileUtils { tikhomirov@617: tikhomirov@617: private final LogFacility log; tikhomirov@654: private final Class troublemaker; tikhomirov@617: tikhomirov@617: public static void copyFile(File from, File to) throws HgIOException { tikhomirov@654: new FileUtils(new StreamLogFacility(Debug, true, System.err), FileUtils.class).copy(from, to); tikhomirov@617: } tikhomirov@617: tikhomirov@654: public FileUtils(LogFacility logFacility, Object troubleSource) { tikhomirov@617: log = logFacility; tikhomirov@654: if (troubleSource == null) { tikhomirov@654: troublemaker = null; tikhomirov@654: } else { tikhomirov@654: troublemaker = troubleSource instanceof Class ? (Class) troubleSource : troubleSource.getClass(); tikhomirov@654: } tikhomirov@617: } tikhomirov@617: tikhomirov@617: public void copy(File from, File to) throws HgIOException { tikhomirov@617: FileInputStream fis = null; tikhomirov@617: FileOutputStream fos = null; tikhomirov@617: try { tikhomirov@617: fis = new FileInputStream(from); tikhomirov@617: fos = new FileOutputStream(to); tikhomirov@617: FileChannel input = fis.getChannel(); tikhomirov@617: FileChannel output = fos.getChannel(); tikhomirov@617: long count = input.size(); tikhomirov@617: long pos = 0; tikhomirov@617: int zeroCopied = 0; // flag to prevent hang-up tikhomirov@617: do { tikhomirov@617: long c = input.transferTo(pos, count, output); tikhomirov@617: pos += c; tikhomirov@617: count -= c; tikhomirov@617: if (c == 0) { tikhomirov@617: if (++zeroCopied == 3) { tikhomirov@617: 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); tikhomirov@617: throw new IOException(m); tikhomirov@617: } tikhomirov@617: } else { tikhomirov@617: // reset tikhomirov@617: zeroCopied = 0; tikhomirov@617: } tikhomirov@617: } while (count > 0); tikhomirov@617: fos.close(); tikhomirov@617: fos = null; tikhomirov@617: fis.close(); tikhomirov@617: fis = null; tikhomirov@617: } catch (IOException ex) { tikhomirov@617: // not in finally because I don't want to loose exception from fos.close() tikhomirov@636: closeQuietly(fis, from); tikhomirov@636: closeQuietly(fos, to); tikhomirov@617: String m = String.format("Failed to copy %s to %s", from.getName(), to.getName()); tikhomirov@617: throw new HgIOException(m, ex, from); tikhomirov@617: } tikhomirov@624: /* Copy of cpython's 00changelog.d, 20Mb+ tikhomirov@624: * Linux&Windows: 300-400 ms, tikhomirov@624: * Windows uncached run: 1.6 seconds tikhomirov@624: */ tikhomirov@617: } tikhomirov@697: tikhomirov@697: public void write(InputStream is, File file) throws IOException { tikhomirov@697: FileOutputStream fos = new FileOutputStream(file); tikhomirov@697: int r; tikhomirov@697: byte[] buf = new byte[8*1024]; tikhomirov@697: while ((r = is.read(buf)) != -1) { tikhomirov@697: fos.write(buf, 0, r); tikhomirov@697: } tikhomirov@697: fos.flush(); tikhomirov@697: fos.close(); tikhomirov@697: } tikhomirov@705: tikhomirov@617: public void closeQuietly(Closeable stream) { tikhomirov@636: closeQuietly(stream, null); tikhomirov@636: } tikhomirov@636: tikhomirov@636: public void closeQuietly(Closeable stream, File f) { tikhomirov@617: if (stream != null) { tikhomirov@617: try { tikhomirov@617: stream.close(); tikhomirov@617: } catch (IOException ex) { tikhomirov@617: // ignore tikhomirov@636: final String msg; tikhomirov@636: if (f == null) { tikhomirov@636: msg = "Exception while closing stream quietly"; tikhomirov@636: } else { tikhomirov@636: msg = String.format("Failed to close %s", f); tikhomirov@636: } tikhomirov@654: log.dump(troublemaker == null ? getClass() : troublemaker, Severity.Warn, ex, msg); tikhomirov@617: } tikhomirov@617: } tikhomirov@617: } tikhomirov@705: tikhomirov@705: // nothing special, just a single place with common prefix tikhomirov@705: public File createTempFile() throws IOException { tikhomirov@705: return File.createTempFile("hg4j-", null); tikhomirov@705: } tikhomirov@617: }