1 29 30 package com.caucho.vfs; 31 32 import com.caucho.util.CharBuffer; 33 import com.caucho.util.Crc64; 34 import com.caucho.util.L10N; 35 import com.caucho.util.LruCache; 36 import com.caucho.util.RandomUtil; 37 38 import java.io.File ; 39 import java.io.IOException ; 40 import java.io.OutputStream ; 41 import java.security.cert.Certificate ; 42 import java.util.ArrayList ; 43 import java.util.Iterator ; 44 import java.util.Map ; 45 46 66 public abstract class Path { 67 protected final static L10N L = new L10N(Path.class); 68 69 private static final Integer LOCK = new Integer (0); 70 71 private static final LruCache<PathKey,Path> _pathLookupCache 72 = new LruCache<PathKey,Path>(8192); 73 74 private static boolean _isTestWindows; 75 76 protected static char _separatorChar = File.separatorChar; 77 protected static char _pathSeparatorChar = File.pathSeparatorChar; 78 private static String _newline; 79 80 private static final PathKey _key = new PathKey(); 81 82 private static final SchemeMap DEFAULT_SCHEME_MAP = new SchemeMap(); 83 84 private static SchemeMap _defaultSchemeMap; 85 86 protected SchemeMap _schemeMap = _defaultSchemeMap; 87 88 93 protected Path(Path root) 94 { 95 if (root != null) 96 _schemeMap = root._schemeMap; 97 else if (_defaultSchemeMap != null) 98 _schemeMap = _defaultSchemeMap; 99 else 100 _schemeMap = DEFAULT_SCHEME_MAP; 101 } 102 103 109 public final Path lookup(String name) 110 { 111 return lookup(name, null); 112 } 113 114 125 public Path lookup(String userPath, Map <String ,Object > newAttributes) 126 { 127 if (newAttributes != null) 128 return lookupImpl(userPath, newAttributes); 129 130 synchronized (_key) { 131 _key.init(this, userPath); 132 133 Path path = _pathLookupCache.get(_key); 134 135 if (path != null) { 136 return path.cacheCopy(); 137 } 138 } 139 140 Path path = lookupImpl(userPath, null); 141 142 synchronized (_key) { 143 Path copy = path.cacheCopy(); 144 145 if (copy != null) { 146 _pathLookupCache.putIfNew(new PathKey(this, userPath), copy); 147 } 148 } 149 150 return path; 151 } 152 153 164 public Path lookupImpl(String userPath, Map <String ,Object > newAttributes) 165 { 166 if (userPath == null) 167 return lookupImpl(getPath(), newAttributes); 168 169 String scheme = scanScheme(userPath); 170 171 if (scheme == null) 172 return schemeWalk(userPath, newAttributes, userPath, 0); 173 174 Path path; 175 176 SchemeMap schemeMap = _schemeMap; 177 178 if (isWindows()) { 181 int length = scheme.length(); 182 int ch; 183 184 if (length == 1 && 185 ((ch = scheme.charAt(0)) >= 'a' && ch <= 'z' || 186 ch >= 'A' && ch <= 'Z')) { 187 path = schemeMap.get("file"); 188 189 if (path != null) 190 return path.schemeWalk(userPath, newAttributes, "/" + userPath, 0); 191 } 192 } 193 194 path = schemeMap.get(scheme); 195 196 if (path == null) 198 return schemeWalk(userPath, newAttributes, userPath, 0); 199 200 return path.schemeWalk(userPath, newAttributes, 201 userPath, scheme.length() + 1); 202 } 203 204 211 public final Path lookupNative(String name) 212 { 213 return lookupNative(name, null); 214 } 215 218 public Path lookupNative(String name, Map <String ,Object > attributes) 219 { 220 return lookup(name, attributes); 221 } 222 223 228 public String lookupRelativeNativePath(Path path) 229 { 230 String thisNative = getNativePath(); 231 String pathNative = path.getNativePath(); 232 233 if (pathNative.startsWith(thisNative)) { 234 int i = thisNative.length(); 235 236 while (i < pathNative.length()) { 237 if (pathNative.charAt(i) != getFileSeparatorChar()) 238 break; 239 240 i++; 241 } 242 243 return i == pathNative.length() ? "" : pathNative.substring(i); 244 } 245 else 246 return pathNative; 247 } 248 249 253 public ArrayList <Path> getResources(String name) 254 { 255 ArrayList <Path> list = new ArrayList <Path>(); 256 Path path = lookup(name); 257 if (path.exists()) 258 list.add(path); 259 260 return list; 261 } 262 263 267 public ArrayList <Path> getResources() 268 { 269 ArrayList <Path> list = new ArrayList <Path>(); 270 271 list.add(this); 273 274 return list; 275 } 276 277 280 public Path getParent() 281 { 282 return this; 283 } 284 285 289 protected String scanScheme(String uri) 290 { 291 int i = 0; 292 if (uri == null) 293 return null; 294 295 int length = uri.length(); 296 if (length == 0) 297 return null; 298 299 int ch = uri.charAt(0); 300 if (ch >= 'a' && ch <= 'z' || 301 ch >= 'A' && ch <= 'Z') { 302 for (i = 1; i < length; i++) { 303 ch = uri.charAt(i); 304 305 if (ch == ':') 306 return uri.substring(0, i).toLowerCase(); 307 308 if (! (ch >= 'a' && ch <= 'z' || 309 ch >= 'A' && ch <= 'Z' || 310 ch >= '0' && ch <= '0' || 311 ch == '+' || ch == '-' || ch == '.')) 312 break; 313 } 314 } 315 316 return null; 317 } 318 319 329 abstract protected Path schemeWalk(String userPath, 330 Map <String ,Object > newAttributes, 331 String newPath, int offset); 332 333 336 public String getURL() 337 { 338 return escapeURL(getScheme() + ":" + getFullPath()); 339 } 340 341 344 public abstract String getScheme(); 345 348 public String getHost() 349 { 350 throw new UnsupportedOperationException (); 351 } 352 355 public int getPort() 356 { 357 throw new UnsupportedOperationException (); 358 } 359 363 public abstract String getPath(); 364 365 371 public String getTail() 372 { 373 return ""; 374 } 375 378 public String getQuery() 379 { 380 throw new UnsupportedOperationException (); 381 } 382 383 389 public String getNativePath() 390 { 391 return getFullPath(); 392 } 393 405 public String getUserPath() 406 { 407 return getPath(); 408 } 409 410 414 public void setUserPath(String userPath) 415 { 416 } 417 427 public String getFullPath() 428 { 429 return getPath(); 430 } 431 432 436 public String getRelativePath() 437 { 438 return getPath(); 439 } 440 441 444 public Certificate []getCertificates() 445 { 446 return null; 447 } 448 449 452 public boolean exists() 453 { 454 return false; 455 } 456 457 461 public String getContentType() 462 { 463 return "application/octet-stream"; 464 } 465 466 469 public boolean isDirectory() 470 { 471 return false; 472 } 473 474 477 public boolean isFile() 478 { 479 return false; 480 } 481 482 485 public boolean isLink() 486 { 487 return false; 488 } 489 490 493 public boolean isSocket() 494 { 495 return false; 496 } 497 498 501 public boolean isFIFO() 502 { 503 return false; 504 } 505 506 509 public boolean isBlockDevice() 510 { 511 return false; 512 } 513 514 517 public boolean isCharacterDevice() 518 { 519 return false; 520 } 521 522 525 public boolean isExecutable() 526 { 527 return false; 528 } 529 530 535 public boolean setExecutable(boolean isExecutable) 536 { 537 return false; 538 } 539 540 543 public boolean isSymbolicLink() 544 { 545 return false; 546 } 547 548 551 public boolean isHardLink() 552 { 553 return false; 554 } 555 556 559 public boolean isObject() 560 { 561 return false; 562 } 563 564 568 public long getLength() 569 { 570 return 0; 571 } 572 573 578 public long getLastModified() 579 { 580 return 0; 581 } 582 583 public void setLastModified(long time) 584 { 585 } 586 587 592 public long getLastAccessTime() 593 { 594 return getLastModified(); 595 } 596 597 602 public long getCreateTime() 603 { 604 return getLastModified(); 605 } 606 607 610 public boolean canRead() 611 { 612 return false; 613 } 614 615 618 public boolean canWrite() 619 { 620 return false; 621 } 622 623 627 630 public long getDevice() 631 { 632 return 0; 633 } 634 635 638 public long getInode() 639 { 640 return 0; 641 } 642 643 646 public int getMode() 647 { 648 return 0; 649 } 650 651 654 public int getNumberOfLinks() 655 { 656 return 0; 657 } 658 659 662 public int getUser() 663 { 664 return 0; 665 } 666 667 670 public int getGroup() 671 { 672 return 0; 673 } 674 675 678 public long getDeviceId() 679 { 680 return 0; 681 } 682 683 686 public long getBlockSize() 687 { 688 return 0; 689 } 690 691 694 public long getBlockCount() 695 { 696 return 0; 697 } 698 699 702 public long getLastStatusChangeTime() 703 { 704 return 0; 705 } 706 707 710 public boolean canExecute() 711 { 712 return canRead(); 713 } 714 715 718 public boolean changeGroup(int gid) 719 throws IOException 720 { 721 return false; 722 } 723 724 727 public boolean changeGroup(String groupName) 728 throws IOException 729 { 730 return false; 731 } 732 733 738 public boolean chmod(int value) 739 { 740 return false; 741 } 742 743 public int getOwner() 744 { 745 return 0; 746 } 747 748 753 public boolean changeOwner(int uid) 754 throws IOException 755 { 756 return false; 757 } 758 759 764 public boolean changeOwner(String ownerName) 765 throws IOException 766 { 767 return false; 768 } 769 770 public long getDiskSpaceFree() 771 { 772 return 0; 773 } 774 775 public long getDiskSpaceTotal() 776 { 777 return 0; 778 } 779 780 784 public String []list() throws IOException 785 { 786 return new String [0]; 787 } 788 789 792 public Iterator <String > iterator() throws IOException 793 { 794 return new ArrayIterator(list()); 795 } 796 797 801 public boolean mkdir() throws IOException 802 { 803 return false; 804 } 805 806 810 public boolean mkdirs() throws IOException 811 { 812 return false; 813 } 814 815 820 public boolean remove() throws IOException 821 { 822 return false; 823 } 824 825 830 public boolean removeAll() throws IOException 831 { 832 if (isDirectory()) { 833 String []list = list(); 834 835 for (int i = 0; i < list.length; i++) { 836 Path subpath = lookup(list[i]); 837 subpath.removeAll(); 838 } 839 } 840 841 return remove(); 842 } 843 844 849 public boolean truncate() 850 throws IOException 851 { 852 return truncate(0); 853 } 854 855 860 public boolean truncate(long length) 861 throws IOException 862 { 863 if (length == 0) { 864 if (exists()) { 865 StreamImpl stream = openWriteImpl(); 866 stream.close(); 867 868 return true; 869 } 870 else 871 return false; 872 } 873 else 874 throw new UnsupportedOperationException (getClass().getName() + ": truncate"); 875 } 876 877 881 public boolean renameTo(Path path) throws IOException 882 { 883 return false; 884 } 885 886 890 public final boolean renameTo(String path) throws IOException 891 { 892 return renameTo(lookup(path)); 893 } 894 895 903 public Path createRoot() 904 { 905 return createRoot(SchemeMap.getNullSchemeMap()); 906 } 907 908 public Path createRoot(SchemeMap schemeMap) 909 { 910 throw new UnsupportedOperationException ("createRoot"); 911 } 912 913 918 public void bind(Path context) 919 { 920 throw new UnsupportedOperationException ("bind"); 921 } 922 923 926 public void unbind() 927 { 928 throw new UnsupportedOperationException ("unbind"); 929 } 930 931 938 public Object getValue() throws Exception 939 { 940 throw new UnsupportedOperationException ("getValue"); 941 } 942 943 950 public void setValue(Object obj) throws Exception 951 { 952 throw new UnsupportedOperationException ("setValue"); 953 } 954 955 958 public Object getAttribute(String name) throws IOException 959 { 960 return null; 961 } 962 963 967 public Iterator getAttributeNames() throws IOException 968 { 969 return null; 970 } 971 972 975 public final ReadStream openRead() throws IOException 976 { 977 StreamImpl impl = openReadImpl(); 978 impl.setPath(this); 979 980 return new ReadStream(impl); 981 } 982 983 986 public final WriteStream openWrite() throws IOException 987 { 988 StreamImpl impl = openWriteImpl(); 989 impl.setPath(this); 990 return new WriteStream(impl); 991 } 992 993 999 public ReadWritePair openReadWrite() throws IOException 1000 { 1001 StreamImpl impl = openReadWriteImpl(); 1002 impl.setPath(this); 1003 WriteStream writeStream = new WriteStream(impl); 1004 ReadStream readStream = new ReadStream(impl, writeStream); 1005 return new ReadWritePair(readStream, writeStream); 1006 } 1007 1008 1017 public void openReadWrite(ReadStream is, WriteStream os) throws IOException 1018 { 1019 StreamImpl impl = openReadWriteImpl(); 1020 impl.setPath(this); 1021 1022 os.init(impl); 1023 is.init(impl, os); 1024 } 1025 1026 1029 public WriteStream openAppend() throws IOException 1030 { 1031 StreamImpl impl = openAppendImpl(); 1032 return new WriteStream(impl); 1033 } 1034 1035 1038 public RandomAccessStream openRandomAccess() throws IOException 1039 { 1040 throw new UnsupportedOperationException (getClass().getName()); 1041 } 1042 1043 1047 public boolean createNewFile() throws IOException 1048 { 1049 synchronized (LOCK) { 1050 if (! exists()) { 1051 WriteStream s = openWrite(); 1052 s.close(); 1053 return true; 1054 } 1055 } 1056 1057 return false; 1058 } 1059 1060 1067 public Path createTempFile(String prefix, String suffix) throws IOException 1068 { 1069 if (prefix == null || prefix.length () < 3) 1070 throw new IllegalArgumentException ("prefix too short: " + prefix); 1071 1072 if (suffix == null) 1073 suffix = ".tmp"; 1074 1075 synchronized (LOCK) { 1076 for (int i = 0; i < 32768; i++) { 1077 int r = Math.abs((int) RandomUtil.getRandomLong()); 1078 Path file = lookup(prefix + r + suffix); 1079 1080 if (file.createNewFile()) 1081 return file; 1082 } 1083 } 1084 1085 throw new IOException ("cannot create temp file"); 1086 } 1087 1088 1094 public boolean createLink(Path target, boolean hardLink) 1095 throws IOException 1096 { 1097 throw new UnsupportedOperationException (getScheme() + ": doesn't support createLink"); 1098 } 1099 1100 1105 public void writeToStream(OutputStream os) 1106 throws IOException 1107 { 1108 StreamImpl is = openReadImpl(); 1109 TempBuffer tempBuffer = TempBuffer.allocate(); 1110 try { 1111 byte []buffer = tempBuffer.getBuffer(); 1112 int length = buffer.length; 1113 int len; 1114 1115 while ((len = is.read(buffer, 0, length)) > 0) 1116 os.write(buffer, 0, len); 1117 } finally { 1118 TempBuffer.free(tempBuffer); 1119 1120 is.close(); 1121 } 1122 } 1123 1124 1129 public void writeToStream(OutputStreamWithBuffer os) 1130 throws IOException 1131 { 1132 StreamImpl is = openReadImpl(); 1133 1134 try { 1135 byte []buffer = os.getBuffer(); 1136 int offset = os.getBufferOffset(); 1137 int length = buffer.length; 1138 1139 while (true) { 1140 int sublen = length - offset; 1141 1142 if (sublen <= 0) { 1143 buffer = os.nextBuffer(offset); 1144 offset = 0; 1145 sublen = length; 1146 } 1147 1148 sublen = is.read(buffer, offset, sublen); 1149 1150 if (sublen <= 0) { 1151 os.setBufferOffset(offset); 1152 return; 1153 } 1154 1155 offset += sublen; 1156 } 1157 } finally { 1158 is.close(); 1159 } 1160 } 1161 1162 1165 public long getCrc64() 1166 { 1167 try { 1168 if (isDirectory()) { 1169 String []list = list(); 1170 1171 long digest = 0; 1172 1173 for (int i = 0; i < list.length; i++) { 1174 digest = Crc64.generate(digest, list[i]); 1175 } 1176 1177 return digest; 1178 } 1179 else if (canRead()) { 1180 ReadStream is = openRead(); 1181 1182 try { 1183 long digest = 0; 1184 1185 int ch; 1186 1187 while ((ch = is.read()) >= 0) { 1188 digest = Crc64.next(digest, ch); 1189 } 1190 1191 return digest; 1192 } finally { 1193 is.close(); 1194 } 1195 } 1196 else { 1197 return -1; } 1199 } catch (IOException e) { 1200 e.printStackTrace(); 1202 1203 return -1; 1204 } 1205 } 1206 1207 1211 public Object getObject() 1212 throws IOException 1213 { 1214 throw new UnsupportedOperationException (getScheme() + ": doesn't support getObject"); 1215 } 1216 1217 1221 public void setObject(Object obj) 1222 throws IOException 1223 { 1224 throw new UnsupportedOperationException (getScheme() + ": doesn't support setObject"); 1225 } 1226 1227 public int hashCode() 1228 { 1229 return toString().hashCode(); 1230 } 1231 1232 public boolean equals(Object o) 1233 { 1234 if (this == o) 1235 return true; 1236 else if (! (o instanceof Path)) 1237 return false; 1238 else 1239 return getPath().equals(((Path) o).getPath()); 1240 } 1241 1242 public String toString() 1243 { 1244 return getPath(); 1245 } 1246 1247 public StreamImpl openReadImpl() throws IOException 1248 { 1249 throw new UnsupportedOperationException ("openRead:" + getClass().getName()); 1250 } 1251 1252 public StreamImpl openWriteImpl() throws IOException 1253 { 1254 throw new UnsupportedOperationException ("openWrite:" + getClass().getName()); 1255 } 1256 1257 public StreamImpl openReadWriteImpl() throws IOException 1258 { 1259 throw new UnsupportedOperationException ("openReadWrite:" + getClass().getName()); 1260 } 1261 1262 public StreamImpl openAppendImpl() throws IOException 1263 { 1264 throw new UnsupportedOperationException ("openAppend:" + getClass().getName()); 1265 } 1266 1267 protected static String escapeURL(String rawURL) 1268 { 1269 CharBuffer cb = null; 1270 int length = rawURL.length(); 1271 1272 for (int i = 0; i < length; i++) { 1273 char ch = rawURL.charAt(i); 1274 1275 switch (ch) { 1276 case ' ': 1277 if (cb == null) { 1278 cb = new CharBuffer(); 1279 cb.append(rawURL, 0, i); 1280 } 1281 cb.append("%20"); 1282 break; 1283 1284 case '#': 1285 if (cb == null) { 1286 cb = new CharBuffer(); 1287 cb.append(rawURL, 0, i); 1288 } 1289 cb.append("%23"); 1290 break; 1291 1292 case '%': 1293 if (cb == null) { 1294 cb = new CharBuffer(); 1295 cb.append(rawURL, 0, i); 1296 } 1297 cb.append("%25"); 1298 break; 1299 1300 default: 1301 if (cb != null) 1302 cb.append(ch); 1303 break; 1304 } 1305 } 1306 1307 if (cb != null) 1308 return cb.toString(); 1309 else 1310 return rawURL; 1311 } 1312 1313 protected Path copy() 1314 { 1315 return this; 1316 } 1317 1318 1321 protected Path cacheCopy() 1322 { 1323 return this; 1324 } 1325 1326 public static final void setDefaultSchemeMap(SchemeMap schemeMap) 1327 { 1328 _defaultSchemeMap = schemeMap; 1329 _pathLookupCache.clear(); 1330 } 1331 1332 public static final boolean isWindows() 1333 { 1334 return _separatorChar == '\\' || _isTestWindows; 1335 } 1336 1337 protected static final char getSeparatorChar() 1338 { 1339 return _separatorChar; 1340 } 1341 1342 public static final char getFileSeparatorChar() 1343 { 1344 return _separatorChar; 1345 } 1346 1347 public static final char getPathSeparatorChar() 1348 { 1349 return _pathSeparatorChar; 1350 } 1351 1352 protected static String getUserDir() 1353 { 1354 return System.getProperty("user.dir"); 1355 } 1356 1357 public static String getNewlineString() 1358 { 1359 if (_newline == null) { 1360 _newline = System.getProperty("line.separator"); 1361 if (_newline == null) 1362 _newline = "\n"; 1363 } 1364 1365 return _newline; 1366 } 1367 1368 private class ArrayIterator implements Iterator <String > { 1369 String []list; 1370 int index; 1371 1372 public boolean hasNext() { return index < list.length; } 1373 public String next() { return index < list.length ? list[index++] : null; } 1374 public void remove() { throw new UnsupportedOperationException (); } 1375 1376 ArrayIterator(String []list) 1377 { 1378 this.list = list; 1379 index = 0; 1380 } 1381 } 1382 1383 static class PathKey { 1384 private Path _parent; 1385 private String _lookup; 1386 1387 PathKey() 1388 { 1389 } 1390 1391 PathKey(Path parent, String lookup) 1392 { 1393 _parent = parent; 1394 _lookup = lookup; 1395 } 1396 1397 void init(Path parent, String lookup) 1398 { 1399 _parent = parent; 1400 _lookup = lookup; 1401 } 1402 1403 public int hashCode() 1404 { 1405 return System.identityHashCode(_parent) * 65521 + _lookup.hashCode(); 1406 } 1407 1408 public boolean equals(Object test) 1409 { 1410 if (! (test instanceof PathKey)) 1411 return false; 1412 1413 PathKey key = (PathKey) test; 1414 1415 return (_parent == key._parent && _lookup.equals(key._lookup)); 1416 } 1417 } 1418 1419 static { 1420 DEFAULT_SCHEME_MAP.put("file", new FilePath(null)); 1421 1422 DEFAULT_SCHEME_MAP.put("http", new HttpPath("127.0.0.1", 0)); 1424 DEFAULT_SCHEME_MAP.put("https", new HttpsPath("127.0.0.1", 0)); 1425 DEFAULT_SCHEME_MAP.put("tcp", new TcpPath(null, null, null, "127.0.0.1", 0)); 1426 DEFAULT_SCHEME_MAP.put("tcps", new TcpsPath(null, null, null, "127.0.0.1", 0)); 1427 1428 StreamImpl stdout = StdoutStream.create(); 1429 StreamImpl stderr = StderrStream.create(); 1430 DEFAULT_SCHEME_MAP.put("stdout", stdout.getPath()); 1431 DEFAULT_SCHEME_MAP.put("stderr", stderr.getPath()); 1432 VfsStream nullStream = new VfsStream(null, null); 1433 DEFAULT_SCHEME_MAP.put("null", new ConstPath(null, nullStream)); 1434 DEFAULT_SCHEME_MAP.put("jndi", new JndiPath()); 1435 } 1436} 1437 | Popular Tags |