KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > quercus > lib > file > FileModule


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

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 JavaDoc;
48 import java.io.InputStream JavaDoc;
49 import java.util.Arrays JavaDoc;
50 import java.util.HashMap JavaDoc;
51 import java.util.Map JavaDoc;
52 import java.util.logging.Level JavaDoc;
53 import java.util.logging.Logger JavaDoc;
54 import java.util.regex.Matcher JavaDoc;
55 import java.util.regex.Pattern JavaDoc;
56 import java.util.regex.PatternSyntaxException JavaDoc;
57
58 /**
59  * Information and actions for about files
60  */

61 public class FileModule extends AbstractQuercusModule {
62   private static final L10N L = new L10N(FileModule.class);
63   private static final Logger JavaDoc log
64     = Logger.getLogger(FileModule.class.getName());
65
66   public static final String JavaDoc DIRECTORY_SEPARATOR = "/";
67   public static final String JavaDoc 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 JavaDoc<String JavaDoc,StringValue> _iniMap
96     = new HashMap JavaDoc<String JavaDoc,StringValue>();
97
98   private static final HashMap JavaDoc<String JavaDoc,Value> _constMap
99     = new HashMap JavaDoc<String JavaDoc,Value>();
100
101   /**
102    * Returns the default quercus.ini values.
103    */

104   public Map JavaDoc<String JavaDoc,StringValue> getDefaultIni()
105   {
106     return _iniMap;
107   }
108   
109   /**
110    * Returns the constants defined by this module.
111    */

112   public Map JavaDoc<String JavaDoc,Value> getConstMap()
113   {
114     return _constMap;
115   }
116   
117   /**
118    * Returns the base name of a string.
119    */

120   public static String JavaDoc basename(String JavaDoc path, @Optional String JavaDoc 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 JavaDoc 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   /**
150    * Changes the working directory
151    *
152    * @param path the path to change to
153    */

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   /**
168    * Changes the working directory, forming a virtual root
169    *
170    * @param path the path to change to
171    */

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   /**
187    * Changes the group of the file.
188    *
189    * @param env the PHP executing environment
190    * @param file the file to change the group of
191    * @param group the group id to change to
192    */

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     // quercus/160i
202

203     try {
204       // XXX: safe_mode
205

206       if (group instanceof LongValue)
207         file.changeGroup(group.toInt());
208       else
209         file.changeGroup(group.toString());
210
211       return true;
212     } catch (IOException JavaDoc e) {
213       log.log(Level.FINE, e.toString(), e);
214
215       return false;
216     }
217   }
218
219   /**
220    * Changes the permissions of the file.
221    *
222    * @param env the PHP executing environment
223    * @param file the file to change the group of
224    * @param mode the mode id to change to
225    */

226   public static boolean chmod(Env env, Path file, int mode)
227   {
228     if (! file.canRead()) {
229       // XXX: gallery?
230
env.warning(L.l("{0} cannot be read", file.getFullPath()));
231
232       return false;
233     }
234
235     // quercus/160j
236
file.chmod(mode);
237
238     return true;
239   }
240
241   /**
242    * Changes the ownership of the file.
243    *
244    * @param env the PHP executing environment
245    * @param file the file to change the group of
246    * @param user the user id to change to
247    */

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       // XXX: safe_mode
258

259       if (user instanceof LongValue)
260         file.changeOwner(user.toInt());
261       else
262         file.changeOwner(user.toString());
263
264       return true;
265     } catch (IOException JavaDoc e) {
266       log.log(Level.FINE, e.toString(), e);
267
268       return false;
269     }
270   }
271
272   /**
273    * Clears the stat cache for the file
274    *
275    * @param env the PHP executing environment
276    */

277   public static Value clearstatcache(Env env)
278   {
279     // quercus/160l
280

281     // XXX: stubbed
282

283     return NullValue.NULL;
284   }
285
286   /**
287    * Copies a file to the destination.
288    *
289    * @param src the source path
290    * @param dst the destination path
291    */

292   public static boolean copy(Env env, Path src, Path dst)
293   {
294     // quercus/1603
295

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 JavaDoc e) {
313       log.log(Level.FINE, e.toString(), e);
314
315       return false;
316     }
317   }
318
319   /**
320    * Opens a directory
321    *
322    * @param path the path to change to
323    */

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 /*
337       DirectoryValue dir = new DirectoryValue(path);
338
339       env.addClose(dir);
340
341       return dir;
342 */

