/* * ==================================================================== * Copyright (c) 2004-2010 TMate Software Ltd. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://svnkit.com/license.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * ==================================================================== */ package org.tmatesoft.svn.core.internal.wc17.db; import java.io.File; import java.util.ArrayList; import java.util.List; import org.tmatesoft.sqljet.core.SqlJetErrorCode; import org.tmatesoft.sqljet.core.SqlJetException; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.internal.db.SVNSqlJetDb; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.internal.wc2.ng.SvnNgUpgradeSDb; import org.tmatesoft.svn.util.SVNLogType; /** * @author TMate Software Ltd. */ public class SVNWCDbRoot { public static class WCLock { /** Relative path of the lock root */ public File localRelpath; /** Number of levels locked (0 for infinity) */ public int levels; } private SVNWCDb db; /** Location of this wcroot in the filesystem. */ private File absPath; /** * The SQLite database containing the metadata for everything in this * wcroot. */ private SVNSqlJetDb sDb; /** The WCROOT.id for this directory (and all its children). */ private long wcId; /** * The format of this wcroot's metadata storage (see wc.h). If the format * has not (yet) been determined, this will be UNKNOWN_FORMAT. */ private int format; /** * Array of SVNWCDbLock fields. Typically just one or two locks maximum. */ private List<WCLock> ownedLocks = new ArrayList<WCLock>(); public SVNWCDbRoot(SVNWCDb db, File absPath, SVNSqlJetDb sDb, long wcId, int format, boolean autoUpgrade, boolean failOnVersionsMismatch, boolean enforceEmptyWQ) throws SVNException { if (sDb != null) { try { format = sDb.getDb().getOptions().getUserVersion(); } catch (SqlJetException e) { if (e.getErrorCode() == SqlJetErrorCode.NOTADB) { SVNErrorMessage errorMessage = SVNErrorMessage.create(SVNErrorCode.WC_CORRUPT, e); SVNErrorManager.error(errorMessage, SVNLogType.WC); } SVNSqlJetDb.createSqlJetError(e); } } /* If we construct a wcroot, then we better have a format. */ /* This is most probably due to a concurrect db access during db creation */ if (format < 1) { final SqlJetException busyException = new SqlJetException(SqlJetErrorCode.BUSY); SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.SQLITE_ERROR), busyException, SVNLogType.WC); } /* If this working copy is PRE-1.0, then simply bail out. */ if (format < 4) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_UPGRADE_REQUIRED, "Working copy format of ''{0}'' is too old ''{1}''", new Object[] { absPath, format }); SVNErrorManager.error(err, SVNLogType.WC); } if (format > ISVNWCDb.WC_FORMAT_18) { /* If this working copy is from a future version, then bail out. */ SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_UNSUPPORTED_FORMAT, "This client is too old to work with the working copy at\n" + "''{0}'' (format ''{1}'').", new Object[] { absPath, format }); SVNErrorManager.error(err, SVNLogType.WC); } if (failOnVersionsMismatch) { if (format < ISVNWCDb.WC_FORMAT_17) { if (autoUpgrade) { format = SvnNgUpgradeSDb.upgrade(absPath, db, sDb, format, null); } else { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_UPGRADE_REQUIRED, "Working copy format of ''{0}'' is too old ''{1}''", new Object[] { absPath, format }); SVNErrorManager.error(err, SVNLogType.WC); } } } /* * Verify that no work items exists. If they do, then our integrity is * suspect and, thus, we cannot use this database. */ if (format >= ISVNWCDb.WC_HAS_WORK_QUEUE && enforceEmptyWQ) { sDb.verifyNoWork(); } this.db = db; this.absPath = absPath; this.sDb = sDb; this.wcId = wcId; this.format = format; } public SVNWCDb getDb() { return db; } public File getAbsPath() { return absPath; } public SVNSqlJetDb getSDb() { return sDb; } public long getWcId() { return wcId; } public int getFormat() { return format; } public List<WCLock> getOwnedLocks() { return ownedLocks; } public void close() throws SVNException { assert (sDb != null); try { sDb.close(); } finally { sDb = null; } } public File getAbsPath(File localRelPath) { return SVNFileUtil.createFilePath(getAbsPath(), localRelPath); } public void ensureNoUnfinishedTransactions() throws SVNException { if (sDb != null) { if (sDb.getOpenCount() != 0) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.SQLITE_ERROR, "There are unfinished transactions detected in ''{0}''", absPath); SVNErrorManager.error(err, SVNLogType.WC); } } } public File computeRelPath(File localAbsPath) { final String relativePath = SVNPathUtil.getRelativePath(getAbsPath().getPath(), localAbsPath.getPath()); return SVNFileUtil.createFilePath(relativePath); } }