Source Code Cross Referenced for FSFS.java in  » Source-Control » tmatesoft-SVN » org » tmatesoft » svn » core » internal » io » fs » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Source Control » tmatesoft SVN » org.tmatesoft.svn.core.internal.io.fs 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * ====================================================================
0003:         * Copyright (c) 2004-2008 TMate Software Ltd.  All rights reserved.
0004:         *
0005:         * This software is licensed as described in the file COPYING, which
0006:         * you should have received as part of this distribution.  The terms
0007:         * are also available at http://svnkit.com/license.html
0008:         * If newer versions of this license are posted there, you may use a
0009:         * newer version instead, at your option.
0010:         * ====================================================================
0011:         */
0012:        package org.tmatesoft.svn.core.internal.io.fs;
0013:
0014:        import java.io.File;
0015:        import java.io.FileNotFoundException;
0016:        import java.io.IOException;
0017:        import java.io.OutputStream;
0018:        import java.security.MessageDigest;
0019:        import java.security.NoSuchAlgorithmException;
0020:        import java.util.ArrayList;
0021:        import java.util.Collection;
0022:        import java.util.Collections;
0023:        import java.util.Date;
0024:        import java.util.HashMap;
0025:        import java.util.Iterator;
0026:        import java.util.LinkedList;
0027:        import java.util.Map;
0028:
0029:        import org.tmatesoft.svn.core.SVNErrorCode;
0030:        import org.tmatesoft.svn.core.SVNErrorMessage;
0031:        import org.tmatesoft.svn.core.SVNException;
0032:        import org.tmatesoft.svn.core.SVNLock;
0033:        import org.tmatesoft.svn.core.SVNNodeKind;
0034:        import org.tmatesoft.svn.core.SVNProperty;
0035:        import org.tmatesoft.svn.core.SVNRevisionProperty;
0036:        import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
0037:        import org.tmatesoft.svn.core.internal.util.SVNTimeUtil;
0038:        import org.tmatesoft.svn.core.internal.util.SVNUUIDGenerator;
0039:        import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
0040:        import org.tmatesoft.svn.core.internal.wc.SVNFileListUtil;
0041:        import org.tmatesoft.svn.core.internal.wc.SVNFileType;
0042:        import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
0043:        import org.tmatesoft.svn.core.internal.wc.SVNProperties;
0044:        import org.tmatesoft.svn.core.io.ISVNLockHandler;
0045:
0046:        /**
0047:         * @version 1.1.1
0048:         * @author  TMate Software Ltd.
0049:         */
0050:        public class FSFS {
0051:            public static final String SVN_REPOS_DB_DIR = "db";
0052:            public static final String TXN_PATH_EXT = ".txn";
0053:            public static final String TXN_PATH_EXT_CHILDREN = ".children";
0054:            public static final String PATH_PREFIX_NODE = "node.";
0055:            public static final String TXN_PATH_EXT_PROPS = ".props";
0056:            public static final int DIGEST_SUBDIR_LEN = 3;
0057:            public static final String SVN_OPAQUE_LOCK_TOKEN = "opaquelocktoken:";
0058:            public static final String TXN_PATH_REV = "rev";
0059:            public static final String PATH_LOCK_KEY = "path";
0060:            public static final String CHILDREN_LOCK_KEY = "children";
0061:            public static final String TOKEN_LOCK_KEY = "token";
0062:            public static final String OWNER_LOCK_KEY = "owner";
0063:            public static final String IS_DAV_COMMENT_LOCK_KEY = "is_dav_comment";
0064:            public static final String CREATION_DATE_LOCK_KEY = "creation_date";
0065:            public static final String EXPIRATION_DATE_LOCK_KEY = "expiration_date";
0066:            public static final String COMMENT_LOCK_KEY = "comment";
0067:
0068:            private static final int REPOSITORY_FORMAT = 5;
0069:            private static final int DB_FORMAT = 2;
0070:            private static final String DB_TYPE = "fsfs";
0071:
0072:            private int myDBFormat;
0073:            private int myReposFormat;
0074:
0075:            private String myUUID;
0076:
0077:            private File myRepositoryRoot;
0078:            private File myRevisionsRoot;
0079:            private File myRevisionPropertiesRoot;
0080:            private File myTransactionsRoot;
0081:            private File myLocksRoot;
0082:            private File myDBRoot;
0083:            private File myWriteLockFile;
0084:            private File myCurrentFile;
0085:
0086:            public FSFS(File repositoryRoot) {
0087:                myRepositoryRoot = repositoryRoot;
0088:                myDBRoot = new File(myRepositoryRoot, "db");
0089:                myRevisionsRoot = new File(myDBRoot, "revs");
0090:                myRevisionPropertiesRoot = new File(myDBRoot, "revprops");
0091:                myTransactionsRoot = new File(myDBRoot, "transactions");
0092:                myWriteLockFile = new File(myDBRoot, "write-lock");
0093:                myLocksRoot = new File(myDBRoot, "locks");
0094:            }
0095:
0096:            public int getDBFormat() {
0097:                return myDBFormat;
0098:            }
0099:
0100:            public int getReposFormat() {
0101:                return myReposFormat;
0102:            }
0103:
0104:            public void open() throws SVNException {
0105:                // repo format /root/format
0106:                FSFile formatFile = new FSFile(new File(myRepositoryRoot,
0107:                        "format"));
0108:                int format = -1;
0109:                try {
0110:                    format = formatFile.readInt();
0111:                } finally {
0112:                    formatFile.close();
0113:                }
0114:                if (format > REPOSITORY_FORMAT) {
0115:                    SVNErrorMessage err = SVNErrorMessage
0116:                            .create(
0117:                                    SVNErrorCode.REPOS_UNSUPPORTED_VERSION,
0118:                                    "Expected format ''{0,number,integer}'' of repository; found format ''{1,number,integer}''",
0119:                                    new Object[] {
0120:                                            new Integer(REPOSITORY_FORMAT),
0121:                                            new Integer(format) });
0122:                    SVNErrorManager.error(err);
0123:                }
0124:                myReposFormat = format;
0125:                // fs format /root/db/format
0126:                formatFile = new FSFile(new File(myDBRoot, "format"));
0127:                try {
0128:                    format = formatFile.readInt();
0129:                } catch (SVNException svne) {
0130:                    if (svne.getCause() instanceof  FileNotFoundException) {
0131:                        format = DB_FORMAT;
0132:                    }
0133:                } finally {
0134:                    formatFile.close();
0135:                }
0136:                if (format > DB_FORMAT) {
0137:                    SVNErrorMessage err = SVNErrorMessage
0138:                            .create(
0139:                                    SVNErrorCode.FS_UNSUPPORTED_FORMAT,
0140:                                    "Expected FS format ''{0,number,integer}''; found format ''{1,number,integer}''",
0141:                                    new Object[] { new Integer(DB_FORMAT),
0142:                                            new Integer(format) });
0143:                    SVNErrorManager.error(err);
0144:                }
0145:                myDBFormat = format;
0146:
0147:                // fs type /root/db/fs-type
0148:                formatFile = new FSFile(new File(myDBRoot, "fs-type"));
0149:                String fsType = null;
0150:                try {
0151:                    fsType = formatFile.readLine(128);
0152:                } finally {
0153:                    formatFile.close();
0154:                }
0155:                if (!DB_TYPE.equals(fsType)) {
0156:                    SVNErrorMessage err = SVNErrorMessage.create(
0157:                            SVNErrorCode.FS_UNKNOWN_FS_TYPE,
0158:                            "Unsupported fs type ''{0}''", fsType);
0159:                    SVNErrorManager.error(err);
0160:                }
0161:
0162:                File dbCurrentFile = getCurrentFile();
0163:                if (!(dbCurrentFile.exists() && dbCurrentFile.canRead())) {
0164:                    SVNErrorMessage err = SVNErrorMessage.create(
0165:                            SVNErrorCode.IO_ERROR, "Can''t open file ''{0}''",
0166:                            dbCurrentFile);
0167:                    SVNErrorManager.error(err);
0168:                }
0169:
0170:            }
0171:
0172:            public String getUUID() throws SVNException {
0173:                if (myUUID == null) {
0174:                    // uuid
0175:                    FSFile formatFile = new FSFile(new File(myDBRoot, "uuid"));
0176:                    try {
0177:                        myUUID = formatFile.readLine(38);
0178:                    } finally {
0179:                        formatFile.close();
0180:                    }
0181:                }
0182:
0183:                return myUUID;
0184:            }
0185:
0186:            public File getWriteLockFile() {
0187:                return myWriteLockFile;
0188:            }
0189:
0190:            public long getDatedRevision(Date date) throws SVNException {
0191:                long latest = getYoungestRevision();
0192:                long top = latest;
0193:                long bottom = 0;
0194:                long middle;
0195:                Date currentTime = null;
0196:
0197:                while (bottom <= top) {
0198:                    middle = (top + bottom) / 2;
0199:                    currentTime = getRevisionTime(middle);
0200:                    if (currentTime.compareTo(date) > 0) {
0201:                        if ((middle - 1) < 0) {
0202:                            return 0;
0203:                        }
0204:                        Date prevTime = getRevisionTime(middle - 1);
0205:                        if (prevTime.compareTo(date) < 0) {
0206:                            return middle - 1;
0207:                        }
0208:                        top = middle - 1;
0209:                    } else if (currentTime.compareTo(date) < 0) {
0210:                        if ((middle + 1) > latest) {
0211:                            return latest;
0212:                        }
0213:                        Date nextTime = getRevisionTime(middle + 1);
0214:                        if (nextTime.compareTo(date) > 0) {
0215:                            return middle;
0216:                        }
0217:                        bottom = middle + 1;
0218:                    } else {
0219:                        return middle;
0220:                    }
0221:                }
0222:                return 0;
0223:
0224:            }
0225:
0226:            public long getYoungestRevision() throws SVNException {
0227:                FSFile file = new FSFile(getCurrentFile());
0228:                try {
0229:                    String line = file.readLine(180);
0230:                    int spaceIndex = line.indexOf(' ');
0231:                    if (spaceIndex > 0) {
0232:                        return Long.parseLong(line.substring(0, spaceIndex));
0233:                    }
0234:                } catch (NumberFormatException nfe) {
0235:                    //
0236:                } finally {
0237:                    file.close();
0238:                }
0239:                SVNErrorMessage err = SVNErrorMessage.create(
0240:                        SVNErrorCode.FS_CORRUPT,
0241:                        "Can''t parse revision number in file ''{0}''", file);
0242:                SVNErrorManager.error(err);
0243:                return -1;
0244:            }
0245:
0246:            public File getDBRoot() {
0247:                return myDBRoot;
0248:            }
0249:
0250:            public Map getRevisionProperties(long revision) throws SVNException {
0251:                FSFile file = new FSFile(getRevisionPropertiesFile(revision));
0252:                try {
0253:                    return file.readProperties(false);
0254:                } finally {
0255:                    file.close();
0256:                }
0257:            }
0258:
0259:            public FSRevisionRoot createRevisionRoot(long revision) {
0260:                return new FSRevisionRoot(this , revision);
0261:            }
0262:
0263:            public FSTransactionRoot createTransactionRoot(String txnId)
0264:                    throws SVNException {
0265:                Map txnProps = getTransactionProperties(txnId);
0266:                int flags = 0;
0267:                if (txnProps.get(SVNProperty.TXN_CHECK_OUT_OF_DATENESS) != null) {
0268:                    flags |= FSTransactionRoot.SVN_FS_TXN_CHECK_OUT_OF_DATENESS;
0269:                }
0270:                if (txnProps.get(SVNProperty.TXN_CHECK_LOCKS) != null) {
0271:                    flags |= FSTransactionRoot.SVN_FS_TXN_CHECK_LOCKS;
0272:                }
0273:
0274:                return new FSTransactionRoot(this , txnId, flags);
0275:            }
0276:
0277:            public FSTransactionInfo openTxn(String txnName)
0278:                    throws SVNException {
0279:                SVNFileType kind = SVNFileType
0280:                        .getType(getTransactionDir(txnName));
0281:                if (kind != SVNFileType.DIRECTORY) {
0282:                    SVNErrorMessage err = SVNErrorMessage.create(
0283:                            SVNErrorCode.FS_NO_SUCH_TRANSACTION,
0284:                            "No such transaction");
0285:                    SVNErrorManager.error(err);
0286:                }
0287:
0288:                FSTransactionRoot txnRoot = new FSTransactionRoot(this ,
0289:                        txnName, 0);
0290:                FSTransactionInfo localTxn = txnRoot.getTxn();
0291:                return new FSTransactionInfo(localTxn.getBaseRevision(),
0292:                        txnName);
0293:            }
0294:
0295:            public FSRevisionNode getRevisionNode(FSID id) throws SVNException {
0296:                FSFile revisionFile = null;
0297:
0298:                if (id.isTxn()) {
0299:                    File file = new File(getTransactionDir(id.getTxnID()),
0300:                            PATH_PREFIX_NODE + id.getNodeID() + "."
0301:                                    + id.getCopyID());
0302:                    revisionFile = new FSFile(file);
0303:                } else {
0304:                    revisionFile = getRevisionFile(id.getRevision());
0305:                    revisionFile.seek(id.getOffset());
0306:                }
0307:
0308:                Map headers = null;
0309:                try {
0310:                    headers = revisionFile.readHeader();
0311:                } finally {
0312:                    revisionFile.close();
0313:                }
0314:
0315:                FSRevisionNode node = FSRevisionNode.fromMap(headers);
0316:                if (node.isFreshTxnRoot()) {
0317:                    node.setFreshRootPredecessorId(node.getPredecessorId());
0318:                }
0319:                return node;
0320:            }
0321:
0322:            public Map getDirContents(FSRevisionNode revNode)
0323:                    throws SVNException {
0324:                if (revNode.getTextRepresentation() != null
0325:                        && revNode.getTextRepresentation().isTxn()) {
0326:                    FSFile childrenFile = getTransactionRevisionNodeChildrenFile(revNode
0327:                            .getId());
0328:                    Map entries = null;
0329:                    try {
0330:                        Map rawEntries = childrenFile.readProperties(false);
0331:                        rawEntries.putAll(childrenFile.readProperties(true));
0332:
0333:                        Object[] keys = rawEntries.keySet().toArray();
0334:                        for (int i = 0; i < keys.length; i++) {
0335:                            if (rawEntries.get(keys[i]) == null) {
0336:                                rawEntries.remove(keys[i]);
0337:                            }
0338:                        }
0339:
0340:                        entries = parsePlainRepresentation(rawEntries, true);
0341:                    } finally {
0342:                        childrenFile.close();
0343:                    }
0344:                    return entries;
0345:                } else if (revNode.getTextRepresentation() != null) {
0346:                    FSRepresentation textRep = revNode.getTextRepresentation();
0347:                    FSFile revisionFile = null;
0348:
0349:                    try {
0350:                        revisionFile = openAndSeekRepresentation(textRep);
0351:                        String repHeader = revisionFile.readLine(160);
0352:
0353:                        if (!"PLAIN".equals(repHeader)) {
0354:                            SVNErrorMessage err = SVNErrorMessage.create(
0355:                                    SVNErrorCode.FS_CORRUPT,
0356:                                    "Malformed representation header");
0357:                            SVNErrorManager.error(err);
0358:                        }
0359:
0360:                        revisionFile.resetDigest();
0361:                        Map rawEntries = revisionFile.readProperties(false);
0362:                        String checksum = revisionFile.digest();
0363:
0364:                        if (!checksum.equals(textRep.getHexDigest())) {
0365:                            SVNErrorMessage err = SVNErrorMessage
0366:                                    .create(
0367:                                            SVNErrorCode.FS_CORRUPT,
0368:                                            "Checksum mismatch while reading representation:\n   expected:  {0}\n     actual:  {1}",
0369:                                            new Object[] { checksum,
0370:                                                    textRep.getHexDigest() });
0371:                            SVNErrorManager.error(err);
0372:                        }
0373:
0374:                        return parsePlainRepresentation(rawEntries, false);
0375:                    } finally {
0376:                        if (revisionFile != null) {
0377:                            revisionFile.close();
0378:                        }
0379:                    }
0380:                }
0381:                return new HashMap();// returns an empty map, must not be null!!
0382:            }
0383:
0384:            public Map getProperties(FSRevisionNode revNode)
0385:                    throws SVNException {
0386:                if (revNode.getPropsRepresentation() != null
0387:                        && revNode.getPropsRepresentation().isTxn()) {
0388:                    FSFile propsFile = null;
0389:                    try {
0390:                        propsFile = getTransactionRevisionNodePropertiesFile(revNode
0391:                                .getId());
0392:                        return propsFile.readProperties(false);
0393:                    } finally {
0394:                        if (propsFile != null) {
0395:                            propsFile.close();
0396:                        }
0397:                    }
0398:                } else if (revNode.getPropsRepresentation() != null) {
0399:                    FSRepresentation propsRep = revNode
0400:                            .getPropsRepresentation();
0401:                    FSFile revisionFile = null;
0402:
0403:                    try {
0404:                        revisionFile = openAndSeekRepresentation(propsRep);
0405:                        String repHeader = revisionFile.readLine(160);
0406:
0407:                        if (!"PLAIN".equals(repHeader)) {
0408:                            SVNErrorMessage err = SVNErrorMessage.create(
0409:                                    SVNErrorCode.FS_CORRUPT,
0410:                                    "Malformed representation header");
0411:                            SVNErrorManager.error(err);
0412:                        }
0413:
0414:                        revisionFile.resetDigest();
0415:                        Map props = revisionFile.readProperties(false);
0416:                        String checksum = revisionFile.digest();
0417:
0418:                        if (!checksum.equals(propsRep.getHexDigest())) {
0419:                            SVNErrorMessage err = SVNErrorMessage
0420:                                    .create(
0421:                                            SVNErrorCode.FS_CORRUPT,
0422:                                            "Checksum mismatch while reading representation:\n   expected:  {0}\n     actual:  {1}",
0423:                                            new Object[] { checksum,
0424:                                                    propsRep.getHexDigest() });
0425:                            SVNErrorManager.error(err);
0426:                        }
0427:                        return props;
0428:                    } finally {
0429:                        if (revisionFile != null) {
0430:                            revisionFile.close();
0431:                        }
0432:                    }
0433:                }
0434:                return new HashMap();// no properties? return an empty map
0435:            }
0436:
0437:            public String[] getNextRevisionIDs() throws SVNException {
0438:                String[] ids = new String[2];
0439:                FSFile currentFile = new FSFile(getCurrentFile());
0440:                String idsLine = null;
0441:
0442:                try {
0443:                    idsLine = currentFile.readLine(80);
0444:                } finally {
0445:                    currentFile.close();
0446:                }
0447:
0448:                if (idsLine == null || idsLine.length() == 0) {
0449:                    SVNErrorMessage err = SVNErrorMessage.create(
0450:                            SVNErrorCode.FS_CORRUPT, "Corrupt current file");
0451:                    SVNErrorManager.error(err);
0452:                }
0453:
0454:                int spaceInd = idsLine.indexOf(' ');
0455:                if (spaceInd == -1) {
0456:                    SVNErrorMessage err = SVNErrorMessage.create(
0457:                            SVNErrorCode.FS_CORRUPT, "Corrupt current file");
0458:                    SVNErrorManager.error(err);
0459:                }
0460:
0461:                idsLine = idsLine.substring(spaceInd + 1);
0462:                spaceInd = idsLine.indexOf(' ');
0463:                if (spaceInd == -1) {
0464:                    SVNErrorMessage err = SVNErrorMessage.create(
0465:                            SVNErrorCode.FS_CORRUPT, "Corrupt current file");
0466:                    SVNErrorManager.error(err);
0467:                }
0468:                String nodeID = idsLine.substring(0, spaceInd);
0469:                String copyID = idsLine.substring(spaceInd + 1);
0470:
0471:                ids[0] = nodeID;
0472:                ids[1] = copyID;
0473:                return ids;
0474:            }
0475:
0476:            public Map listTransactions() {
0477:                Map result = new HashMap();
0478:                File txnsDir = getTransactionsParentDir();
0479:
0480:                File[] entries = SVNFileListUtil.listFiles(txnsDir);
0481:                for (int i = 0; i < entries.length; i++) {
0482:                    File entry = entries[i];
0483:                    if (entry.getName().length() <= TXN_PATH_EXT.length()
0484:                            || !entry.getName().endsWith(TXN_PATH_EXT)) {
0485:                        continue;
0486:                    }
0487:                    String txnName = entry.getName().substring(0,
0488:                            entry.getName().lastIndexOf(TXN_PATH_EXT));
0489:                    result.put(txnName, entry);
0490:                }
0491:                return result;
0492:            }
0493:
0494:            public File getNewRevisionFile(long revision) throws SVNException {
0495:                File revFile = new File(myRevisionsRoot, String
0496:                        .valueOf(revision));
0497:                if (revFile.exists()) {
0498:                    SVNErrorMessage err = SVNErrorMessage
0499:                            .create(SVNErrorCode.FS_CONFLICT,
0500:                                    "Revision already exists");
0501:                    SVNErrorManager.error(err);
0502:                }
0503:                return revFile;
0504:            }
0505:
0506:            public File getNewRevisionPropertiesFile(long revision)
0507:                    throws SVNException {
0508:                File revPropsFile = new File(myRevisionPropertiesRoot, String
0509:                        .valueOf(revision));
0510:                if (revPropsFile.exists()) {
0511:                    SVNErrorMessage err = SVNErrorMessage
0512:                            .create(SVNErrorCode.FS_CONFLICT,
0513:                                    "Revision already exists");
0514:                    SVNErrorManager.error(err);
0515:                }
0516:                return revPropsFile;
0517:            }
0518:
0519:            public File getTransactionDir(String txnID) {
0520:                return new File(getTransactionsParentDir(), txnID
0521:                        + TXN_PATH_EXT);
0522:            }
0523:
0524:            public File getTransactionsParentDir() {
0525:                return myTransactionsRoot;
0526:            }
0527:
0528:            public void setUUID(String uuid) throws SVNException {
0529:                File uuidFile = new File(myDBRoot, "uuid");
0530:                File uniqueFile = SVNFileUtil.createUniqueFile(myDBRoot,
0531:                        "uuid", ".tmp");
0532:                uuid += '\n';
0533:
0534:                OutputStream uuidOS = null;
0535:                try {
0536:                    uuidOS = SVNFileUtil.openFileForWriting(uniqueFile);
0537:                    uuidOS.write(uuid.getBytes("US-ASCII"));
0538:                } catch (IOException e) {
0539:                    SVNErrorMessage err = SVNErrorMessage.create(
0540:                            SVNErrorCode.IO_ERROR,
0541:                            "Error writing repository UUID to ''{0}''",
0542:                            uuidFile);
0543:                    err.setChildErrorMessage(SVNErrorMessage.create(
0544:                            SVNErrorCode.IO_ERROR, e.getLocalizedMessage()));
0545:                    SVNErrorManager.error(err);
0546:                } finally {
0547:                    SVNFileUtil.closeFile(uuidOS);
0548:                }
0549:                SVNFileUtil.rename(uniqueFile, uuidFile);
0550:            }
0551:
0552:            public File getRevisionPropertiesFile(long revision)
0553:                    throws SVNException {
0554:                File file = new File(myRevisionPropertiesRoot, String
0555:                        .valueOf(revision));
0556:                if (!file.exists()) {
0557:                    SVNErrorMessage err = SVNErrorMessage.create(
0558:                            SVNErrorCode.FS_NO_SUCH_REVISION,
0559:                            "No such revision {0,number,integer}", new Long(
0560:                                    revision));
0561:                    SVNErrorManager.error(err);
0562:                }
0563:                return file;
0564:            }
0565:
0566:            public File getRepositoryRoot() {
0567:                return myRepositoryRoot;
0568:            }
0569:
0570:            public FSFile openAndSeekRepresentation(FSRepresentation rep)
0571:                    throws SVNException {
0572:                if (!rep.isTxn()) {
0573:                    return openAndSeekRevision(rep.getRevision(), rep
0574:                            .getOffset());
0575:                }
0576:                return openAndSeekTransaction(rep);
0577:            }
0578:
0579:            public File getNextIDsFile(String txnID) {
0580:                return new File(getTransactionDir(txnID), "next-ids");
0581:            }
0582:
0583:            public void writeNextIDs(String txnID, String nodeID, String copyID)
0584:                    throws SVNException {
0585:                OutputStream nextIdsFile = null;
0586:                try {
0587:                    nextIdsFile = SVNFileUtil
0588:                            .openFileForWriting(getNextIDsFile(txnID));
0589:                    String ids = nodeID + " " + copyID + "\n";
0590:                    nextIdsFile.write(ids.getBytes("UTF-8"));
0591:                } catch (IOException ioe) {
0592:                    SVNErrorMessage err = SVNErrorMessage.create(
0593:                            SVNErrorCode.IO_ERROR, ioe.getLocalizedMessage());
0594:                    SVNErrorManager.error(err, ioe);
0595:                } finally {
0596:                    SVNFileUtil.closeFile(nextIdsFile);
0597:                }
0598:            }
0599:
0600:            public void setTransactionProperty(String txnID,
0601:                    String propertyName, String propertyValue)
0602:                    throws SVNException {
0603:                SVNProperties revProps = new SVNProperties(
0604:                        getTransactionPropertiesFile(txnID), null);
0605:                revProps.setPropertyValue(propertyName, propertyValue);
0606:            }
0607:
0608:            public void setRevisionProperty(long revision, String propertyName,
0609:                    String propertyValue) throws SVNException {
0610:                SVNProperties revProps = new SVNProperties(
0611:                        getRevisionPropertiesFile(revision), null);
0612:                revProps.setPropertyValue(propertyName, propertyValue);
0613:            }
0614:
0615:            public Map getTransactionProperties(String txnID)
0616:                    throws SVNException {
0617:                FSFile txnPropsFile = new FSFile(
0618:                        getTransactionPropertiesFile(txnID));
0619:                try {
0620:                    return txnPropsFile.readProperties(false);
0621:                } finally {
0622:                    txnPropsFile.close();
0623:                }
0624:            }
0625:
0626:            public File getTransactionPropertiesFile(String txnID) {
0627:                return new File(getTransactionDir(txnID), "props");
0628:            }
0629:
0630:            public void createNewTxnNodeRevisionFromRevision(String txnID,
0631:                    FSRevisionNode sourceNode) throws SVNException {
0632:                if (sourceNode.getId().isTxn()) {
0633:                    SVNErrorMessage err = SVNErrorMessage.create(
0634:                            SVNErrorCode.FS_CORRUPT,
0635:                            "Copying from transactions not allowed");
0636:                    SVNErrorManager.error(err);
0637:                }
0638:                FSRevisionNode revNode = FSRevisionNode
0639:                        .dumpRevisionNode(sourceNode);
0640:                revNode.setPredecessorId(sourceNode.getId());
0641:                revNode.setCount(revNode.getCount() + 1);
0642:                revNode.setCopyFromPath(null);
0643:                revNode.setIsFreshTxnRoot(true);
0644:                revNode.setCopyFromRevision(FSRepository.SVN_INVALID_REVNUM);
0645:                revNode.setId(FSID.createTxnId(sourceNode.getId().getNodeID(),
0646:                        sourceNode.getId().getCopyID(), txnID));
0647:                putTxnRevisionNode(revNode.getId(), revNode);
0648:            }
0649:
0650:            public void putTxnRevisionNode(FSID id, FSRevisionNode revNode)
0651:                    throws SVNException {
0652:                if (!id.isTxn()) {
0653:                    SVNErrorMessage err = SVNErrorMessage.create(
0654:                            SVNErrorCode.FS_CORRUPT,
0655:                            "Attempted to write to non-transaction");
0656:                    SVNErrorManager.error(err);
0657:                }
0658:                OutputStream revNodeFile = null;
0659:                try {
0660:                    revNodeFile = SVNFileUtil
0661:                            .openFileForWriting(getTransactionRevNodeFile(id));
0662:                    writeTxnNodeRevision(revNodeFile, revNode);
0663:                } catch (IOException ioe) {
0664:                    SVNErrorMessage err = SVNErrorMessage.create(
0665:                            SVNErrorCode.IO_ERROR, ioe.getLocalizedMessage());
0666:                    SVNErrorManager.error(err, ioe);
0667:                } finally {
0668:                    SVNFileUtil.closeFile(revNodeFile);
0669:                }
0670:            }
0671:
0672:            public File getTransactionRevNodeFile(FSID id) {
0673:                return new File(getTransactionDir(id.getTxnID()),
0674:                        PATH_PREFIX_NODE + id.getNodeID() + "."
0675:                                + id.getCopyID());
0676:            }
0677:
0678:            public void writeTxnNodeRevision(OutputStream revNodeFile,
0679:                    FSRevisionNode revNode) throws IOException {
0680:                String id = FSRevisionNode.HEADER_ID + ": " + revNode.getId()
0681:                        + "\n";
0682:                revNodeFile.write(id.getBytes("UTF-8"));
0683:                String type = FSRevisionNode.HEADER_TYPE + ": "
0684:                        + revNode.getType() + "\n";
0685:                revNodeFile.write(type.getBytes("UTF-8"));
0686:
0687:                if (revNode.getPredecessorId() != null) {
0688:                    String predId = FSRevisionNode.HEADER_PRED + ": "
0689:                            + revNode.getPredecessorId() + "\n";
0690:                    revNodeFile.write(predId.getBytes("UTF-8"));
0691:                }
0692:
0693:                String count = FSRevisionNode.HEADER_COUNT + ": "
0694:                        + revNode.getCount() + "\n";
0695:                revNodeFile.write(count.getBytes("UTF-8"));
0696:
0697:                if (revNode.getTextRepresentation() != null) {
0698:                    String textRepresentation = FSRevisionNode.HEADER_TEXT
0699:                            + ": "
0700:                            + (revNode.getTextRepresentation().getTxnId() != null
0701:                                    && revNode.getType() == SVNNodeKind.DIR ? "-1"
0702:                                    : revNode.getTextRepresentation()
0703:                                            .toString()) + "\n";
0704:                    revNodeFile.write(textRepresentation.getBytes("UTF-8"));
0705:                }
0706:
0707:                if (revNode.getPropsRepresentation() != null) {
0708:                    String propsRepresentation = FSRevisionNode.HEADER_PROPS
0709:                            + ": "
0710:                            + (revNode.getPropsRepresentation().getTxnId() != null ? "-1"
0711:                                    : revNode.getPropsRepresentation()
0712:                                            .toString()) + "\n";
0713:                    revNodeFile.write(propsRepresentation.getBytes("UTF-8"));
0714:                }
0715:
0716:                String cpath = FSRevisionNode.HEADER_CPATH + ": "
0717:                        + revNode.getCreatedPath() + "\n";
0718:                revNodeFile.write(cpath.getBytes("UTF-8"));
0719:
0720:                if (revNode.getCopyFromPath() != null) {
0721:                    String copyFromPath = FSRevisionNode.HEADER_COPYFROM + ": "
0722:                            + revNode.getCopyFromRevision() + " "
0723:                            + revNode.getCopyFromPath() + "\n";
0724:                    revNodeFile.write(copyFromPath.getBytes("UTF-8"));
0725:                }
0726:
0727:                if (revNode.getCopyRootRevision() != revNode.getId()
0728:                        .getRevision()
0729:                        || !revNode.getCopyRootPath().equals(
0730:                                revNode.getCreatedPath())) {
0731:                    String copyroot = FSRevisionNode.HEADER_COPYROOT + ": "
0732:                            + revNode.getCopyRootRevision() + " "
0733:                            + revNode.getCopyRootPath() + "\n";
0734:                    revNodeFile.write(copyroot.getBytes("UTF-8"));
0735:                }
0736:
0737:                if (revNode.isFreshTxnRoot()) {
0738:                    String isFreshRootStr = FSRevisionNode.HEADER_IS_FRESH_TXN_ROOT
0739:                            + ": y\n";
0740:                    revNodeFile.write(isFreshRootStr.getBytes("UTF-8"));
0741:                }
0742:
0743:                revNodeFile.write("\n".getBytes("UTF-8"));
0744:            }
0745:
0746:            public SVNLock getLock(String repositoryPath, boolean haveWriteLock)
0747:                    throws SVNException {
0748:                SVNLock lock = fetchLockFromDigestFile(null, repositoryPath,
0749:                        null);
0750:
0751:                if (lock == null) {
0752:                    SVNErrorManager.error(FSErrors.errorNoSuchLock(
0753:                            repositoryPath, this ));
0754:                }
0755:
0756:                Date current = new Date(System.currentTimeMillis());
0757:
0758:                if (lock.getExpirationDate() != null
0759:                        && current.compareTo(lock.getExpirationDate()) > 0) {
0760:                    if (haveWriteLock) {
0761:                        deleteLock(lock);
0762:                    }
0763:                    SVNErrorManager.error(FSErrors.errorLockExpired(lock
0764:                            .getID(), this ));
0765:                }
0766:                return lock;
0767:            }
0768:
0769:            public void deleteLock(SVNLock lock) throws SVNException {
0770:                String reposPath = lock.getPath();
0771:                String childToKill = null;
0772:                Collection children = new ArrayList();
0773:                while (true) {
0774:                    fetchLockFromDigestFile(null, reposPath, children);
0775:                    if (childToKill != null) {
0776:                        children.remove(childToKill);
0777:                    }
0778:
0779:                    if (children.size() == 0) {
0780:                        childToKill = getDigestFromRepositoryPath(reposPath);
0781:                        File digestFile = getDigestFileFromRepositoryPath(reposPath);
0782:                        SVNFileUtil.deleteFile(digestFile);
0783:                    } else {
0784:                        writeDigestLockFile(null, children, reposPath);
0785:                        childToKill = null;
0786:                    }
0787:
0788:                    if ("/".equals(reposPath)) {
0789:                        break;
0790:                    }
0791:
0792:                    reposPath = SVNPathUtil.removeTail(reposPath);
0793:
0794:                    if ("".equals(reposPath)) {
0795:                        reposPath = "/";
0796:                    }
0797:                    children.clear();
0798:                }
0799:            }
0800:
0801:            public void walkDigestFiles(File digestFile,
0802:                    ISVNLockHandler getLocksHandler, boolean haveWriteLock)
0803:                    throws SVNException {
0804:                Collection children = new LinkedList();
0805:                SVNLock lock = fetchLockFromDigestFile(digestFile, null,
0806:                        children);
0807:
0808:                if (lock != null) {
0809:                    Date current = new Date(System.currentTimeMillis());
0810:                    if (lock.getExpirationDate() == null
0811:                            || current.compareTo(lock.getExpirationDate()) < 0) {
0812:                        getLocksHandler.handleLock(null, lock, null);
0813:                    } else if (haveWriteLock) {
0814:                        deleteLock(lock);
0815:                    }
0816:                }
0817:
0818:                if (children.isEmpty()) {
0819:                    return;
0820:                }
0821:
0822:                for (Iterator entries = children.iterator(); entries.hasNext();) {
0823:                    String digestName = (String) entries.next();
0824:                    File parent = new File(myLocksRoot, digestName.substring(0,
0825:                            FSFS.DIGEST_SUBDIR_LEN));
0826:                    File childDigestFile = new File(parent, digestName);
0827:                    walkDigestFiles(childDigestFile, getLocksHandler,
0828:                            haveWriteLock);
0829:                }
0830:            }
0831:
0832:            public SVNLock getLockHelper(String repositoryPath,
0833:                    boolean haveWriteLock) throws SVNException {
0834:                SVNLock lock = null;
0835:                try {
0836:                    lock = getLock(repositoryPath, haveWriteLock);
0837:                } catch (SVNException svne) {
0838:                    if (svne.getErrorMessage().getErrorCode() == SVNErrorCode.FS_NO_SUCH_LOCK
0839:                            || svne.getErrorMessage().getErrorCode() == SVNErrorCode.FS_LOCK_EXPIRED) {
0840:                        return null;
0841:                    }
0842:                    throw svne;
0843:                }
0844:                return lock;
0845:            }
0846:
0847:            public SVNLock fetchLockFromDigestFile(File digestFile,
0848:                    String repositoryPath, Collection children)
0849:                    throws SVNException {
0850:                File digestLockFile = digestFile == null ? getDigestFileFromRepositoryPath(repositoryPath)
0851:                        : digestFile;
0852:                Map lockProps = null;
0853:
0854:                if (digestLockFile.exists()) {
0855:                    FSFile reader = new FSFile(digestLockFile);
0856:                    try {
0857:                        lockProps = reader.readProperties(false);
0858:                    } catch (SVNException svne) {
0859:                        SVNErrorMessage err = svne.getErrorMessage().wrap(
0860:                                "Can't parse lock/entries hashfile ''{0}''",
0861:                                digestLockFile);
0862:                        SVNErrorManager.error(err);
0863:                    } finally {
0864:                        reader.close();
0865:                    }
0866:                } else {
0867:                    lockProps = Collections.EMPTY_MAP;
0868:                }
0869:
0870:                SVNLock lock = null;
0871:                String lockPath = (String) lockProps.get(FSFS.PATH_LOCK_KEY);
0872:                if (lockPath != null) {
0873:                    String lockToken = (String) lockProps
0874:                            .get(FSFS.TOKEN_LOCK_KEY);
0875:                    if (lockToken == null) {
0876:                        SVNErrorManager.error(FSErrors.errorCorruptLockFile(
0877:                                lockPath, this ));
0878:                    }
0879:                    String lockOwner = (String) lockProps
0880:                            .get(FSFS.OWNER_LOCK_KEY);
0881:                    if (lockOwner == null) {
0882:                        SVNErrorManager.error(FSErrors.errorCorruptLockFile(
0883:                                lockPath, this ));
0884:                    }
0885:                    String davComment = (String) lockProps
0886:                            .get(FSFS.IS_DAV_COMMENT_LOCK_KEY);
0887:                    if (davComment == null) {
0888:                        SVNErrorManager.error(FSErrors.errorCorruptLockFile(
0889:                                lockPath, this ));
0890:                    }
0891:                    String creationTime = (String) lockProps
0892:                            .get(FSFS.CREATION_DATE_LOCK_KEY);
0893:                    if (creationTime == null) {
0894:                        SVNErrorManager.error(FSErrors.errorCorruptLockFile(
0895:                                lockPath, this ));
0896:                    }
0897:                    Date creationDate = SVNTimeUtil
0898:                            .parseDateString(creationTime);
0899:                    String expirationTime = (String) lockProps
0900:                            .get(FSFS.EXPIRATION_DATE_LOCK_KEY);
0901:                    Date expirationDate = null;
0902:                    if (expirationTime != null) {
0903:                        expirationDate = SVNTimeUtil
0904:                                .parseDateString(expirationTime);
0905:                    }
0906:                    String comment = (String) lockProps
0907:                            .get(FSFS.COMMENT_LOCK_KEY);
0908:                    lock = new SVNLock(lockPath, lockToken, lockOwner, comment,
0909:                            creationDate, expirationDate);
0910:                }
0911:
0912:                String childEntries = (String) lockProps
0913:                        .get(FSFS.CHILDREN_LOCK_KEY);
0914:                if (children != null && childEntries != null) {
0915:                    String[] digests = childEntries.split("\n");
0916:                    for (int i = 0; i < digests.length; i++) {
0917:                        children.add(digests[i]);
0918:                    }
0919:                }
0920:                return lock;
0921:            }
0922:
0923:            public File getDigestFileFromRepositoryPath(String repositoryPath)
0924:                    throws SVNException {
0925:                String digest = getDigestFromRepositoryPath(repositoryPath);
0926:                File parent = new File(myLocksRoot, digest.substring(0,
0927:                        FSFS.DIGEST_SUBDIR_LEN));
0928:                return new File(parent, digest);
0929:            }
0930:
0931:            public String getDigestFromRepositoryPath(String repositoryPath)
0932:                    throws SVNException {
0933:                MessageDigest digestFromPath = null;
0934:                try {
0935:                    digestFromPath = MessageDigest.getInstance("MD5");
0936:                    digestFromPath.update(repositoryPath.getBytes("UTF-8"));
0937:                } catch (NoSuchAlgorithmException nsae) {
0938:                    SVNErrorMessage err = SVNErrorMessage.create(
0939:                            SVNErrorCode.IO_ERROR,
0940:                            "MD5 implementation not found: {0}", nsae
0941:                                    .getLocalizedMessage());
0942:                    SVNErrorManager.error(err, nsae);
0943:                } catch (IOException ioe) {
0944:                    SVNErrorMessage err = SVNErrorMessage.create(
0945:                            SVNErrorCode.IO_ERROR, ioe.getLocalizedMessage());
0946:                    SVNErrorManager.error(err, ioe);
0947:                }
0948:                return SVNFileUtil.toHexDigest(digestFromPath);
0949:            }
0950:
0951:            public void unlockPath(String path, String token, String username,
0952:                    boolean breakLock, boolean enableHooks) throws SVNException {
0953:                String[] paths = { path };
0954:
0955:                if (!breakLock && username == null) {
0956:                    SVNErrorMessage err = SVNErrorMessage
0957:                            .create(
0958:                                    SVNErrorCode.FS_NO_USER,
0959:                                    "Cannot unlock path ''{0}'', no authenticated username available",
0960:                                    path);
0961:                    SVNErrorManager.error(err);
0962:                }
0963:
0964:                if (enableHooks) {
0965:                    FSHooks.runPreUnlockHook(myRepositoryRoot, path, username);
0966:                }
0967:
0968:                FSWriteLock writeLock = FSWriteLock.getWriteLock(this );
0969:                synchronized (writeLock) {
0970:                    try {
0971:                        writeLock.lock();
0972:                        unlock(path, token, username, breakLock);
0973:                    } finally {
0974:                        writeLock.unlock();
0975:                        FSWriteLock.realease(writeLock);
0976:                    }
0977:                }
0978:
0979:                if (enableHooks) {
0980:                    try {
0981:                        FSHooks.runPostUnlockHook(myRepositoryRoot, paths,
0982:                                username);
0983:                    } catch (SVNException svne) {
0984:                        SVNErrorMessage err = SVNErrorMessage
0985:                                .create(
0986:                                        SVNErrorCode.REPOS_POST_UNLOCK_HOOK_FAILED,
0987:                                        "Unlock succeeded, but post-unlock hook failed");
0988:                        err.setChildErrorMessage(svne.getErrorMessage());
0989:                        SVNErrorManager.error(err, svne);
0990:                    }
0991:                }
0992:            }
0993:
0994:            public SVNLock lockPath(String path, String token, String username,
0995:                    String comment, Date expirationDate, long currentRevision,
0996:                    boolean stealLock) throws SVNException {
0997:                String[] paths = { path };
0998:
0999:                if (username == null) {
1000:                    SVNErrorMessage err = SVNErrorMessage
1001:                            .create(
1002:                                    SVNErrorCode.FS_NO_USER,
1003:                                    "Cannot lock path ''{0}'', no authenticated username available.",
1004:                                    path);
1005:                    SVNErrorManager.error(err);
1006:                }
1007:
1008:                FSHooks.runPreLockHook(myRepositoryRoot, path, username);
1009:                SVNLock lock = null;
1010:
1011:                FSWriteLock writeLock = FSWriteLock.getWriteLock(this );
1012:
1013:                synchronized (writeLock) {
1014:                    try {
1015:                        writeLock.lock();
1016:                        lock = lock(path, token, username, comment,
1017:                                expirationDate, currentRevision, stealLock);
1018:                    } finally {
1019:                        writeLock.unlock();
1020:                        FSWriteLock.realease(writeLock);
1021:                    }
1022:                }
1023:
1024:                try {
1025:                    FSHooks.runPostLockHook(myRepositoryRoot, paths, username);
1026:                } catch (SVNException svne) {
1027:                    SVNErrorMessage err = SVNErrorMessage.create(
1028:                            SVNErrorCode.REPOS_POST_LOCK_HOOK_FAILED,
1029:                            "Lock succeeded, but post-lock hook failed");
1030:                    err.setChildErrorMessage(svne.getErrorMessage());
1031:                    SVNErrorManager.error(err, svne);
1032:                }
1033:                return lock;
1034:            }
1035:
1036:            public Map compoundMetaProperties(long revision)
1037:                    throws SVNException {
1038:                Map metaProps = new HashMap();
1039:                Map revProps = getRevisionProperties(revision);
1040:                String author = (String) revProps
1041:                        .get(SVNRevisionProperty.AUTHOR);
1042:                String date = (String) revProps.get(SVNRevisionProperty.DATE);
1043:                String uuid = getUUID();
1044:                String rev = String.valueOf(revision);
1045:
1046:                metaProps.put(SVNProperty.LAST_AUTHOR, author);
1047:                metaProps.put(SVNProperty.COMMITTED_DATE, date);
1048:                metaProps.put(SVNProperty.COMMITTED_REVISION, rev);
1049:                metaProps.put(SVNProperty.UUID, uuid);
1050:                return metaProps;
1051:            }
1052:
1053:            public static File findRepositoryRoot(File path) {
1054:                if (path == null) {
1055:                    path = new File("");
1056:                }
1057:                File rootPath = path;
1058:                while (!isRepositoryRoot(rootPath)) {
1059:                    rootPath = rootPath.getParentFile();
1060:                    if (rootPath == null) {
1061:                        return null;
1062:                    }
1063:                }
1064:                return rootPath;
1065:            }
1066:
1067:            public static String findRepositoryRoot(String host, String path) {
1068:                if (path == null) {
1069:                    path = "";
1070:                }
1071:
1072:                String testPath = host != null ? SVNPathUtil.append("\\\\"
1073:                        + host, path) : path;
1074:                File rootPath = new File(testPath).getAbsoluteFile();
1075:                while (!isRepositoryRoot(rootPath)) {
1076:                    if (rootPath.getParentFile() == null) {
1077:                        return null;
1078:                    }
1079:                    path = SVNPathUtil.removeTail(path);
1080:                    rootPath = rootPath.getParentFile();
1081:                }
1082:                while (path.endsWith("/")) {
1083:                    path = path.substring(0, path.length() - 1);
1084:                }
1085:                while (path.endsWith("\\")) {
1086:                    path = path.substring(0, path.length() - 1);
1087:                }
1088:                return path;
1089:            }
1090:
1091:            protected FSFile getTransactionRevisionPrototypeFile(String txnID) {
1092:                File revFile = new File(getTransactionDir(txnID), TXN_PATH_REV);
1093:                return new FSFile(revFile);
1094:            }
1095:
1096:            protected FSFile getTransactionChangesFile(String txnID) {
1097:                File file = new File(getTransactionDir(txnID), "changes");
1098:                return new FSFile(file);
1099:            }
1100:
1101:            protected FSFile getTransactionRevisionNodeChildrenFile(FSID txnID) {
1102:                File childrenFile = new File(
1103:                        getTransactionDir(txnID.getTxnID()), PATH_PREFIX_NODE
1104:                                + txnID.getNodeID() + "." + txnID.getCopyID()
1105:                                + TXN_PATH_EXT_CHILDREN);
1106:                return new FSFile(childrenFile);
1107:            }
1108:
1109:            protected FSFile getRevisionFile(long revision) throws SVNException {
1110:                File revisionFile = new File(myRevisionsRoot, String
1111:                        .valueOf(revision));
1112:                if (!revisionFile.exists()) {
1113:                    SVNErrorMessage err = SVNErrorMessage.create(
1114:                            SVNErrorCode.FS_NO_SUCH_REVISION,
1115:                            "No such revision {0,number,integer}", new Long(
1116:                                    revision));
1117:                    SVNErrorManager.error(err);
1118:                }
1119:                return new FSFile(revisionFile);
1120:            }
1121:
1122:            protected FSFile getTransactionRevisionNodePropertiesFile(FSID id) {
1123:                File revNodePropsFile = new File(getTransactionDir(id
1124:                        .getTxnID()), PATH_PREFIX_NODE + id.getNodeID() + "."
1125:                        + id.getCopyID() + TXN_PATH_EXT_PROPS);
1126:                return new FSFile(revNodePropsFile);
1127:            }
1128:
1129:            protected File getCurrentFile() {
1130:                if (myCurrentFile == null) {
1131:                    myCurrentFile = new File(myDBRoot, "current");
1132:                }
1133:                return myCurrentFile;
1134:            }
1135:
1136:            private void unlock(String path, String token, String username,
1137:                    boolean breakLock) throws SVNException {
1138:                SVNLock lock = getLock(path, true);
1139:                if (!breakLock) {
1140:                    if (token == null || !token.equals(lock.getID())) {
1141:                        SVNErrorManager.error(FSErrors.errorNoSuchLock(lock
1142:                                .getPath(), this ));
1143:                    }
1144:                    if (username == null || "".equals(username)) {
1145:                        SVNErrorManager.error(FSErrors.errorNoUser(this ));
1146:                    }
1147:                    if (!username.equals(lock.getOwner())) {
1148:                        SVNErrorManager.error(FSErrors.errorLockOwnerMismatch(
1149:                                username, lock.getOwner(), this ));
1150:                    }
1151:                }
1152:                deleteLock(lock);
1153:            }
1154:
1155:            private SVNLock lock(String path, String token, String username,
1156:                    String comment, Date expirationDate, long currentRevision,
1157:                    boolean stealLock) throws SVNException {
1158:                long youngestRev = getYoungestRevision();
1159:                FSRevisionRoot root = createRevisionRoot(youngestRev);
1160:                SVNNodeKind kind = root.checkNodeKind(path);
1161:
1162:                if (kind == SVNNodeKind.DIR) {
1163:                    SVNErrorManager.error(FSErrors.errorNotFile(path, this ));
1164:                } else if (kind == SVNNodeKind.NONE) {
1165:                    SVNErrorMessage err = SVNErrorMessage
1166:                            .create(
1167:                                    SVNErrorCode.FS_NOT_FOUND,
1168:                                    "Path ''{0}'' doesn't exist in HEAD revision",
1169:                                    path);
1170:                    SVNErrorManager.error(err);
1171:                }
1172:
1173:                if (username == null || "".equals(username)) {
1174:                    SVNErrorManager.error(FSErrors.errorNoUser(this ));
1175:                }
1176:
1177:                if (FSRepository.isValidRevision(currentRevision)) {
1178:                    FSRevisionNode node = root.getRevisionNode(path);
1179:                    long createdRev = node.getCreatedRevision();
1180:                    if (FSRepository.isInvalidRevision(createdRev)) {
1181:                        SVNErrorMessage err = SVNErrorMessage.create(
1182:                                SVNErrorCode.FS_OUT_OF_DATE,
1183:                                "Path ''{0}'' doesn't exist in HEAD revision",
1184:                                path);
1185:                        SVNErrorManager.error(err);
1186:                    }
1187:                    if (currentRevision < createdRev) {
1188:                        SVNErrorMessage err = SVNErrorMessage.create(
1189:                                SVNErrorCode.FS_OUT_OF_DATE,
1190:                                "Lock failed: newer version of ''{0}'' exists",
1191:                                path);
1192:                        SVNErrorManager.error(err);
1193:                    }
1194:                }
1195:
1196:                SVNLock existingLock = getLockHelper(path, true);
1197:
1198:                if (existingLock != null) {
1199:                    if (!stealLock) {
1200:                        SVNErrorManager.error(FSErrors.errorPathAlreadyLocked(
1201:                                existingLock.getPath(),
1202:                                existingLock.getOwner(), this ));
1203:                    } else {
1204:                        deleteLock(existingLock);
1205:                    }
1206:                }
1207:
1208:                SVNLock lock = null;
1209:                if (token == null) {
1210:                    String uuid = SVNUUIDGenerator.formatUUID(SVNUUIDGenerator
1211:                            .generateUUID());
1212:                    token = FSFS.SVN_OPAQUE_LOCK_TOKEN + uuid;
1213:                    lock = new SVNLock(path, token, username, comment,
1214:                            new Date(System.currentTimeMillis()),
1215:                            expirationDate);
1216:                } else {
1217:                    lock = new SVNLock(path, token, username, comment,
1218:                            new Date(System.currentTimeMillis()),
1219:                            expirationDate);
1220:                }
1221:
1222:                setLock(lock);
1223:                return lock;
1224:            }
1225:
1226:            private void setLock(SVNLock lock) throws SVNException {
1227:                if (lock == null) {
1228:                    SVNErrorMessage err = SVNErrorMessage.create(
1229:                            SVNErrorCode.UNKNOWN,
1230:                            "FATAL error: attempted to set a null lock");
1231:                    SVNErrorManager.error(err);
1232:                }
1233:                String lastChild = "";
1234:                String path = lock.getPath();
1235:                Collection children = new ArrayList();
1236:                while (true) {
1237:                    String digestFileName = getDigestFromRepositoryPath(path);
1238:                    SVNLock fetchedLock = fetchLockFromDigestFile(null, path,
1239:                            children);
1240:
1241:                    if (lock != null) {
1242:                        fetchedLock = lock;
1243:                        lock = null;
1244:                        lastChild = digestFileName;
1245:                    } else {
1246:                        if (!children.isEmpty() && children.contains(lastChild)) {
1247:                            break;
1248:                        }
1249:                        children.add(lastChild);
1250:                    }
1251:
1252:                    writeDigestLockFile(fetchedLock, children, path);
1253:
1254:                    if ("/".equals(path)) {
1255:                        break;
1256:                    }
1257:                    path = SVNPathUtil.removeTail(path);
1258:
1259:                    if ("".equals(path)) {
1260:                        path = "/";
1261:                    }
1262:                    children.clear();
1263:                }
1264:            }
1265:
1266:            private boolean ensureDirExists(File dir, boolean create) {
1267:                if (!dir.exists() && create == true) {
1268:                    return dir.mkdirs();
1269:                } else if (!dir.exists()) {
1270:                    return false;
1271:                }
1272:                return true;
1273:            }
1274:
1275:            private void writeDigestLockFile(SVNLock lock, Collection children,
1276:                    String repositoryPath) throws SVNException {
1277:                if (!ensureDirExists(myLocksRoot, true)) {
1278:                    SVNErrorMessage err = SVNErrorMessage.create(
1279:                            SVNErrorCode.UNKNOWN,
1280:                            "Can't create a directory at ''{0}''", myLocksRoot);
1281:                    SVNErrorManager.error(err);
1282:                }
1283:
1284:                File digestLockFile = getDigestFileFromRepositoryPath(repositoryPath);
1285:                String digest = getDigestFromRepositoryPath(repositoryPath);
1286:                File lockDigestSubdir = new File(myLocksRoot, digest.substring(
1287:                        0, FSFS.DIGEST_SUBDIR_LEN));
1288:
1289:                if (!ensureDirExists(lockDigestSubdir, true)) {
1290:                    SVNErrorMessage err = SVNErrorMessage.create(
1291:                            SVNErrorCode.UNKNOWN,
1292:                            "Can't create a directory at ''{0}''",
1293:                            lockDigestSubdir);
1294:                    SVNErrorManager.error(err);
1295:                }
1296:
1297:                Map props = new HashMap();
1298:
1299:                if (lock != null) {
1300:                    props.put(FSFS.PATH_LOCK_KEY, lock.getPath());
1301:                    props.put(FSFS.OWNER_LOCK_KEY, lock.getOwner());
1302:                    props.put(FSFS.TOKEN_LOCK_KEY, lock.getID());
1303:                    props.put(FSFS.IS_DAV_COMMENT_LOCK_KEY, "0");
1304:                    if (lock.getComment() != null) {
1305:                        props.put(FSFS.COMMENT_LOCK_KEY, lock.getComment());
1306:                    }
1307:                    if (lock.getCreationDate() != null) {
1308:                        props.put(FSFS.CREATION_DATE_LOCK_KEY, SVNTimeUtil
1309:                                .formatDate(lock.getCreationDate()));
1310:                    }
1311:                    if (lock.getExpirationDate() != null) {
1312:                        props.put(FSFS.EXPIRATION_DATE_LOCK_KEY, SVNTimeUtil
1313:                                .formatDate(lock.getExpirationDate()));
1314:                    }
1315:                }
1316:                if (children != null && children.size() > 0) {
1317:                    Object[] digests = children.toArray();
1318:                    StringBuffer value = new StringBuffer();
1319:                    for (int i = 0; i < digests.length; i++) {
1320:                        value.append(digests[i]);
1321:                        value.append('\n');
1322:                    }
1323:                    props.put(FSFS.CHILDREN_LOCK_KEY, value.toString());
1324:                }
1325:                try {
1326:                    SVNProperties.setProperties(props, digestLockFile,
1327:                            SVNFileUtil.createUniqueFile(digestLockFile
1328:                                    .getParentFile(), digestLockFile.getName(),
1329:                                    ".tmp"), SVNProperties.SVN_HASH_TERMINATOR);
1330:                } catch (SVNException svne) {
1331:                    SVNErrorMessage err = svne.getErrorMessage().wrap(
1332:                            "Cannot write lock/entries hashfile ''{0}''",
1333:                            digestLockFile);
1334:                    SVNErrorManager.error(err, svne);
1335:                }
1336:            }
1337:
1338:            private FSFile openAndSeekTransaction(FSRepresentation rep) {
1339:                FSFile file = getTransactionRevisionPrototypeFile(rep
1340:                        .getTxnId());
1341:                file.seek(rep.getOffset());
1342:                return file;
1343:            }
1344:
1345:            private FSFile openAndSeekRevision(long revision, long offset)
1346:                    throws SVNException {
1347:                FSFile file = getRevisionFile(revision);
1348:                file.seek(offset);
1349:                return file;
1350:            }
1351:
1352:            private Map parsePlainRepresentation(Map entries,
1353:                    boolean mayContainNulls) throws SVNException {
1354:                Map representationMap = new HashMap();
1355:                Object[] names = entries.keySet().toArray();
1356:                for (int i = 0; i < names.length; i++) {
1357:                    String name = (String) names[i];
1358:                    String unparsedEntry = (String) entries.get(names[i]);
1359:
1360:                    if (unparsedEntry == null && mayContainNulls) {
1361:                        continue;
1362:                    }
1363:
1364:                    FSEntry nextRepEntry = parseRepEntryValue(name,
1365:                            unparsedEntry);
1366:                    if (nextRepEntry == null) {
1367:                        SVNErrorMessage err = SVNErrorMessage.create(
1368:                                SVNErrorCode.FS_CORRUPT,
1369:                                "Directory entry corrupt");
1370:                        SVNErrorManager.error(err);
1371:                    }
1372:                    representationMap.put(name, nextRepEntry);
1373:                }
1374:                return representationMap;
1375:            }
1376:
1377:            private FSEntry parseRepEntryValue(String name, String value) {
1378:                if (value == null) {
1379:                    return null;
1380:                }
1381:                int spaceInd = value.indexOf(' ');
1382:                if (spaceInd == -1) {
1383:                    return null;
1384:                }
1385:                String kind = value.substring(0, spaceInd);
1386:                String rawID = value.substring(spaceInd + 1);
1387:
1388:                SVNNodeKind type = SVNNodeKind.parseKind(kind);
1389:                FSID id = FSID.fromString(rawID);
1390:                if ((type != SVNNodeKind.DIR && type != SVNNodeKind.FILE)
1391:                        || id == null) {
1392:                    return null;
1393:                }
1394:                return new FSEntry(id, type, name);
1395:            }
1396:
1397:            private Date getRevisionTime(long revision) throws SVNException {
1398:                Map revisionProperties = getRevisionProperties(revision);
1399:                String timeString = (String) revisionProperties
1400:                        .get(SVNRevisionProperty.DATE);
1401:                if (timeString == null) {
1402:                    SVNErrorMessage err = SVNErrorMessage
1403:                            .create(
1404:                                    SVNErrorCode.FS_GENERAL,
1405:                                    "Failed to find time on revision {0,number,integer}",
1406:                                    new Long(revision));
1407:                    SVNErrorManager.error(err);
1408:                }
1409:                return SVNTimeUtil.parseDateString(timeString);
1410:            }
1411:
1412:            private static boolean isRepositoryRoot(File candidatePath) {
1413:                File formatFile = new File(candidatePath, "format");
1414:                SVNFileType fileType = SVNFileType.getType(formatFile);
1415:                if (fileType != SVNFileType.FILE) {
1416:                    return false;
1417:                }
1418:                File dbFile = new File(candidatePath, SVN_REPOS_DB_DIR);
1419:                fileType = SVNFileType.getType(dbFile);
1420:                if (fileType != SVNFileType.DIRECTORY
1421:                        && fileType != SVNFileType.SYMLINK) {
1422:                    return false;
1423:                }
1424:                return true;
1425:            }
1426:
1427:        }
ww_w__.___j_a___v_a_2___s__._c___o__m | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.