343     } catch (IOException JavaDoc e) {
344       throw new QuercusModuleException(e);
345     }
346   }
347
348   /**
349    * Returns the directory name of a string.
350    */

351   public String JavaDoc dirname(String JavaDoc path)
352   {
353     // quercus/1601
354

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   /**
380    * Returns the free space for disk partition containing the directory
381    *
382    * @param directory the disk directory
383    */

384   public static Value disk_free_space(Env env, Path directory)
385   {
386     // quercus/160m
387

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   /**
398    * Returns the total space for disk partition containing the directory
399    *
400    * @param directory the disk directory
401    */

402   public static Value disk_total_space(Env env, Path directory)
403   {
404     // quercus/160n
405

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   /**
416    * Returns the total space for disk partition containing the directory
417    *
418    * @param directory the disk directory
419    */

420   public static Value diskfreespace(Env env, Path directory)
421   {
422     return disk_free_space(env, directory);
423   }
424
425   /**
426    * Closes a file.
427    */

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   /**
439    * Checks for the end of file.
440    */

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   /**
450    * Flushes a file.
451    */

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 JavaDoc e) {
462       return false;
463     }
464   }
465
466   /**
467    * Returns the next character as a boolean
468    */

469   public static Value fgetc(Env env, @NotNull BinaryInput is)
470   {
471     try {
472       if (is == null)
473     return BooleanValue.FALSE;
474
475       // php/1612
476
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 JavaDoc e) {
483       throw new QuercusModuleException(e);
484     }
485   }
486
487   /**
488    * Parses a comma-separated-value line from a file.
489    *
490    * @param file the file to read
491    * @param length the maximum line length
492    * @param delimiter optional comma replacement
493    * @param enclosure optional quote replacement
494    */

495   public Value fgetcsv(Env env,
496                        @NotNull BinaryInput is,
497                        @Optional int length,
498                        @Optional String JavaDoc delimiter,
499                        @Optional String JavaDoc enclosure)
500   {
501     // php/1619
502

503     try {
504       if (is == null)
505     return BooleanValue.FALSE;
506
507       // XXX: length is never used
508
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     // scan whitespace
527
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 JavaDoc e) {
588       throw new QuercusModuleException(e);
589     }
590   }
591
592   /**
593    * Returns the next line
594    */

595   public static Value fgets(Env env,
596                 @NotNull BinaryInput is,
597                 @Optional("0x7fffffff") int length)
598   {
599     // php/1615
600

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 JavaDoc e) {
612       throw new QuercusModuleException(e);
613     }
614   }
615
616   /**
617    * Returns the next line stripping tags
618    */

619   public static Value fgetss(Env env,
620                  BinaryInput is,
621                  @Optional("0x7fffffff") int length,
622                  @Optional String JavaDoc allowedTags)
623   {
624     // php/161a
625

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 JavaDoc e) {
639       throw new QuercusModuleException(e);
640     }
641   }
642
643   /**
644    * Parses the file, returning it in an array. Binary-safe.
645    *
646    * @param filename the file's name
647    * @param useIncludePath if 1, use the include path
648    * @param context the resource context
649    */

650   public static Value file(Env env,
651                            String JavaDoc 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 JavaDoc e) {
701       throw new QuercusModuleException(e);
702     }
703   }
704
705   /**
706    * Returns the file access time
707    *
708    * @param path the path to check
709    */

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   /**
726    * Returns the file create time
727    *
728    * @param path the path to check
729    */

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   /**
746    * Returns the file's group
747    *
748    * @param path the path to check
749    */

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   /**
761    * Returns the file's inocde
762    *
763    * @param path the path to check
764    */

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   /**
776    * Returns the file modified time
777    *
778    * @param path the path to check
779    */

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   /**
796    * Returns the file's owner
797    *
798    * @param path the path to check
799    */

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   /**
811    * Returns the file's permissions
812    *
813    * @param path the path to check
814    */

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   /**
826    * Returns the file's size
827    *
828    * @param path the path to check
829    */

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   /**
846    * Returns the file's type
847    *
848    * @param path the path to check
849    */

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   /**
875    * Returns true if file exists
876    *
877    * @param path the path to check
878    */

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   /**
888    * Parses the file, returning it in an array.
889    *
890    * @param filename the file's name
891    * @param useIncludePath if true, use the include path
892    * @param context the resource context
893    */

