1 29 30 package com.caucho.quercus.lib.file; 31 32 import com.caucho.quercus.QuercusModuleException; 33 import com.caucho.quercus.annotation.NotNull; 34 import com.caucho.quercus.annotation.Optional; 35 import com.caucho.quercus.annotation.ReturnNullAsFalse; 36 import com.caucho.quercus.env.*; 37 import com.caucho.quercus.lib.UrlModule; 38 import com.caucho.quercus.lib.string.StringModule; 39 import com.caucho.quercus.module.AbstractQuercusModule; 40 import com.caucho.util.Alarm; 41 import com.caucho.util.L10N; 42 import com.caucho.vfs.Path; 43 import com.caucho.vfs.ReadStream; 44 import com.caucho.vfs.TempBuffer; 45 import com.caucho.vfs.WriteStream; 46 47 import java.io.IOException ; 48 import java.io.InputStream ; 49 import java.util.Arrays ; 50 import java.util.HashMap ; 51 import java.util.Map ; 52 import java.util.logging.Level ; 53 import java.util.logging.Logger ; 54 import java.util.regex.Matcher ; 55 import java.util.regex.Pattern ; 56 import java.util.regex.PatternSyntaxException ; 57 58 61 public class FileModule extends AbstractQuercusModule { 62 private static final L10N L = new L10N(FileModule.class); 63 private static final Logger log 64 = Logger.getLogger(FileModule.class.getName()); 65 66 public static final String DIRECTORY_SEPARATOR = "/"; 67 public static final String PATH_SEPARATOR = ":"; 68 69 public static final int UPLOAD_ERROR_OK = 0; 70 public static final int UPLOAD_ERR_INI_SIZE = 1; 71 public static final int UPLOAD_ERR_FORM_SIZE = 2; 72 public static final int UPLOAD_ERR_PARTIAL = 3; 73 public static final int UPLOAD_ERR_NO_FILE = 4; 74 75 public static final int FILE_USE_INCLUDE_PATH = 1; 76 public static final int FILE_APPEND = 8; 77 78 public static final int LOCK_SH = 1; 79 public static final int LOCK_EX = 2; 80 public static final int LOCK_UN = 3; 81 public static final int LOCK_NB = 4; 82 83 public static final int FNM_PATHNAME = 1; 84 public static final int FNM_NOESCAPE = 2; 85 public static final int FNM_PERIOD = 4; 86 public static final int FNM_CASEFOLD = 16; 87 88 public static final int GLOB_MARK = 2; 89 public static final int GLOB_NOSORT = 4; 90 public static final int GLOB_NOCHECK = 16; 91 public static final int GLOB_NOESCAPE = 64; 92 public static final int GLOB_BRACE = 1024; 93 public static final int GLOB_ONLYDIR = 8192; 94 95 private static final HashMap <String ,StringValue> _iniMap 96 = new HashMap <String ,StringValue>(); 97 98 private static final HashMap <String ,Value> _constMap 99 = new HashMap <String ,Value>(); 100 101 104 public Map <String ,StringValue> getDefaultIni() 105 { 106 return _iniMap; 107 } 108 109 112 public Map <String ,Value> getConstMap() 113 { 114 return _constMap; 115 } 116 117 120 public static String basename(String path, @Optional String suffix) 121 { 122 int len = path.length(); 123 124 if (len == 0) 125 return ""; 126 else if (path.endsWith("/")) 127 len -= 1; 128 else if (path.endsWith("\\")) 129 len -= 1; 130 131 int p = path.lastIndexOf('/', len - 1); 132 133 if (p < 0) 134 p = path.lastIndexOf('\\', len - 1); 135 136 String file; 137 138 if (p < 0) 139 file = path.substring(0, len); 140 else 141 file = path.substring(p + 1, len); 142 143 if (suffix != null && file.endsWith(suffix)) 144 file = file.substring(0, file.length() - suffix.length()); 145 146 return file; 147 } 148 149 154 public static boolean chdir(Env env, Path path) 155 { 156 if (path.isDirectory()) { 157 env.setPwd(path); 158 return true; 159 } 160 else { 161 env.warning(L.l("{0} is not a directory", path.getFullPath())); 162 163 return false; 164 } 165 } 166 167 172 public static boolean chroot(Env env, Path path) 173 { 174 if (path.isDirectory()) { 175 env.setPwd(path.createRoot()); 176 177 return true; 178 } 179 else { 180 env.warning(L.l("{0} is not a directory", path.getFullPath())); 181 182 return false; 183 } 184 } 185 186 193 public static boolean chgrp(Env env, Path file, Value group) 194 { 195 if (!file.canRead()) { 196 env.warning(L.l("{0} cannot be read", file.getFullPath())); 197 198 return false; 199 } 200 201 203 try { 204 206 if (group instanceof LongValue) 207 file.changeGroup(group.toInt()); 208 else 209 file.changeGroup(group.toString()); 210 211 return true; 212 } catch (IOException e) { 213 log.log(Level.FINE, e.toString(), e); 214 215 return false; 216 } 217 } 218 219 226 public static boolean chmod(Env env, Path file, int mode) 227 { 228 if (! file.canRead()) { 229 env.warning(L.l("{0} cannot be read", file.getFullPath())); 231 232 return false; 233 } 234 235 file.chmod(mode); 237 238 return true; 239 } 240 241 248 public static boolean chown(Env env, Path file, Value user) 249 { 250 if (!file.canRead()) { 251 env.warning(L.l("{0} cannot be read", file.getFullPath())); 252 253 return false; 254 } 255 256 try { 257 259 if (user instanceof LongValue) 260 file.changeOwner(user.toInt()); 261 else 262 file.changeOwner(user.toString()); 263 264 return true; 265 } catch (IOException e) { 266 log.log(Level.FINE, e.toString(), e); 267 268 return false; 269 } 270 } 271 272 277 public static Value clearstatcache(Env env) 278 { 279 281 283 return NullValue.NULL; 284 } 285 286 292 public static boolean copy(Env env, Path src, Path dst) 293 { 294 296 try { 297 if (! src.canRead() || ! src.isFile()) { 298 env.warning(L.l("{0} cannot be read", src.getFullPath())); 299 300 return false; 301 } 302 303 WriteStream os = dst.openWrite(); 304 305 try { 306 src.writeToStream(os); 307 } finally { 308 os.close(); 309 } 310 311 return true; 312 } catch (IOException e) { 313 log.log(Level.FINE, e.toString(), e); 314 315 return false; 316 } 317 } 318 319 324 @ReturnNullAsFalse 325 public static Directory dir(Env env, Path path) 326 { 327 try { 328 if (! path.isDirectory()) { 329 env.warning(L.l("{0} is not a directory", path.getFullPath())); 330 331 return null; 332 } 333 334 return new Directory(env, path); 335 336 343 } catch (IOException e) { 344 throw new QuercusModuleException(e); 345 } 346 } 347 348 351 public String dirname(String path) 352 { 353 355 int len = path.length(); 356 357 if (len == 0) 358 return "."; 359 else if (path.equals("/")) 360 return path; 361 362 int p = path.lastIndexOf('/', len - 2); 363 364 if (p == 0) 365 return "/"; 366 else if (p > 0) 367 return path.substring(0, p); 368 369 p = path.lastIndexOf('\\', len - 2); 370 371 if (p == 0) 372 return "\\"; 373 else if (p > 0) 374 return path.substring(0, p); 375 376 return "."; 377 } 378 379 384 public static Value disk_free_space(Env env, Path directory) 385 { 386 388 if (!directory.canRead()) { 389 env.warning(L.l("{0} cannot be read", directory.getFullPath())); 390 391 return BooleanValue.FALSE; 392 } 393 394 return new DoubleValue(directory.getDiskSpaceFree()); 395 } 396 397 402 public static Value disk_total_space(Env env, Path directory) 403 { 404 406 if (!directory.canRead()) { 407 env.warning(L.l("{0} cannot be read", directory.getFullPath())); 408 409 return BooleanValue.FALSE; 410 } 411 412 return new DoubleValue(directory.getDiskSpaceTotal()); 413 } 414 415 420 public static Value diskfreespace(Env env, Path directory) 421 { 422 return disk_free_space(env, directory); 423 } 424 425 428 public static boolean fclose(Env env, @NotNull BinaryStream s) 429 { 430 if (s == null) 431 return false; 432 433 s.close(); 434 435 return true; 436 } 437 438 441 public static boolean feof(Env env, @NotNull BinaryInput is) 442 { 443 if (is == null) 444 return false; 445 446 return is.isEOF(); 447 } 448 449 452 public static boolean fflush(Env env, @NotNull BinaryOutput os) 453 { 454 if (os == null) 455 return false; 456 457 try { 458 os.flush(); 459 460 return true; 461 } catch (IOException e) { 462 return false; 463 } 464 } 465 466 469 public static Value fgetc(Env env, @NotNull BinaryInput is) 470 { 471 try { 472 if (is == null) 473 return BooleanValue.FALSE; 474 475 int ch = is.read(); 477 478 if (ch >= 0) 479 return new BinaryBuilderValue(new byte[] { (byte) ch }); 480 else 481 return BooleanValue.FALSE; 482 } catch (IOException e) { 483 throw new QuercusModuleException(e); 484 } 485 } 486 487 495 public Value fgetcsv(Env env, 496 @NotNull BinaryInput is, 497 @Optional int length, 498 @Optional String delimiter, 499 @Optional String enclosure) 500 { 501 503 try { 504 if (is == null) 505 return BooleanValue.FALSE; 506 507 if (length <= 0) 509 length = Integer.MAX_VALUE; 510 511 int comma = ','; 512 513 if (delimiter != null && delimiter.length() > 0) 514 comma = delimiter.charAt(0); 515 516 int quote = '"'; 517 518 if (enclosure != null && enclosure.length() > 0) 519 quote = enclosure.charAt(0); 520 521 ArrayValue array = new ArrayValueImpl(); 522 523 int ch; 524 525 while (true) { 526 while (true) { 528 ch = is.read(); 529 530 if (ch < 0 || ch == '\n') 531 return array; 532 else if (ch == '\r') { 533 is.readOptionalLinefeed(); 534 return array; 535 } 536 else if (ch == ' ' || ch == '\t') 537 continue; 538 else 539 break; 540 } 541 542 StringBuilderValue sb = new StringBuilderValue(); 543 544 if (ch == quote) { 545 for (ch = is.read(); ch >= 0; ch = is.read()) { 546 if (ch == quote) { 547 ch = is.read(); 548 549 if (ch == quote) 550 sb.append((char) ch); 551 else 552 break; 553 } 554 else 555 sb.append((char) ch); 556 } 557 558 array.append(sb); 559 560 for (; ch >= 0 && ch == ' ' || ch == '\t'; ch = is.read()) { 561 } 562 } 563 else { 564 for (; 565 ch >= 0 && ch != comma && ch != '\r' && ch != '\n'; 566 ch = is.read()) { 567 sb.append((char) ch); 568 } 569 570 array.append(sb); 571 } 572 573 if (ch < 0) 574 return array; 575 else if (ch == '\n') 576 return array; 577 else if (ch == '\r') { 578 is.readOptionalLinefeed(); 579 return array; 580 } 581 else if (ch == comma) { 582 } 583 else { 584 env.warning("expected comma"); 585 } 586 } 587 } catch (IOException e) { 588 throw new QuercusModuleException(e); 589 } 590 } 591 592 595 public static Value fgets(Env env, 596 @NotNull BinaryInput is, 597 @Optional("0x7fffffff") int length) 598 { 599 601 try { 602 if (is == null) 603 return BooleanValue.FALSE; 604 605 StringValue value = is.readLine(length); 606 607 if (value != null) 608 return value; 609 else 610 return BooleanValue.FALSE; 611 } catch (IOException e) { 612 throw new QuercusModuleException(e); 613 } 614 } 615 616 619 public static Value fgetss(Env env, 620 BinaryInput is, 621 @Optional("0x7fffffff") int length, 622 @Optional String allowedTags) 623 { 624 626 try { 627 if (is == null) { 628 env.warning(L.l("{0} is null", "handle")); 629 return BooleanValue.FALSE; 630 } 631 632 StringValue value = is.readLine(length); 633 634 if (value != null) 635 return StringModule.strip_tags(value, allowedTags); 636 else 637 return BooleanValue.FALSE; 638 } catch (IOException e) { 639 throw new QuercusModuleException(e); 640 } 641 } 642 643 650 public static Value file(Env env, 651 String filename, 652 @Optional boolean useIncludePath, 653 @Optional Value context) 654 { 655 656 657 try { 658 BinaryStream stream = fopen(env, filename, "r", useIncludePath, context); 659 660 if (stream == null) 661 return BooleanValue.FALSE; 662 663 BinaryInput is = (BinaryInput) stream; 664 665 ArrayValue result = new ArrayValueImpl(); 666 667 try { 668 while (true) { 669 BinaryBuilderValue bb = new BinaryBuilderValue(); 670 671 for (int ch = is.read(); ch >= 0; ch = is.read()) { 672 if (ch == '\n') { 673 bb.appendByte(ch); 674 break; 675 } 676 else if (ch == '\r') { 677 bb.appendByte('\r'); 678 679 int ch2 = is.read(); 680 681 if (ch == '\n') 682 bb.appendByte('\n'); 683 else 684 is.unread(); 685 686 break; 687 } 688 else 689 bb.appendByte(ch); 690 } 691 692 if (bb.length() > 0) 693 result.append(bb); 694 else 695 return result; 696 } 697 } finally { 698 is.close(); 699 } 700 } catch (IOException e) { 701 throw new QuercusModuleException(e); 702 } 703 } 704 705 710 public static Value fileatime(Env env, Path path) 711 { 712 if (!path.canRead()) { 713 env.warning(L.l("{0} cannot be read", path.getFullPath())); 714 return BooleanValue.FALSE; 715 } 716 717 long time = path.getLastAccessTime(); 718 719 if (time <= 24 * 3600 * 1000L) 720 return BooleanValue.FALSE; 721 else 722 return new LongValue(time / 1000L); 723 } 724 725 730 public static Value filectime(Env env, Path path) 731 { 732 if (!path.canRead()) { 733 env.warning(L.l("{0} cannot be read", path.getFullPath())); 734 return BooleanValue.FALSE; 735 } 736 737 long time = path.getCreateTime(); 738 739 if (time <= 24 * 3600 * 1000L) 740 return BooleanValue.FALSE; 741 else 742 return new LongValue(time / 1000L); 743 } 744 745 750 public static Value filegroup(Env env, Path path) 751 { 752 if (!path.canRead()) { 753 env.warning(L.l("{0} cannot be read", path.getFullPath())); 754 return BooleanValue.FALSE; 755 } 756 757 return new LongValue(path.getGroup()); 758 } 759 760 765 public static Value fileinode(Env env, Path path) 766 { 767 if (!path.canRead()) { 768 env.warning(L.l("{0} cannot be read", path.getFullPath())); 769 return BooleanValue.FALSE; 770 } 771 772 return new LongValue(path.getInode()); 773 } 774 775 780 public static Value filemtime(Env env, Path path) 781 { 782 if (!path.canRead()) { 783 env.warning(L.l("{0} cannot be read", path.getFullPath())); 784 return BooleanValue.FALSE; 785 } 786 787 long time = path.getLastModified(); 788 789 if (time <= 24 * 3600 * 1000L) 790 return BooleanValue.FALSE; 791 else 792 return new LongValue(time / 1000L); 793 } 794 795 800 public static Value fileowner(Env env, Path path) 801 { 802 if (!path.canRead()) { 803 env.warning(L.l("{0} cannot be read", path.getFullPath())); 804 return BooleanValue.FALSE; 805 } 806 807 return new LongValue(path.getOwner()); 808 } 809 810 815 public static Value fileperms(Env env, Path path) 816 { 817 if (!path.canRead()) { 818 env.warning(L.l("{0} cannot be read", path.getFullPath())); 819 return BooleanValue.FALSE; 820 } 821 822 return new LongValue(path.getMode()); 823 } 824 825 830 public static Value filesize(Env env, Path path) 831 { 832 if (! path.exists() || ! path.isFile()) { 833 env.warning(L.l("{0} cannot be read", path.getFullPath())); 834 return BooleanValue.FALSE; 835 } 836 837 long length = path.getLength(); 838 839 if (length < 0) 840 return BooleanValue.FALSE; 841 else 842 return new LongValue(length); 843 } 844 845 850 public static Value filetype(Env env, @NotNull Path path) 851 { 852 if (path == null) 853 return BooleanValue.FALSE; 854 else if (! path.exists()) { 855 env.warning(L.l("{0} cannot be read", path.getFullPath())); 856 return BooleanValue.FALSE; 857 } 858 else if (path.isDirectory()) 859 return new StringValueImpl("dir"); 860 else if (path.isFile()) 861 return new StringValueImpl("file"); 862 else if (path.isFIFO()) 863 return new StringValueImpl("fifo"); 864 else if (path.isLink()) 865 return new StringValueImpl("link"); 866 else if (path.isBlockDevice()) 867 return new StringValueImpl("block"); 868 else if (path.isCharacterDevice()) 869 return new StringValueImpl("char"); 870 else 871 return new StringValueImpl("unknown"); 872 } 873 874 879 public static boolean file_exists(@NotNull Path path) 880 { 881 if (path != null) 882 return path.exists(); 883 else 884 return false; 885 } 886 887 894 @ReturnNullAsFalse 895 public static BinaryValue 896 file_get_contents(Env env, 897 String filename, 898 @Optional boolean useIncludePath, 899 @Optional Value context, 900 @Optional long offset, 901 @Optional("4294967296") long maxLen) 902 { 903 try { 904 BinaryStream s = fopen(env, filename, "r", useIncludePath, context); 905 906 if (! (s instanceof BinaryInput)) 907 return null; 908 909 BinaryInput is = (BinaryInput) s; 910 911 try { 912 BinaryBuilderValue bb = new BinaryBuilderValue(); 913 914 int len; 915 916 do { 917 bb.prepareReadBuffer(); 918 919 len = is.read(bb.getBuffer(), bb.getOffset(), 920 bb.getLength() - bb.getOffset()); 921 922 if (len > 0) 923 bb.setOffset(bb.getOffset() + len); 924 } while (len > 0); 925 926 return bb; 927 } finally { 928 is.close(); 929 } 930 } catch (IOException e) { 931 throw new QuercusModuleException(e); 932 } 933 } 934 935 938 public Value file_put_contents(Env env, 939 String filename, 940 Value data, 941 @Optional int flags, 942 @Optional Value context) 943 { 944 946 BinaryStream s = null; 947 948 try { 949 boolean useIncludePath = (flags & FILE_USE_INCLUDE_PATH) != 0; 950 String mode = (flags & FILE_APPEND) != 0 ? "a" : "w"; 951 952 s = fopen(env, filename, mode, useIncludePath, context); 953 954 if (! (s instanceof BinaryOutput)) 955 return BooleanValue.FALSE; 956 957 if ((flags & LOCK_EX) != 0) { 958 if (s instanceof LockableStream) { 959 if (! flock(env, (LockableStream) s, LOCK_EX, null)) 960 return BooleanValue.FALSE; 961 } else { 962 return BooleanValue.FALSE; 963 } 964 } 965 966 BinaryOutput os = (BinaryOutput) s; 967 968 try { 969 long dataWritten = 0; 970 971 if (data instanceof ArrayValue) { 972 for (Value item : ((ArrayValue) data).values()) { 973 InputStream is = item.toInputStream(); 974 975 dataWritten += os.write(is, Integer.MAX_VALUE); 976 977 is.close(); 978 } 979 } 980 else { 981 InputStream is = data.toInputStream(); 982 983 dataWritten += os.write(is, Integer.MAX_VALUE); 984 985 is.close(); 986 } 987 988 return new LongValue(dataWritten); 989 } finally { 990 os.close(); 991 } 992 } catch (IOException e) { 993 throw new QuercusModuleException(e); 994 } finally { 995 if (s != null && (s instanceof LockableStream) && 996 ((flags & LOCK_EX) != 0)) 997 flock(env, (LockableStream) s, LOCK_UN, null); 998 } 999 } 1000 1001 1008 public static boolean flock(Env env, 1009 LockableStream fileV, 1010 int operation, 1011 @Optional Value wouldBlock) 1012 { 1013 1015 if (fileV == null) { 1016 env.warning(L.l("{0} is null", "handle")); 1017 return false; 1018 } 1019 1020 boolean shared = false; 1021 boolean block = false; 1022 1023 if (operation > LOCK_NB) { 1024 block = true; 1025 operation -= LOCK_NB; 1026 } 1027 1028 switch (operation) { 1029 case LOCK_SH: 1030 shared = true; 1031 break; 1032 case LOCK_EX: 1033 shared = false; 1034 break; 1035 case LOCK_UN: 1036 return fileV.unlock(); 1037 default: 1038 return true; 1040 } 1041 1042 return fileV.lock(shared, block); 1043 } 1044 1045 1046 1049 private static String globToRegex(String pattern, int flags, boolean brace) 1050 { 1051 StringBuilder globRegex = new StringBuilder (); 1052 1053 int bracketCount = 0; 1054 boolean inSquareBrackets = false; 1055 boolean inCurlyBrackets = false; 1056 char lastCh = ' '; 1057 1058 for (int i = 0; i < pattern.length(); i++) { 1059 char ch = pattern.charAt(i); 1060 1061 switch (ch) { 1062 case '*': 1063 if (inSquareBrackets || inCurlyBrackets) { 1064 globRegex.append("*"); 1065 1066 if (inSquareBrackets) 1067 bracketCount++; 1068 } else { 1069 if ((flags & FNM_PATHNAME) != 0) 1070 globRegex.append("[^/]*"); 1071 else 1072 globRegex.append(".*"); 1073 } 1074 1075 break; 1076 1077 case '?': 1078 if (inSquareBrackets || inCurlyBrackets) { 1079 globRegex.append("*"); 1080 1081 if (inSquareBrackets) 1082 bracketCount++; 1083 } else { 1084 if ((flags & FNM_PATHNAME) != 0) 1085 globRegex.append("[^/]"); 1086 else 1087 globRegex.append("."); 1088 } 1089 1090 break; 1091 1092 case '^': 1093 if (lastCh == '[') 1094 globRegex.append(ch); 1095 else { 1096 globRegex.append("\\" + ch); 1097 1098 if (inSquareBrackets) 1099 bracketCount++; 1100 } 1101 1102 break; 1103 1104 case '!': 1105 if (lastCh == '[') 1106 globRegex.append('^'); 1107 else { 1108 globRegex.append(ch); 1109 1110 if (inSquareBrackets) 1111 bracketCount++; 1112 } 1113 1114 break; 1115 1116 case '/': 1117 if (! ((inSquareBrackets || inCurlyBrackets) && 1118 ((flags & FNM_PATHNAME) != 0))) { 1119 globRegex.append(ch); 1120 1121 if (inSquareBrackets) 1122 bracketCount++; 1123 } 1124 1125 break; 1127 1128 case '+': 1129 case '(': 1130 case ')': 1131 case '$': 1132 case '.': 1133 case '|': 1134 globRegex.append('\\'); 1137 globRegex.append(ch); 1138 1139 if (inSquareBrackets) 1140 bracketCount++; 1141 1142 break; 1143 1144 case '\\': 1145 if ((flags & FNM_NOESCAPE) != 0) 1146 globRegex.append('\\'); 1147 1148 globRegex.append(ch); 1149 1150 if (inSquareBrackets) 1151 bracketCount++; 1152 1153 break; 1154 1155 case '[': 1156 inSquareBrackets = true; 1157 1158 globRegex.append(ch); 1159 1160 break; 1161 1162 case ']': 1163 inSquareBrackets = false; 1164 1165 if (bracketCount == 0) 1166 return null; 1167 1168 globRegex.append(ch); 1169 1170 break; 1171 1172 case '{': 1173 if (inSquareBrackets || inCurlyBrackets) { 1174 globRegex.append(ch); 1175 1176 if (inSquareBrackets) 1177 bracketCount++; 1178 } else if (brace) { 1179 globRegex.append('('); 1180 1181 inCurlyBrackets = true; 1182 } else { 1183 globRegex.append('\\'); 1184 globRegex.append(ch); 1185 } 1186 1187 break; 1188 1189 case '}': 1190 if (inSquareBrackets) { 1191 globRegex.append(ch); 1192 1193 bracketCount++; 1194 } else if (brace && inCurlyBrackets) { 1195 globRegex.append(')'); 1196 1197 inCurlyBrackets = false; 1198 } else { 1199 globRegex.append('\\'); 1200 globRegex.append(ch); 1201 } 1202 1203 break; 1204 1205 case ',': 1206 if (brace && inCurlyBrackets) 1207 globRegex.append('|'); 1208 else 1209 globRegex.append(ch); 1210 1211 break; 1212 1213 default: 1214 globRegex.append(ch); 1215 1216 if (inSquareBrackets) 1217 bracketCount++; 1218 1219 break; 1220 } 1221 1222 lastCh = ch; 1223 } 1224 1225 return globRegex.toString(); 1226 } 1227 1228 1231 public static boolean fnmatch(Env env, String pattern, String string, 1232 @Optional int flags) 1233 { 1234 if ((flags & FNM_CASEFOLD) != 0) { 1235 string = string.toLowerCase(); 1236 pattern = pattern.toLowerCase(); 1237 } 1238 1239 if ((flags & FNM_PERIOD) != 0) { 1241 if (string.length() > 0 && string.charAt(0) == '.'){ 1242 if (! (pattern.length() > 0 && pattern.charAt(0) == '.')) 1243 return false; 1244 1245 string = string.substring(1); 1246 pattern = pattern.substring(1); 1247 } else if ((flags & FNM_PATHNAME) != 0) { 1248 if ((string.length() >= 2) && 1251 (string.charAt(0) == '/') && (string.charAt(1) == '.')) { 1252 if (! ((pattern.length() >= 2) && 1253 (pattern.charAt(0) == '/') && (pattern.charAt(1) == '.'))) 1254 return false; 1255 1256 string = string.substring(2); 1257 pattern = pattern.substring(2); 1258 } 1259 } 1260 } 1261 1262 String globRegex = globToRegex(pattern, flags, false); 1263 1264 if (globRegex == null) 1265 return false; 1266 1267 return string.matches(globRegex.toString()); 1268 } 1269 1270 private static ProtocolWrapper getProtocolWrapper(Env env, String pathName) 1271 { 1272 ArrayValue url = (ArrayValue) UrlModule.parse_url(env, pathName); 1273 1274 Value scheme = url.get(new StringValueImpl("scheme")); 1275 1276 if (scheme == UnsetValue.UNSET) 1277 return null; 1278 1279 return StreamModule.getWrapper(scheme.toString()); 1280 } 1281 1282 1289 @ReturnNullAsFalse 1290 public static BinaryStream fopen(Env env, 1291 String filename, 1292 String mode, 1293 @Optional boolean useIncludePath, 1294 @Optional Value context) 1295 { 1296 try { 1298 ProtocolWrapper wrapper = getProtocolWrapper(env, filename); 1299 1300 if (wrapper != null) { 1301 long options = 0; 1302 1303 if (useIncludePath) 1304 options = StreamModule.STREAM_USE_PATH; 1305 1306 return wrapper.fopen(env, new StringValueImpl(filename), 1307 new StringValueImpl(mode), 1308 LongValue.create(options)); 1309 } 1310 1311 Path path; 1312 1313 path = env.getPwd().lookup(filename); 1314 1315 if (mode.startsWith("r")) { 1316 if (useIncludePath) 1317 path = env.lookupInclude(filename); 1318 1319 if (path == null) { 1320 env.warning(L.l("{0} cannot be read", filename)); 1321 1322 return null; 1323 } else if (! path.exists()) { 1324 env.warning(L.l("{0} cannot be read", path.getFullPath())); 1325 1326 return null; 1327 } 1328 1329 try { 1330 BinaryInput input; 1331 1332 if (mode.startsWith("r+")) 1333 input = new FileInputOutput(env, path); 1334 else 1335 input = new FileInput(env, path); 1336 1337 input.setEncoding(env.getRuntimeEncoding().toString()); 1338 1339 return input; 1340 } catch (IOException e) { 1341 log.log(Level.FINE, e.toString(), e); 1342 1343 env.warning(L.l("{0} cannot be read", path.getFullPath())); 1344 1345 return null; 1346 } 1347 } 1348 else if (mode.startsWith("w")) { 1349 try { 1350 if (mode.startsWith("w+")) 1351 return new FileInputOutput(env, path, false, true); 1352 else 1353 return new FileOutput(env, path); 1354 } catch (IOException e) { 1355 log.log(Level.FINE, e.toString(), e); 1356 1357 env.warning(L.l("{0} cannot be written", path.getFullPath())); 1358 1359 return null; 1360 } 1361 } 1362 else if (mode.startsWith("a")) { 1363 try { 1364 if (mode.startsWith("a+")) 1365 return new FileInputOutput(env, path, true, false); 1366 else 1367 return new FileOutput(env, path, true); 1368 } catch (IOException e) { 1369 log.log(Level.FINE, e.toString(), e); 1370 1371 env.warning(L.l("{0} cannot be written", path.getFullPath())); 1372 1373 return null; 1374 } 1375 } 1376 else if (mode.startsWith("x") && ! path.exists()) { 1377 if (mode.startsWith("x+")) 1378 return new FileInputOutput(env, path); 1379 else 1380 return new FileOutput(env, path); 1381 } 1382 1383 env.warning(L.l("bad mode `{0}'", mode)); 1384 1385 return null; 1386 } catch (IOException e) { 1387 log.log(Level.FINE, e.toString(), e); 1388 1389 env.warning(L.l("{0} can't be opened.\n{1}", 1390 filename, e.toString())); 1391 1392 return null; 1393 } 1394 } 1395 1396 1399 public Value fpassthru(Env env, @NotNull BinaryInput is) 1400 { 1401 1403 try { 1404 if (is == null) 1405 return BooleanValue.FALSE; 1406 1407 WriteStream out = env.getOut(); 1408 1409 long writeLength = out.writeStream(is.getInputStream()); 1410 1411 return LongValue.create(writeLength); 1412 } catch (IOException e) { 1413 throw new QuercusModuleException(e); 1414 } 1415 } 1416 1417 1424 public Value fputcsv(Env env, 1425 @NotNull BinaryOutput os, 1426 @NotNull ArrayValue value, 1427 @Optional StringValue delimiter, 1428 @Optional StringValue enclosure) 1429 { 1430 1432 try { 1433 if (os == null) 1434 return BooleanValue.FALSE; 1435 1436 if (value == null) 1437 return BooleanValue.FALSE; 1438 1439 char comma = ','; 1440 char quote = '\"'; 1441 1442 if (delimiter != null && delimiter.length() > 0) 1443 comma = delimiter.charAt(0); 1444 1445 if (enclosure != null && enclosure.length() > 0) 1446 quote = enclosure.charAt(0); 1447 1448 int writeLength = 0; 1449 boolean isFirst = true; 1450 1451 for (Value data : value.values()) { 1452 if (! isFirst) { 1453 os.print(comma); 1454 writeLength++; 1455 } 1456 isFirst = false; 1457 1458 StringValue s = data.toStringValue(); 1459 int strlen = s.length(); 1460 1461 writeLength++; 1462 os.print(quote); 1463 1464 for (int i = 0; i < strlen; i++) { 1465 char ch = s.charAt(i); 1466 1467 if (ch != quote) { 1468 os.print(ch); 1469 writeLength++; 1470 } 1471 else { 1472 os.print(quote); 1473 os.print(quote); 1474 writeLength += 2; 1475 } 1476 } 1477 1478 os.print(quote); 1479 writeLength++; 1480 } 1481 1482 os.print("\n"); 1483 writeLength++; 1484 1485 return LongValue.create(writeLength); 1486 } catch (IOException e) { 1487 throw new QuercusModuleException(e); 1488 } 1489 } 1490 1491 1494 public static Value fputs(Env env, 1495 BinaryOutput os, 1496 InputStream value, 1497 @Optional("0x7fffffff") int length) 1498 { 1499 return fwrite(env, os, value, length); 1500 } 1501 1502 1507 public static Value fread(Env env, 1508 @NotNull BinaryInput is, 1509 int length) 1510 { 1511 try { 1512 if (is == null) 1513 return BooleanValue.FALSE; 1514 1515 if (length < 0) 1516 length = Integer.MAX_VALUE; 1517 1518 1520 TempBuffer tempBuf = TempBuffer.allocate(); 1521 byte []buffer = tempBuf.getBuffer(); 1522 1523 if (buffer.length < length) { 1524 buffer = new byte[length]; 1525 } 1526 1527 length = is.read(buffer, 0, length); 1528 1529 if (length > 0) { 1530 BinaryBuilderValue bb = new BinaryBuilderValue(buffer, 0, length); 1531 TempBuffer.free(tempBuf); 1532 return bb; 1533 } 1534 else { 1535 TempBuffer.free(tempBuf); 1536 return BooleanValue.FALSE; 1537 } 1538 } catch (IOException e) { 1539 throw new QuercusModuleException(e); 1540 } 1541 } 1542 1543 1546 public static Value fscanf(Env env, 1547 @NotNull BinaryInput is, 1548 StringValue format, 1549 @Optional Value []args) 1550 { 1551 try { 1552 if (is == null) 1553 return BooleanValue.FALSE; 1554 1555 StringValue value = is.readLine(Integer.MAX_VALUE); 1556 1557 if (value == null) 1558 return BooleanValue.FALSE; 1559 1560 return StringModule.sscanf(value, format, args); 1561 } catch (IOException e) { 1562 throw new QuercusModuleException(e); 1563 } 1564 } 1565 1566 1571 public static Value fseek(Env env, 1572 @NotNull BinaryInput is, 1573 long offset, @Optional int whence) 1574 { 1575 if (is == null) 1576 return BooleanValue.FALSE; 1577 1578 long position = is.seek(offset, whence); 1579 1580 if (position < 0) 1581 return BooleanValue.FALSE; 1582 else 1583 return LongValue.create(position); 1584 } 1585 1586 1589 public static Value fstat(Env env, @NotNull BinaryStream stream) 1590 { 1591 return stream.stat(); 1592 } 1593 1594 1599 public static Value ftell(Env env, 1600 @NotNull BinaryInput is) 1601 { 1602 if (is == null) 1603 return BooleanValue.FALSE; 1604 1605 return new LongValue(is.getPosition()); 1606 } 1607 1608 1611 public static boolean ftruncate(Env env, 1612 @NotNull BinaryOutput handle, 1613 long size) 1614 { 1615 if (handle instanceof FileOutput) { 1616 Path path = ((FileOutput) handle).getPath(); 1617 1618 try { 1619 return path.truncate(size); 1620 } catch (IOException e) { 1621 return false; 1622 } 1623 } 1624 1625 return false; 1626 } 1627 1628 1631 public static Value fwrite(Env env, 1632 @NotNull BinaryOutput os, 1633 InputStream value, 1634 @Optional("0x7fffffff") int length) 1635 { 1636 try { 1637 if (os == null) 1638 return BooleanValue.FALSE; 1639 1640 return LongValue.create(os.write(value, length)); 1641 } catch (IOException e) { 1642 throw new QuercusModuleException(e); 1643 } 1644 } 1645 1646 private static boolean globImpl(Env env, String pattern, int flags, 1647 Path path, String prefix, ArrayValue result) 1648 { 1649 String cwdPattern; 1650 String subPattern = null; 1651 1652 int firstSlash = pattern.indexOf('/'); 1653 1654 if (firstSlash < 0) 1655 cwdPattern = pattern; 1656 else { 1657 cwdPattern = pattern.substring(0, firstSlash); 1658 1659 for (; firstSlash < pattern.length(); firstSlash++) { 1661 if (pattern.charAt(firstSlash) != '/') 1662 break; 1663 } 1664 1665 subPattern = pattern.substring(firstSlash); 1666 } 1667 1668 int fnmatchFlags = 0; 1669 1670 if ((flags & GLOB_NOESCAPE) != 0) 1671 fnmatchFlags = FNM_NOESCAPE; 1672 1673 boolean doBraces = (flags & GLOB_BRACE) != 0; 1674 1675 String globRegex = globToRegex(cwdPattern, fnmatchFlags, doBraces); 1676 1677 if (globRegex == null) 1678 return false; 1679 1680 Pattern compiledGlobRegex; 1681 1682 try { 1683 compiledGlobRegex = Pattern.compile(globRegex); 1684 } catch (PatternSyntaxException e) { 1685 log.log(Level.FINE, e.toString(), e); 1686 1687 return false; 1688 } 1689 1690 String [] list; 1691 1692 try { 1693 list = path.list(); 1694 } catch (IOException e) { 1695 return false; 1696 } 1697 1698 for (String entry : list) { 1699 Matcher matcher = compiledGlobRegex.matcher(entry); 1700 1701 if (matcher.matches()) { 1702 StringBuilderValue sb = new StringBuilderValue(); 1703 1704 sb.append(prefix); 1705 1706 if (prefix.length() > 0) 1707 sb.append("/"); 1708 1709 sb.append(entry); 1710 1711 Path entryPath = path.lookup(entry); 1712 1713 if (entryPath != null && entryPath.isDirectory()) { 1714 if (firstSlash >= 0 && subPattern.length() > 0) { 1715 globImpl(env, subPattern, flags, entryPath, sb.toString(), result); 1718 } else if ((flags & GLOB_MARK) != 0) { 1719 sb.append("/"); 1720 } 1721 } 1722 1723 if ((firstSlash < 0 || subPattern.length() == 0) && 1724 (((flags & GLOB_ONLYDIR) == 0) || 1725 (((flags & GLOB_ONLYDIR) != 0) && 1726 (entryPath != null && entryPath.isDirectory())))) 1727 result.put(sb); 1728 } 1729 } 1730 1731 if (result.getSize() == 0) 1732 return false; 1733 1734 return true; 1735 } 1736 1737 1740 public static Value glob(Env env, StringValue pattern, @Optional int flags) 1741 { 1742 Path path = env.getPwd(); 1743 1744 String trimmedPattern = pattern.toString(); 1745 1746 if (pattern.length() > 0 && pattern.charAt(0) == '/') { 1747 int i; 1748 1749 for (i = 0; i < pattern.length(); i++) { 1751 if (pattern.charAt(i) != '/') 1752 break; 1753 } 1754 1755 path = path.lookup("/"); 1756 1757 trimmedPattern = pattern.substring(i).toString(); 1758 } 1759 1760 ArrayValue result = new ArrayValueImpl(); 1761 1762 boolean success = globImpl(env, trimmedPattern, flags, path, "", result); 1763 1764 if (! success) { 1765 if ((flags & GLOB_NOCHECK) != 0) { 1766 if (result.getSize() > 0) 1767 result = new ArrayValueImpl(); 1768 1769 result.put(pattern); 1770 1771 return result; 1772 } else 1773 return BooleanValue.FALSE; 1774 } 1775 1776 if ((flags & GLOB_NOSORT) == 0 && result.isArray()) 1777 ((ArrayValue) result).sort(ArrayValue.ValueComparator.CMP, true, true); 1778 1779 return result; 1780 } 1781 1782 1787 public static String getcwd(Env env) 1788 { 1789 return env.getPwd().getNativePath(); 1790 } 1791 1792 1797 public static boolean is_dir(@NotNull Path path) 1798 { 1799 if (path == null) 1800 return false; 1801 1802 return path.isDirectory(); 1803 } 1804 1805 1810 public static boolean is_executable(@NotNull Path path) 1811 { 1812 if (path == null) 1813 return false; 1814 1815 return path.isExecutable(); 1816 } 1817 1818 1823 public static boolean is_file(@NotNull Path path) 1824 { 1825 if (path == null) 1826 return false; 1827 1828 return path.isFile(); 1829 } 1830 1831 1836 public static boolean is_link(Env env, @NotNull Path path) 1837 { 1838 if (path == null) 1839 return false; 1840 1841 return path.isLink(); 1842 } 1843 1844 1849 public static boolean is_readable(Path path) 1850 { 1851 return path.canRead(); 1852 } 1853 1854 1859 public static boolean is_uploaded_file(Env env, String tail) 1860 { 1861 return env.getUploadDirectory().lookup(tail).canRead(); 1862 } 1863 1864 1869 public static boolean is_writable(Path path) 1870 { 1871 if (path == null) 1872 return false; 1873 1874 return path.canWrite(); 1875 } 1876 1877 1882 public static boolean is_writeable(Path path) 1883 { 1884 return is_writable(path); 1885 } 1886 1887 1890 public boolean link(Env env, Path source, Path destination) 1891 { 1892 try { 1893 return destination.createLink(source, true); 1894 } catch (Exception e) { 1895 env.warning(e); 1896 1897 return false; 1898 } 1899 } 1900 1901 public static long linkinfo(Env env, Path path) 1902 { 1903 if (path.isLink()) 1905 return path.getDevice(); 1906 else 1907 return 0; 1908 } 1909 1910 1913 public static Value lstat(Env env, StringValue filename) 1914 { 1915 ProtocolWrapper wrapper = getProtocolWrapper(env, filename.toString()); 1916 1917 if (wrapper != null) 1918 return wrapper.url_stat(env, filename, 1920 LongValue.create(StreamModule.STREAM_URL_STAT_LINK)); 1921 1922 Path path = env.getPwd().lookup(filename.toString()); 1923 1924 path.isLink(); 1926 1927 return statImpl(env, path); 1928 } 1929 1930 1935 public static boolean mkdir(Env env, StringValue dirname, 1936 @Optional int mode, 1937 @Optional boolean recursive, 1938 @Optional Value context) 1939 { 1940 ProtocolWrapper wrapper = getProtocolWrapper(env, dirname.toString()); 1941 1942 if (wrapper != null) 1943 return wrapper.mkdir(env, dirname, 1945 LongValue.create(mode), LongValue.ZERO); 1946 1947 Path path = env.getPwd().lookup(dirname.toString()); 1948 1949 try { 1950 if (recursive) 1951 return path.mkdirs(); 1952 else 1953 return path.mkdir(); 1954 } catch (IOException e) { 1955 log.log(Level.FINE, e.toString(), e); 1956 1957 return false; 1958 } 1959 } 1960 1961 1967 public static boolean move_uploaded_file(Env env, String tail, Path dst) 1968 { 1969 Path src = env.getUploadDirectory().lookup(tail); 1970 1971 try { 1972 if (src.canRead()) { 1973 src.renameTo(dst); 1974 return true; 1975 } 1976 else 1977 return false; 1978 } catch (IOException e) { 1979 env.warning(e); 1980 1981 return false; 1982 } 1983 } 1984 1985 1990 public static Value opendir(Env env, StringValue pathName, 1991 @Optional Value context) 1992 { 1993 ProtocolWrapper wrapper = getProtocolWrapper(env, pathName.toString()); 1994 1995 if (wrapper != null) 1996 return wrapper.opendir(env, pathName, LongValue.ZERO); 1998 1999 try { 2000 Path path = env.getPwd().lookup(pathName.toString()); 2001 2002 if (path.isDirectory()) 2003 return new DirectoryValue(path); 2004 else { 2005 env.warning(L.l("{0} is not a directory", path.getFullPath())); 2006 2007 return BooleanValue.FALSE; 2008 } 2009 } catch (IOException e) { 2010 throw new QuercusModuleException(e); 2011 } 2012 } 2013 2014 2017 public static Value parse_ini_file(Env env, 2018 Path path, 2019 @Optional boolean processSections) 2020 { 2021 ReadStream is = null; 2022 2023 try { 2024 is = path.openRead(); 2025 is.setEncoding(env.getScriptEncoding()); 2026 2027 return parseIni(env, is, processSections); 2028 } catch (IOException e) { 2029 env.warning(e); 2030 2031 return BooleanValue.FALSE; 2032 } finally { 2033 if (is != null) 2034 is.close(); 2035 } 2036 } 2037 2038 private static ArrayValue parseIni(Env env, 2039 ReadStream is, 2040 boolean processSections) 2041 throws IOException  2042 { 2043 ArrayValue top = new ArrayValueImpl(); 2044 ArrayValue section = top; 2045 2046 int ch; 2047 2048 while ((ch = is.read()) >= 0) { 2049 if (Character.isWhitespace(ch)) { 2050 } 2051 else if (ch == ';') { 2052 for (; ch >= 0 && ch != '\r' && ch != '\n'; ch = is.read()) { 2053 } 2054 } 2055 else if (ch == '[') { 2056 StringBuilder sb = new StringBuilder (); 2057 2058 for (ch = is.read(); ch >= 0 && ch != ']'; ch = is.read()) { 2059 sb.append((char) ch); 2060 } 2061 2062 String name = sb.toString().trim(); 2063 2064 if (processSections) { 2065 section = new ArrayValueImpl(); 2066 top.put(new StringValueImpl(name), section); 2067 } 2068 } 2069 else if (isValidIniKeyChar((char) ch)) { 2070 StringBuilder sb = new StringBuilder (); 2071 2072 for (; isValidIniKeyChar((char) ch); ch = is.read()) { 2073 sb.append((char) ch); 2074 } 2075 2076 String key = sb.toString().trim(); 2077 2078 for (; ch >= 0 && ch != '='; ch = is.read()) { 2079 } 2080 2081 for (ch = is.read(); ch == ' ' || ch == '\t'; ch = is.read()) { 2082 } 2083 2084 Value value = parseIniValue(env, ch, is); 2085 2086 section.put(new StringValueImpl(key), value); 2087 } 2088 } 2089 2090 return top; 2091 } 2092 2093 private static Value parseIniValue(Env env, int ch, ReadStream is) 2094 throws IOException  2095 { 2096 if (ch == '\r' || ch == '\n') 2097 return NullValue.NULL; 2098 2099 if (ch == '"') { 2100 StringBuilder sb = new StringBuilder (); 2101 2102 for (ch = is.read(); ch >= 0 && ch != '"'; ch = is.read()) { 2103 sb.append((char) ch); 2104 } 2105 2106 skipToEndOfLine(ch, is); 2107 2108 return new StringValueImpl(sb.toString()); 2109 } 2110 else if (ch == '\'') { 2111 StringBuilder sb = new StringBuilder (); 2112 2113 for (ch = is.read(); ch >= 0 && ch != '\''; ch = is.read()) { 2114 sb.append((char) ch); 2115 } 2116 2117 skipToEndOfLine(ch, is); 2118 2119 return new StringValueImpl(sb.toString()); 2120 } 2121 else { 2122 StringBuilder sb = new StringBuilder (); 2123 2124 for (; ch >= 0 && ch != '\r' && ch != '\n'; ch = is.read()) { 2125 sb.append((char) ch); 2126 } 2127 2128 String value = sb.toString().trim(); 2129 2130 if (value.equalsIgnoreCase("null")) 2131 return StringValue.EMPTY; 2132 else if (value.equalsIgnoreCase("true") || 2133 value.equalsIgnoreCase("yes")) 2134 return new StringValueImpl("1"); 2135 else if (value.equalsIgnoreCase("false") || 2136 value.equalsIgnoreCase("no")) 2137 return StringValue.EMPTY; 2138 2139 if (env.isDefined(value)) 2140 return new StringValueImpl(env.getConstant(value).toString()); 2141 else 2142 return new StringValueImpl(value); 2143 } 2144 } 2145 2146 private static boolean isValidIniKeyChar(char ch) 2147 { 2148 if (ch <= 0 || 2149 ch == '=' || 2150 ch == ';' || 2151 ch == '{' || 2152 ch == '}' || 2153 ch == '|' || 2154 ch == '&' || 2155 ch == '~' || 2156 ch == '!' || 2157 ch == '[' || 2158 ch == '(' || 2159 ch == ')' || 2160 ch == '"') 2161 return false; 2162 else 2163 return true; 2164 } 2165 2166 2167 private static void skipToEndOfLine(int ch, ReadStream is) 2168 throws IOException  2169 { 2170 for (; ch > 0 && ch != '\r' && ch != '\n'; ch = is.read()) { 2171 } 2172 } 2173 2174 2177 public static Value pathinfo(String path) 2178 { 2179 int p = path.lastIndexOf('/'); 2180 2181 String dirname; 2182 if (p >= 0) { 2183 dirname = path.substring(0, p); 2184 path = path.substring(p + 1); 2185 } 2186 else { 2187 dirname = ""; 2188 } 2189 2190 p = path.indexOf('.'); 2191 String ext = ""; 2192 if (p > 0) 2193 ext = path.substring(p + 1); 2194 2195 ArrayValueImpl value = new ArrayValueImpl(); 2196 2197 value.put("dirname", dirname); 2198 value.put("basename", path); 2199 value.put("extension", ext); 2200 2201 return value; 2202 } 2203 2204 public static int pclose(Env env, @NotNull BinaryStream stream) 2205 { 2206 if (stream instanceof PopenInput) 2207 return ((PopenInput) stream).pclose(); 2208 else if (stream instanceof PopenOutput) 2209 return ((PopenOutput) stream).pclose(); 2210 else { 2211 env.warning(L.l("{0} was not returned by popen()", stream)); 2212 2213 return -1; 2214 } 2215 } 2216 2217 @ReturnNullAsFalse 2218 public static BinaryStream popen(Env env, 2219 @NotNull String command, 2220 @NotNull StringValue mode) 2221 { 2222 boolean doRead = false; 2223 2224 if (mode.toString().equalsIgnoreCase("r")) 2225 doRead = true; 2226 else if (mode.toString().equalsIgnoreCase("w")) 2227 doRead = false; 2228 else 2229 return null; 2230 2231 String []args = new String [3]; 2232 2233 try { 2234 args[0] = "sh"; 2235 args[1] = "-c"; 2236 args[2] = command; 2237 2238 Process process = Runtime.getRuntime().exec(args); 2239 2240 if (doRead) 2241 return new PopenInput(env, process); 2242 else 2243 return new PopenOutput(env, process); 2244 } catch (Exception e) { 2245 env.warning(e.getMessage(), e); 2246 2247 return null; 2248 } 2249 } 2250 2251 2256 public static Value readdir(Env env, @NotNull DirectoryValue dir) 2257 { 2258 return dir.readdir(); 2259 } 2260 2261 2264 public Value readfile(Env env, 2265 String filename, 2266 @Optional boolean useIncludePath, 2267 @Optional Value context) 2268 { 2269 BinaryStream s = fopen(env, filename, "r", useIncludePath, context); 2270 2271 if (! (s instanceof BinaryInput)) 2272 return BooleanValue.FALSE; 2273 2274 BinaryInput is = (BinaryInput) s; 2275 2276 try { 2277 return fpassthru(env, is); 2278 } finally { 2279 is.close(); 2280 } 2281 } 2282 2283 2286 public static boolean readlink(Env env, String path) 2287 { 2288 env.stub("readlink(" + path + ")"); 2289 2290 return false; 2291 } 2292 2293 2296 public static String realpath(Path path) 2297 { 2298 String fullPath = path.getFullPath(); 2299 2300 if (fullPath.endsWith("/") && ! fullPath.equals("/")) 2301 return fullPath.substring(0, fullPath.length() - 1); 2302 else 2303 return fullPath; 2304 } 2305 2306 2312 public static boolean rename(Env env, StringValue from, StringValue to) 2313 { 2314 ProtocolWrapper wrapper = getProtocolWrapper(env, from.toString()); 2315 2316 if (wrapper != null) 2317 return wrapper.rename(env, from, to); 2318 2319 Path fromPath = env.getPwd().lookup(from.toString()); 2320 Path toPath = env.getPwd().lookup(to.toString()); 2321 2322 if (!fromPath.canRead()) { 2323 env.warning(L.l("{0} cannot be read", fromPath.getFullPath())); 2324 return false; 2325 } 2326 2327 try { 2328 return fromPath.renameTo(toPath); 2329 } catch (IOException e) { 2330 log.log(Level.FINE, e.toString(), e); 2331 2332 return false; 2333 } 2334 } 2335 2336 2341 public static Value rewind(Env env, 2342 @NotNull BinaryInput is) 2343 { 2344 if (is == null) 2345 return BooleanValue.FALSE; 2346 2347 fseek(env, is, 0, BinaryInput.SEEK_SET); 2348 2349 return BooleanValue.TRUE; 2350 } 2351 2352 2357 public static void rewinddir(Env env, @NotNull DirectoryValue dir) 2358 { 2359 dir.rewinddir(); 2360 } 2361 2362 2365 public static boolean rmdir(Env env, 2366 StringValue filename, 2367 @Optional Value context) 2368 { 2369 ProtocolWrapper wrapper = getProtocolWrapper(env, filename.toString()); 2370 2371 if (wrapper != null) 2372 return wrapper.rmdir(env, filename, LongValue.ZERO); 2374 2375 2377 try { 2379 Path path = env.getPwd().lookup(filename.toString()); 2380 2381 if (!path.isDirectory()) { 2382 env.warning(L.l("{0} is not a directory", path.getFullPath())); 2383 return false; 2384 } 2385 2386 return path.remove(); 2387 } catch (IOException e) { 2388 log.log(Level.FINE, e.toString(), e); 2389 2390 return false; 2391 } 2392 } 2393 2394 2399 public static void closedir(Env env, @NotNull DirectoryValue dirV) 2400 { 2401 dirV.close(); 2402 } 2403 2404 2409 public static Value scandir(Env env, String fileName, 2410 @Optional("1") int order, 2411 @Optional Value context) 2412 { 2413 try { 2414 Path path = env.getPwd().lookup(fileName); 2415 2416 if (!path.isDirectory()) { 2417 env.warning(L.l("{0} is not a directory", path.getFullPath())); 2418 return BooleanValue.FALSE; 2419 } 2420 2421 String []values = path.list(); 2422 2423 Arrays.sort(values); 2424 2425 ArrayValue result = new ArrayValueImpl(); 2426 2427 if (order == 1) { 2428 for (int i = 0; i < values.length; i++) 2429 result.append(new LongValue(i), new StringValueImpl(values[i])); 2430 } 2431 else { 2432 for (int i = values.length - 1; i >= 0; i--) { 2433 result.append(new LongValue(values.length - i - 1), 2434 new StringValueImpl(values[i])); 2435 } 2436 } 2437 2438 return result; 2439 } catch (IOException e) { 2440 throw new QuercusModuleException(e); 2441 } 2442 } 2443 2444 2447 public static int set_file_buffer(Env env, BinaryOutput stream, 2448 int bufferSize) 2449 { 2450 return StreamModule.stream_set_write_buffer(env, stream, bufferSize); 2451 } 2452 2453 2456 public static Value stat(Env env, StringValue filename) 2457 { 2458 ProtocolWrapper wrapper = getProtocolWrapper(env, filename.toString()); 2459 2460 if (wrapper != null) 2461 return wrapper.url_stat(env, filename, LongValue.ZERO); 2463 2464 Path path = env.getPwd().lookup(filename.toString()); 2465 2466 return statImpl(env, path); 2467 } 2468 2469 static Value statImpl(Env env, Path path) 2470 { 2471 if (! path.exists()) { 2472 env.warning(L.l("stat failed for {0}", path.getFullPath().toString())); 2473 return BooleanValue.FALSE; 2474 } 2475 2476 ArrayValue result = new ArrayValueImpl(); 2477 2478 result.put(path.getDevice()); 2479 result.put(path.getInode()); 2480 result.put(path.getMode()); 2481 result.put(path.getNumberOfLinks()); 2482 result.put(path.getUser()); 2483 result.put(path.getGroup()); 2484 result.put(path.getDeviceId()); 2485 result.put(path.getLength()); 2486 2487 result.put(path.getLastAccessTime() / 1000L); 2488 result.put(path.getLastModified() / 1000L); 2489 result.put(path.getLastStatusChangeTime() / 1000L); 2490 result.put(path.getBlockSize()); 2491 result.put(path.getBlockCount()); 2492 2493 result.put("dev", path.getDevice()); 2494 result.put("ino", path.getInode()); 2495 2496 result.put("mode", path.getMode()); 2497 result.put("nlink", path.getNumberOfLinks()); 2498 result.put("uid", path.getUser()); 2499 result.put("gid", path.getGroup()); 2500 result.put("rdev", path.getDeviceId()); 2501 2502 result.put("size", path.getLength()); 2503 2504 result.put("atime", path.getLastAccessTime() / 1000L); 2505 result.put("mtime", path.getLastModified() / 1000L); 2506 result.put("ctime", path.getLastStatusChangeTime() / 1000L); 2507 result.put("blksize", path.getBlockSize()); 2508 result.put("blocks", path.getBlockCount()); 2509 2510 return result; 2511 } 2512 2513 2516 public boolean symlink(Env env, Path source, Path destination) 2517 { 2518 try { 2519 return destination.createLink(source, false); 2520 } catch (Exception e) { 2521 env.warning(e); 2522 2523 return false; 2524 } 2525 } 2526 2527 2530 public static Value tempnam(Env env, Path dir, String prefix) 2531 { 2532 2534 if (!dir.isDirectory()) { 2535 env.warning(L.l("{0} is not a directory", dir.getFullPath())); 2536 return BooleanValue.FALSE; 2537 } 2538 2539 try { 2540 Path path = dir.createTempFile(prefix, ".tmp"); 2541 return new StringValueImpl(path.getTail()); 2542 } catch (IOException e) { 2543 log.log(Level.FINE, e.toString(), e); 2544 2545 return BooleanValue.FALSE; 2546 } 2547 } 2548 2549 2552 @ReturnNullAsFalse 2553 public static FileInputOutput tmpfile(Env env) 2554 { 2555 try { 2556 2558 Path tmp = env.getPwd().lookup("file:/tmp"); 2559 2560 tmp.mkdirs(); 2561 2562 Path file = tmp.createTempFile("resin", "tmp"); 2563 2564 return new FileInputOutput(env, file, false, false, true); 2565 } catch (IOException e) { 2566 log.log(Level.FINE, e.toString(), e); 2567 2568 return null; 2569 } 2570 } 2571 2572 2575 public static boolean touch(Path path, 2576 @Optional int time, 2577 @Optional int atime) 2578 { 2579 2581 try { 2582 if (path.exists()) { 2583 if (time > 0) 2584 path.setLastModified(1000L * time); 2585 else 2586 path.setLastModified(Alarm.getCurrentTime()); 2587 } 2588 else { 2589 WriteStream ws = path.openWrite(); 2590 ws.close(); 2591 } 2592 2593 return true; 2594 } catch (IOException e) { 2595 log.log(Level.FINE, e.toString(), e); 2596 2597 return false; 2598 } 2599 } 2600 2601 2604 public static int umask(Env env, int mask) 2605 { 2606 env.stub("umask(" + mask + ")"); 2607 2608 return mask; 2609 } 2610 2611 2614 public static boolean unlink(Env env, 2615 StringValue filename, 2616 @Optional Value context) 2617 { 2618 2620 try { 2622 ProtocolWrapper wrapper = getProtocolWrapper(env, filename.toString()); 2623 2624 if (wrapper != null) 2625 return wrapper.unlink(env, filename); 2626 2627 Path path = env.getPwd().lookup(filename.toString()); 2628 2629 return path.remove(); 2630 } catch (IOException e) { 2631 log.log(Level.FINE, e.toString(), e); 2632 2633 return false; 2634 } 2635 } 2636 2637 static { 2638 ProtocolWrapper zlibProtocolWrapper = new ZlibProtocolWrapper(); 2639 StreamModule.stream_wrapper_register(new StringValueImpl("compress.zlib"), 2640 zlibProtocolWrapper); 2641 StreamModule.stream_wrapper_register(new StringValueImpl("zlib"), 2642 zlibProtocolWrapper); 2643 StreamModule.stream_wrapper_register(new StringValueImpl("php"), 2644 new PhpProtocolWrapper()); 2645 2646 _constMap.put("SEEK_SET", LongValue.create(BinaryInput.SEEK_SET)); 2647 _constMap.put("SEEK_CUR", LongValue.create(BinaryInput.SEEK_CUR)); 2648 _constMap.put("SEEK_END", LongValue.create(BinaryInput.SEEK_END)); 2649 2650 _constMap.put("LOCK_SH", LongValue.create(LOCK_SH)); 2651 _constMap.put("LOCK_EX", LongValue.create(LOCK_EX)); 2652 _constMap.put("LOCK_UN", LongValue.create(LOCK_UN)); 2653 _constMap.put("LOCK_NB", LongValue.create(LOCK_NB)); 2654 2655 _constMap.put("FNM_PATHNAME", LongValue.create(FNM_PATHNAME)); 2656 _constMap.put("FNM_NOESCAPE", LongValue.create(FNM_NOESCAPE)); 2657 _constMap.put("FNM_PERIOD", LongValue.create(FNM_PERIOD)); 2658 _constMap.put("FNM_CASEFOLD", LongValue.create(FNM_CASEFOLD)); 2659 2660 _constMap.put("GLOB_MARK", LongValue.create(GLOB_MARK)); 2661 _constMap.put("GLOB_NOSORT", LongValue.create(GLOB_NOSORT)); 2662 _constMap.put("GLOB_NOCHECK", LongValue.create(GLOB_NOCHECK)); 2663 _constMap.put("GLOB_NOESCAPE", LongValue.create(GLOB_NOESCAPE)); 2664 _constMap.put("GLOB_BRACE", LongValue.create(GLOB_BRACE)); 2665 _constMap.put("GLOB_ONLYDIR", LongValue.create(GLOB_ONLYDIR)); 2666 2667 addIni(_iniMap, "allow_url_fopen", "1", PHP_INI_SYSTEM); 2668 addIni(_iniMap, "user_agent", null, PHP_INI_ALL); 2669 addIni(_iniMap, "default_socket_timeout", "60", PHP_INI_ALL); 2670 addIni(_iniMap, "from", "", PHP_INI_ALL); 2671 addIni(_iniMap, "auto_detect_line_endings", "0", PHP_INI_ALL); 2672 } 2673} 2674 2675 | Popular Tags |