package org.basex.core.cmd; import static org.basex.core.Text.*; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import org.basex.core.Command; import org.basex.core.User; import org.basex.data.MetaData; import org.basex.io.IOFile; import org.basex.util.Util; import org.basex.util.list.StringList; /** * Evaluates the 'copy' command and creates a copy of a database. * * @author BaseX Team 2005-12, BSD License * @author Andreas Weiler */ public final class Copy extends Command { /** Counter for outstanding files. */ private int of; /** Counter of total files. */ private int tf; /** * Default constructor. * @param db db name * @param newdb new db name */ public Copy(final String db, final String newdb) { super(User.CREATE, db, newdb); } @Override protected boolean run() { final String db = args[0]; final String newdb = args[1]; // check if names are valid if(!MetaData.validName(db, false)) return error(NAME_INVALID_X, db); if(!MetaData.validName(newdb, false)) return error(NAME_INVALID_X, newdb); // database does not exist if(!mprop.dbexists(db)) return error(DB_NOT_FOUND_X, db); // target database exists already if(mprop.dbexists(newdb)) return error(DB_EXISTS_X, newdb); // try to copy database return copy(db, newdb) ? info(DB_COPIED_X, db, perf) : error(DB_NOT_COPIED_X, db); } /** * Copies the specified database. * @param db database name * @param newdb new database name * @return success flag */ private boolean copy(final String db, final String newdb) { final File src = mprop.dbpath(db).file(); final File trg = mprop.dbpath(newdb).file(); // return false if source cannot be opened, or target cannot be created final StringList files = new IOFile(src).descendants(); tf = files.size(); boolean ok = true; try { for(final String file : files) { copy(new File(src, file), new File(trg, file)); of++; } } catch(final IOException ex) { Util.debug(ex); ok = false; } // drop new database if error occurred if(!ok) DropDB.drop(newdb, mprop); return ok; } /** * Copies the specified file. * @param src source file * @param trg target file * @throws IOException I/O exception */ public static synchronized void copy(final File src, final File trg) throws IOException { // optimize buffer size final int bsize = (int) Math.max(1, Math.min(src.length(), 1 << 22)); final byte[] buf = new byte[bsize]; FileInputStream fis = null; FileOutputStream fos = null; try { // create parent directory of target file trg.getParentFile().mkdirs(); fis = new FileInputStream(src); fos = new FileOutputStream(trg); // copy file buffer by buffer for(int i; (i = fis.read(buf)) != -1;) fos.write(buf, 0, i); } finally { // close file references if(fis != null) try { fis.close(); } catch(final IOException ex) { } if(fos != null) try { fos.close(); } catch(final IOException ex) { } } } @Override protected String tit() { return COPY; } @Override public boolean supportsProg() { return true; } @Override protected double prog() { return (double) of / tf; } }