894   @ReturnNullAsFalse
895   public static BinaryValue
896     file_get_contents(Env env,
897               String JavaDoc 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 JavaDoc e) {
931       throw new QuercusModuleException(e);
932     }
933   }
934
935   /**
936    * Writes data to a file.
937    */

938   public Value file_put_contents(Env env,
939                                  String JavaDoc filename,
940                                  Value data,
941                                  @Optional int flags,
942                                  @Optional Value context)
943   {
944     // php/1634
945

946     BinaryStream s = null;
947
948     try {
949       boolean useIncludePath = (flags & FILE_USE_INCLUDE_PATH) != 0;
950       String JavaDoc 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 JavaDoc is = item.toInputStream();
974
975             dataWritten += os.write(is, Integer.MAX_VALUE);
976
977             is.close();
978           }
979         }
980         else {
981           InputStream JavaDoc 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 JavaDoc 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  /**
1002   * Advisory locking
1003   *
1004   * @param fileV the file handle
1005   * @param operation the locking operation
1006   * @param wouldBlock the resource context
1007   */

1008  public static boolean flock(Env env,
1009                              LockableStream fileV,
1010                              int operation,
1011                              @Optional Value wouldBlock)
1012  {
1013    // XXX: also wouldblock is a ref
1014

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        // This is PHP's behavior...
1039
return true;
1040    }
1041
1042    return fileV.lock(shared, block);
1043  }
1044
1045
1046  /**
1047   * Converts a glob pattern to a regular expression.
1048   */

1049  private static String JavaDoc globToRegex(String JavaDoc pattern, int flags, boolean brace)
1050  {
1051    StringBuilder JavaDoc globRegex = new StringBuilder JavaDoc();
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          // don't include '/' in the brackets when FNM_PATHNAME is specified
1126
break;
1127
1128        case '+':
1129        case '(':
1130        case ')':
1131        case '$':
1132        case '.':
1133        case '|':
1134          // escape regex special characters that are not glob
1135
// special characters
1136
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  /**
1229   * Returns true if the given string matches the given glob pattern.
1230   */

1231  public static boolean fnmatch(Env env, String JavaDoc pattern, String JavaDoc string,
1232                                @Optional int flags)
1233  {
1234    if ((flags & FNM_CASEFOLD) != 0) {
1235      string = string.toLowerCase();
1236      pattern = pattern.toLowerCase();
1237    }
1238
1239    // match "leading" periods exactly (i.e. no wildcards)
1240
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        // special case: if the string starts with '/.', then the pattern
1249
// must also start with exactly that.
1250
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 JavaDoc 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 JavaDoc 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  /**
1283   * Opens a file.
1284   *
1285   * @param filename the path to the file to open
1286   * @param mode the mode the file should be opened as.
1287   * @param useIncludePath if true, search the current include path
1288   */

1289  @ReturnNullAsFalse
1290  public static BinaryStream fopen(Env env,
1291                   String JavaDoc filename,
1292                   String JavaDoc mode,
1293                   @Optional boolean useIncludePath,
1294                   @Optional Value context)
1295  {
1296    // XXX: context
1297
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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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  /**
1397   * Output the filepointer data to the output stream.
1398   */

1399  public Value fpassthru(Env env, @NotNull BinaryInput is)
1400  {
1401    // php/1635
1402

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 JavaDoc e) {
1413      throw new QuercusModuleException(e);
1414    }
1415  }
1416
1417  /**
1418   * Parses a comma-separated-value line from a file.
1419   *
1420   * @param file the file to read
1421   * @param delimiter optional comma replacement
1422   * @param enclosure optional quote replacement
1423   */

1424  public Value fputcsv(Env env,
1425                       @NotNull BinaryOutput os,
1426                       @NotNull ArrayValue value,
1427                       @Optional StringValue delimiter,
1428                       @Optional StringValue enclosure)
1429  {
1430    // php/1636
1431

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 JavaDoc e) {
1487      throw new QuercusModuleException(e);
1488    }
1489  }
1490
1491  /**
1492   * Writes a string to the file.
1493   */

1494  public static Value fputs(Env env,
1495                BinaryOutput os,
1496                InputStream JavaDoc value,
1497                @Optional("0x7fffffff") int length)
1498  {
1499    return fwrite(env, os, value, length);
1500  }
1501
1502  /**
1503   * Reads content from a file.
1504   *
1505   * @param is the file
1506   */

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      // XXX: should use the buffer directly (?)
1519

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 JavaDoc e) {
1539      throw new QuercusModuleException(e);
1540    }
1541  }
1542
1543  /**
1544   * Reads and parses a line.
1545   */

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 JavaDoc e) {
1562      throw new QuercusModuleException(e);
1563    }
1564  }
1565
1566  /**
1567   * Sets the current position.
1568   *
1569   * @param is the stream to test
1570   */

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  /**
1587   * Returns the status of the given file pointer.
1588   */

1589  public static Value fstat(Env env, @NotNull BinaryStream stream)
1590  {
1591    return stream.stat();
1592  }
1593
1594  /**
1595   * Returns the current position.
1596   *
1597   * @param file the stream to test
1598   */

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  /**
1609   * Truncates a file.
1610   */

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 JavaDoc e) {
1621        return false;
1622      }
1623    }
1624
1625    return false;
1626  }
1627
1628  /**
1629   * Writes a string to the file.
1630   */

1631  public static Value fwrite(Env env,
1632                 @NotNull BinaryOutput os,
1633                 InputStream JavaDoc 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 JavaDoc e) {
1642      throw new QuercusModuleException(e);
1643    }
1644  }
1645
1646  private static boolean globImpl(Env env, String JavaDoc pattern, int flags,
1647                                  Path path, String JavaDoc prefix, ArrayValue result)
1648  {
1649    String JavaDoc cwdPattern;
1650    String JavaDoc 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      // strip off any extra slashes
1660
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 JavaDoc globRegex = globToRegex(cwdPattern, fnmatchFlags, doBraces);
1676
1677    if (globRegex == null)
1678      return false;
1679
1680    Pattern JavaDoc compiledGlobRegex;
1681
1682    try {
1683      compiledGlobRegex = Pattern.compile(globRegex);
1684    } catch (PatternSyntaxException JavaDoc e) {
1685      log.log(Level.FINE, e.toString(), e);
1686
1687      return false;
1688    }
1689
1690    String JavaDoc [] list;
1691
1692    try {
1693      list = path.list();
1694    } catch (IOException JavaDoc e) {
1695      return false;
1696    }
1697
1698    for (String JavaDoc entry : list) {
1699      Matcher JavaDoc 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            // ArrayValue.add only adds values when the argument is an
1716
// actual array
1717
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  /**
1738   * Matches all files with the given pattern.
1739   */

1740  public static Value glob(Env env, StringValue pattern, @Optional int flags)
1741  {
1742    Path path = env.getPwd();
1743
1744    String JavaDoc trimmedPattern = pattern.toString();
1745
1746    if (pattern.length() > 0 && pattern.charAt(0) == '/') {
1747      int i;
1748
1749      // strip off any leading slashes
1750
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  /**
1783   * Returns the current working directory.
1784   *
1785   * @return the current directory
1786   */

1787  public static String JavaDoc getcwd(Env env)
1788  {
1789    return env.getPwd().getNativePath();
1790  }
1791
1792  /**
1793   * Returns true if the path is a directory.
1794   *
1795   * @param path the path to check
1796   */

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  /**
1806   * Returns true if the path is an executable file
1807   *
1808   * @param path the path to check
1809   */

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  /**
1819   * Returns true if the path is a file.
1820   *
1821   * @param path the path to check
1822   */

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  /**
1832   * Returns true if the path is a symbolic link
1833   *
1834   * @param path the path to check
1835   */

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  /**
1845   * Returns true if the path is readable
1846   *
1847   * @param path the path to check
1848   */

1849  public static boolean is_readable(Path path)
1850  {
1851    return path.canRead();
1852  }
1853
1854  /**
1855   * Returns true for an uploaded file.
1856   *
1857   * @param tail the temp name of the uploaded file
1858   */

1859  public static boolean is_uploaded_file(Env env, String JavaDoc tail)
1860  {
1861    return env.getUploadDirectory().lookup(tail).canRead();
1862  }
1863
1864  /**
1865   * Returns true if the path is writable
1866   *
1867   * @param path the path to check
1868   */

1869  public static boolean is_writable(Path path)
1870  {
1871    if (path == null)
1872      return false;
1873
1874    return path.canWrite();
1875  }
1876
1877  /**
1878   * Returns true if the path is writable
1879   *
1880   * @param path the path to check
1881   */

1882  public static boolean is_writeable(Path path)
1883  {
1884    return is_writable(path);
1885  }
1886
1887  /**
1888   * Creates a hard link
1889   */

1890  public boolean link(Env env, Path source, Path destination)
1891  {
1892    try {
1893      return destination.createLink(source, true);
1894    } catch (Exception JavaDoc e) {
1895      env.warning(e);
1896
1897      return false;
1898    }
1899  }
1900
1901  public static long linkinfo(Env env, Path path)
1902  {
1903    // XXX: Hack to trigger lstat() in JNI code
1904
if (path.isLink())
1905      return path.getDevice();
1906    else
1907      return 0;
1908  }
1909
1910  /**
1911   * Returns file statistics
1912   */

1913  public static Value lstat(Env env, StringValue filename)
1914  {
1915    ProtocolWrapper wrapper = getProtocolWrapper(env, filename.toString());
1916
1917    if (wrapper != null)
1918      // XXX flags?
1919
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    // XXX: Hack to trigger lstat() in JNI code
1925
path.isLink();
1926
1927    return statImpl(env, path);
1928  }
1929
1930  /**
1931   * Makes the directory
1932   *
1933   * @param path the directory to make
1934   */

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      // XXX options?
1944
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 JavaDoc e) {
1955      log.log(Level.FINE, e.toString(), e);
1956
1957      return false;
1958    }
1959  }
1960
1961  /**
1962   * Moves the uploaded file.
1963   *
1964   * @param tail the temp name of the uploaded file
1965   * @param dst the destination path
1966   */

1967  public static boolean move_uploaded_file(Env env, String JavaDoc 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 JavaDoc e) {
1979      env.warning(e);
1980
1981      return false;
1982    }
1983  }
1984
1985  /**
1986   * Opens a directory
1987   *
1988   * @param pathName the directory to open
1989   */

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      /// XXX options?
1997
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 JavaDoc e) {
2010      throw new QuercusModuleException(e);
2011    }
2012  }
2013
2014  /**
2015   * Parses the ini file.
2016   */

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 JavaDoc 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 JavaDoc
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 JavaDoc sb = new StringBuilder JavaDoc();
2057
2058    for (ch = is.read(); ch >= 0 && ch != ']'; ch = is.read()) {
2059      sb.append((char) ch);
2060    }
2061
2062    String JavaDoc 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 JavaDoc sb = new StringBuilder JavaDoc();
2071
2072    for (; isValidIniKeyChar((char) ch); ch = is.read()) {
2073      sb.append((char) ch);
2074    }
2075
2076    String JavaDoc 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 JavaDoc
2095  {
2096    if (ch == '\r' || ch == '\n')
2097      return NullValue.NULL;
2098
2099    if (ch == '"') {
2100      StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
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 JavaDoc sb = new StringBuilder JavaDoc();
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 JavaDoc sb = new StringBuilder JavaDoc();
2123
2124      for (; ch >= 0 && ch != '\r' && ch != '\n'; ch = is.read()) {
2125    sb.append((char) ch);
2126      }
2127
2128      String JavaDoc 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 JavaDoc
2169  {
2170    for (; ch > 0 && ch != '\r' && ch != '\n'; ch = is.read()) {
2171    }
2172  }
2173
2174  /**
2175   * Parses the path, splitting it into parts.
2176   */

2177  public static Value pathinfo(String JavaDoc path)
2178  {
2179    int p = path.lastIndexOf('/');
2180
2181    String JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc []args = new String JavaDoc[3];
2232
2233    try {
2234      args[0] = "sh";
2235      args[1] = "-c";
2236      args[2] = command;
2237
2238      Process JavaDoc 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 JavaDoc e) {
2245      env.warning(e.getMessage(), e);
2246
2247      return null;
2248    }
2249  }
2250  
2251  /**
2252   * Reads the next entry
2253   *
2254   * @param dirV the directory resource
2255   */

2256  public static Value readdir(Env env, @NotNull DirectoryValue dir)
2257  {
2258    return dir.readdir();
2259  }
2260
2261  /**
2262   * Read the contents of a file and write them out.
2263   */

2264  public Value readfile(Env env,
2265                        String JavaDoc 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  /**
2284   * The readlink always fails.
2285   */

2286  public static boolean readlink(Env env, String JavaDoc path)
2287  {
2288    env.stub("readlink(" + path + ")");
2289
2290    return false;
2291  }
2292
2293  /**
2294   * Returns the actual path name.
2295   */

2296  public static String JavaDoc realpath(Path path)
2297  {
2298    String JavaDoc 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  /**
2307   * Renames a file
2308   *
2309   * @param fromPath the path to change to
2310   * @param toPath the path to change to
2311   */

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 JavaDoc e) {
2330      log.log(Level.FINE, e.toString(), e);
2331
2332      return false;
2333    }
2334  }
2335
2336  /**
2337   * Rewinds the stream.
2338   *
2339   * @param is the file resource
2340   */

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  /**
2353   * Rewinds the directory listing
2354   *
2355   * @param dirV the directory resource
2356   */

2357  public static void rewinddir(Env env, @NotNull DirectoryValue dir)
2358  {
2359    dir.rewinddir();
2360  }
2361
2362  /**
2363   * remove a directory
2364   */

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      // XXX options?
2373
return wrapper.rmdir(env, filename, LongValue.ZERO);
2374
2375    // quercus/160s
2376

2377    // XXX: safe_mode
2378
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 JavaDoc e) {
2388      log.log(Level.FINE, e.toString(), e);
2389
2390      return false;
2391    }
2392  }
2393
2394  /**
2395   * Closes the directory
2396   *
2397   * @param dirV the directory resource
2398   */

2399  public static void closedir(Env env, @NotNull DirectoryValue dirV)
2400  {
2401    dirV.close();
2402  }
2403
2404  /**
2405   * Scan the directory
2406   *
2407   * @param fileName the directory
2408   */

2409  public static Value scandir(Env env, String JavaDoc 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 JavaDoc []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 JavaDoc e) {
2440      throw new QuercusModuleException(e);
2441    }
2442  }
2443
2444  /**
2445   * Sets the write buffer.
2446   */

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  /**
2454   * Returns file statistics
2455   */

2456  public static Value stat(Env env, StringValue filename)
2457  {
2458    ProtocolWrapper wrapper = getProtocolWrapper(env, filename.toString());
2459
2460    if (wrapper != null)
2461      // XXX flags?
2462
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  /**
2514   * Creates a symlink
2515   */

2516  public boolean symlink(Env env, Path source, Path destination)
2517  {
2518    try {
2519      return destination.createLink(source, false);
2520    } catch (Exception JavaDoc e) {
2521      env.warning(e);
2522
2523      return false;
2524    }
2525  }
2526
2527  /**
2528   * Creates a temporary file.
2529   */

2530  public static Value tempnam(Env env, Path dir, String JavaDoc prefix)
2531  {
2532    // quercus/160u
2533

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 JavaDoc e) {
2543      log.log(Level.FINE, e.toString(), e);
2544
2545      return BooleanValue.FALSE;
2546    }
2547  }
2548
2549  /**
2550   * Creates a temporary file.
2551   */

2552  @ReturnNullAsFalse
2553  public static FileInputOutput tmpfile(Env env)
2554  {
2555    try {
2556      // XXX: location of tmp files s/b configurable
2557

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 JavaDoc e) {
2566      log.log(Level.FINE, e.toString(), e);
2567
2568      return null;
2569    }
2570  }
2571
2572  /**
2573   * sets the time to the current time
2574   */

2575  public static boolean touch(Path path,
2576                              @Optional int time,
2577                              @Optional int atime)
2578  {
2579    // XXX: atime not implemented (it might be > time)
2580

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 JavaDoc e) {
2595      log.log(Level.FINE, e.toString(), e);
2596
2597      return false;
2598    }
2599  }
2600
2601  /**
2602   * umask call
2603   */

2604  public static int umask(Env env, int mask)
2605  {
2606    env.stub("umask(" + mask + ")");
2607
2608    return mask;
2609  }
2610
2611  /**
2612   * remove call
2613   */

2614  public static boolean unlink(Env env,
2615                               StringValue filename,
2616                               @Optional Value context)
2617  {
2618    // quercus/160p
2619

2620    // XXX: safe_mode
2621
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 JavaDoc 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