KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > runtime > builtin > meta > FileMetaClass


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2005 Thomas E Enebo <enebo@acm.org>
15  * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
16  * Copyright (C) 2006 Ola Bini <ola.bini@ki.se>
17  *
18  * Alternatively, the contents of this file may be used under the terms of
19  * either of the GNU General Public License Version 2 or later (the "GPL"),
20  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
21  * in which case the provisions of the GPL or the LGPL are applicable instead
22  * of those above. If you wish to allow use of your version of this file only
23  * under the terms of either the GPL or the LGPL, and not to allow others to
24  * use your version of this file under the terms of the CPL, indicate your
25  * decision by deleting the provisions above and replace them with the notice
26  * and other provisions required by the GPL or the LGPL. If you do not delete
27  * the provisions above, a recipient may use your version of this file under
28  * the terms of any one of the CPL, the GPL or the LGPL.
29  ***** END LICENSE BLOCK *****/

30 package org.jruby.runtime.builtin.meta;
31
32 import java.io.File JavaDoc;
33 import java.io.FileInputStream JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.nio.channels.FileChannel JavaDoc;
36 import java.util.regex.Pattern JavaDoc;
37
38 import org.jruby.Ruby;
39 import org.jruby.RubyArray;
40 import org.jruby.RubyClass;
41 import org.jruby.RubyDir;
42 import org.jruby.RubyFile;
43 import org.jruby.RubyFileStat;
44 import org.jruby.RubyFileTest;
45 import org.jruby.RubyFixnum;
46 import org.jruby.RubyInteger;
47 import org.jruby.RubyModule;
48 import org.jruby.RubyNumeric;
49 import org.jruby.RubyString;
50 import org.jruby.RubyTime;
51 import org.jruby.runtime.Arity;
52 import org.jruby.runtime.Block;
53 import org.jruby.runtime.ObjectAllocator;
54 import org.jruby.runtime.ThreadContext;
55 import org.jruby.runtime.builtin.IRubyObject;
56 import org.jruby.util.IOModes;
57 import org.jruby.util.JRubyFile;
58 import org.jruby.util.PrintfFormat;
59 import org.jruby.util.collections.SinglyLinkedList;
60
61 public class FileMetaClass extends IOMetaClass {
62     private static final int FNM_NOESCAPE = 1;
63     private static final int FNM_PATHNAME = 2;
64     private static final int FNM_DOTMATCH = 4;
65     private static final int FNM_CASEFOLD = 8;
66     
67     public static final PrintfFormat OCTAL_FORMATTER = new PrintfFormat("%o");
68     
69     public FileMetaClass(Ruby runtime) {
70         super("File", RubyFile.class, runtime.getClass("IO"), FILE_ALLOCATOR);
71     }
72     
73     public FileMetaClass(String JavaDoc name, RubyClass superClass, ObjectAllocator allocator, SinglyLinkedList parentCRef) {
74         super(name, RubyFile.class, superClass, allocator, parentCRef);
75     }
76     
77     protected class FileMeta extends Meta {
78         protected void initializeClass() {
79             Ruby runtime = getRuntime();
80             RubyString separator = runtime.newString("/");
81             separator.freeze();
82             defineConstant("SEPARATOR", separator);
83             defineConstant("Separator", separator);
84             
85             RubyString altSeparator = runtime.newString(File.separatorChar == '/' ? "\\" : "/");
86             altSeparator.freeze();
87             defineConstant("ALT_SEPARATOR", altSeparator);
88             
89             RubyString pathSeparator = runtime.newString(File.pathSeparator);
90             pathSeparator.freeze();
91             defineConstant("PATH_SEPARATOR", pathSeparator);
92             
93             // TODO: These were missing, so we're not handling them elsewhere?
94
// FIXME: The old value, 32786, didn't match what IOModes expected, so I reference
95
// the constant here. THIS MAY NOT BE THE CORRECT VALUE.
96
setConstant("BINARY", runtime.newFixnum(IOModes.BINARY));
97             setConstant("FNM_NOESCAPE", runtime.newFixnum(FNM_NOESCAPE));
98             setConstant("FNM_CASEFOLD", runtime.newFixnum(FNM_CASEFOLD));
99             setConstant("FNM_DOTMATCH", runtime.newFixnum(FNM_DOTMATCH));
100             setConstant("FNM_PATHNAME", runtime.newFixnum(FNM_PATHNAME));
101             
102             // Create constants for open flags
103
setConstant("RDONLY", runtime.newFixnum(IOModes.RDONLY));
104             setConstant("WRONLY", runtime.newFixnum(IOModes.WRONLY));
105             setConstant("RDWR", runtime.newFixnum(IOModes.RDWR));
106             setConstant("CREAT", runtime.newFixnum(IOModes.CREAT));
107             setConstant("EXCL", runtime.newFixnum(IOModes.EXCL));
108             setConstant("NOCTTY", runtime.newFixnum(IOModes.NOCTTY));
109             setConstant("TRUNC", runtime.newFixnum(IOModes.TRUNC));
110             setConstant("APPEND", runtime.newFixnum(IOModes.APPEND));
111             setConstant("NONBLOCK", runtime.newFixnum(IOModes.NONBLOCK));
112             
113             // Create constants for flock
114
setConstant("LOCK_SH", runtime.newFixnum(RubyFile.LOCK_SH));
115             setConstant("LOCK_EX", runtime.newFixnum(RubyFile.LOCK_EX));
116             setConstant("LOCK_NB", runtime.newFixnum(RubyFile.LOCK_NB));
117             setConstant("LOCK_UN", runtime.newFixnum(RubyFile.LOCK_UN));
118             
119             // Create Constants class
120
RubyModule constants = defineModuleUnder("Constants");
121             
122             // TODO: These were missing, so we're not handling them elsewhere?
123
constants.setConstant("BINARY", runtime.newFixnum(32768));
124             constants.setConstant("FNM_NOESCAPE", runtime.newFixnum(1));
125             constants.setConstant("FNM_CASEFOLD", runtime.newFixnum(8));
126             constants.setConstant("FNM_DOTMATCH", runtime.newFixnum(4));
127             constants.setConstant("FNM_PATHNAME", runtime.newFixnum(2));
128             
129             // Create constants for open flags
130
constants.setConstant("RDONLY", runtime.newFixnum(IOModes.RDONLY));
131             constants.setConstant("WRONLY", runtime.newFixnum(IOModes.WRONLY));
132             constants.setConstant("RDWR", runtime.newFixnum(IOModes.RDWR));
133             constants.setConstant("CREAT", runtime.newFixnum(IOModes.CREAT));
134             constants.setConstant("EXCL", runtime.newFixnum(IOModes.EXCL));
135             constants.setConstant("NOCTTY", runtime.newFixnum(IOModes.NOCTTY));
136             constants.setConstant("TRUNC", runtime.newFixnum(IOModes.TRUNC));
137             constants.setConstant("APPEND", runtime.newFixnum(IOModes.APPEND));
138             constants.setConstant("NONBLOCK", runtime.newFixnum(IOModes.NONBLOCK));
139             
140             // Create constants for flock
141
constants.setConstant("LOCK_SH", runtime.newFixnum(RubyFile.LOCK_SH));
142             constants.setConstant("LOCK_EX", runtime.newFixnum(RubyFile.LOCK_EX));
143             constants.setConstant("LOCK_NB", runtime.newFixnum(RubyFile.LOCK_NB));
144             constants.setConstant("LOCK_UN", runtime.newFixnum(RubyFile.LOCK_UN));
145             
146             // TODO Singleton methods: atime, blockdev?, chardev?, chown, directory?
147
// TODO Singleton methods: executable?, executable_real?,
148
// TODO Singleton methods: ftype, grpowned?, lchmod, lchown, link, mtime, owned?
149
// TODO Singleton methods: pipe?, readlink, setgid?, setuid?, socket?,
150
// TODO Singleton methods: stat, sticky?, symlink, symlink?, umask, utime
151

152             extendObject(runtime.getModule("FileTest"));
153             
154             defineFastSingletonMethod("basename", Arity.optional());
155             defineFastSingletonMethod("chmod", Arity.required(2));
156             defineFastSingletonMethod("chown", Arity.required(2));
157             defineFastSingletonMethod("delete", Arity.optional(), "unlink");
158             defineFastSingletonMethod("dirname", Arity.singleArgument());
159             defineFastSingletonMethod("expand_path", Arity.optional());
160             defineFastSingletonMethod("extname", Arity.singleArgument());
161             defineFastSingletonMethod("fnmatch", Arity.optional());
162             defineFastSingletonMethod("fnmatch?", Arity.optional(), "fnmatch");
163             defineFastSingletonMethod("join", Arity.optional());
164             defineFastSingletonMethod("lstat", Arity.singleArgument());
165             defineFastSingletonMethod("mtime", Arity.singleArgument());
166             defineFastSingletonMethod("ctime", Arity.singleArgument());
167             defineSingletonMethod("open", Arity.optional());
168             defineFastSingletonMethod("rename", Arity.twoArguments());
169             defineFastSingletonMethod("size?", Arity.singleArgument(), "size_p");
170             defineFastSingletonMethod("split", Arity.singleArgument());
171             defineFastSingletonMethod("stat", Arity.singleArgument(), "lstat");
172             defineFastSingletonMethod("symlink?", Arity.singleArgument(), "symlink_p");
173             defineFastSingletonMethod("truncate", Arity.twoArguments());
174             defineFastSingletonMethod("utime", Arity.optional());
175             defineFastSingletonMethod("unlink", Arity.optional());
176             
177             // TODO: Define instance methods: atime, chmod, chown, lchmod, lchown, lstat, mtime
178
//defineMethod("flock", Arity.singleArgument());
179
defineFastMethod("chmod", Arity.required(1));
180             defineFastMethod("chown", Arity.required(1));
181             defineFastMethod("ctime", Arity.noArguments());
182             defineMethod("initialize", Arity.optional());
183             defineFastMethod("path", Arity.noArguments());
184             defineFastMethod("stat", Arity.noArguments());
185             defineFastMethod("truncate", Arity.singleArgument());
186             defineFastMethod("flock", Arity.singleArgument());
187             
188             RubyFileStat.createFileStatClass(runtime);
189         }
190     };
191     
192     protected Meta getMeta() {
193         return new FileMeta();
194     }
195     
196     public RubyClass newSubClass(String JavaDoc name, SinglyLinkedList parentCRef) {
197         return new FileMetaClass(name, this, FILE_ALLOCATOR, parentCRef);
198     }
199     
200     private static ObjectAllocator FILE_ALLOCATOR = new ObjectAllocator() {
201         public IRubyObject allocate(Ruby runtime, RubyClass klass) {
202             RubyFile instance = new RubyFile(runtime, klass);
203             
204             instance.setMetaClass(klass);
205             
206             return instance;
207         }
208     };
209     
210     public IRubyObject basename(IRubyObject[] args) {
211         checkArgumentCount(args, 1, 2);
212         
213         String JavaDoc name = RubyString.stringValue(args[0]).toString();
214         if (name.length() > 1 && name.charAt(name.length() - 1) == '/') {
215             name = name.substring(0, name.length() - 1);
216         }
217         
218         // Paths which end in "/" or "\\" must be stripped off.
219
int slashCount = 0;
220         int length = name.length();
221         for (int i = length - 1; i >= 0; i--) {
222             char c = name.charAt(i);
223             if (c != '/' && c != '\\') {
224                 break;
225             }
226             slashCount++;
227         }
228         if (slashCount > 0 && length > 1) {
229             name = name.substring(0, name.length() - slashCount);
230         }
231         
232         int index = name.lastIndexOf('/');
233         if (index == -1) {
234             // XXX actually only on windows...
235
index = name.lastIndexOf('\\');
236         }
237         
238         if (!name.equals("/") && index != -1) {
239             name = name.substring(index + 1);
240         }
241         
242         if (args.length == 2) {
243             String JavaDoc ext = RubyString.stringValue(args[1]).toString();
244             if (".*".equals(ext)) {
245                 index = name.lastIndexOf('.');
246                 if (index > 0) { // -1 no match; 0 it is dot file not extension
247
name = name.substring(0, index);
248                 }
249             } else if (name.endsWith(ext)) {
250                 name = name.substring(0, name.length() - ext.length());
251             }
252         }
253         return getRuntime().newString(name).infectBy(args[0]);
254     }
255     
256     public IRubyObject chmod(IRubyObject[] args) {
257         checkArgumentCount(args, 2, -1);
258         
259         int count = 0;
260         RubyInteger mode = args[0].convertToInteger();
261         for (int i = 1; i < args.length; i++) {
262             IRubyObject filename = args[i];
263             
264             if (!RubyFileTest.exist_p(filename, filename.convertToString()).isTrue()) {
265                 throw getRuntime().newErrnoENOENTError("No such file or directory - " + filename);
266             }
267             
268             try {
269                 Process JavaDoc chmod = Runtime.getRuntime().exec("chmod " + OCTAL_FORMATTER.sprintf(mode.getLongValue()) + " " + filename);
270                 chmod.waitFor();
271                 int result = chmod.exitValue();
272                 if (result == 0) {
273                     count++;
274                 }
275             } catch (IOException JavaDoc ioe) {
276                 // FIXME: ignore?
277
} catch (InterruptedException JavaDoc ie) {
278                 // FIXME: ignore?
279
}
280         }
281         
282         return getRuntime().newFixnum(count);
283     }
284     
285     public IRubyObject chown(IRubyObject[] args) {
286         checkArgumentCount(args, 2, -1);
287         
288         int count = 0;
289         RubyInteger owner = args[0].convertToInteger();
290         for (int i = 1; i < args.length; i++) {
291             IRubyObject filename = args[i];
292             
293             if (!RubyFileTest.exist_p(filename, filename.convertToString()).isTrue()) {
294                 throw getRuntime().newErrnoENOENTError("No such file or directory - " + filename);
295             }
296             
297             try {
298                 Process JavaDoc chown = Runtime.getRuntime().exec("chown " + owner + " " + filename);
299                 chown.waitFor();
300                 int result = chown.exitValue();
301                 if (result == 0) {
302                     count++;
303                 }
304             } catch (IOException JavaDoc ioe) {
305                 // FIXME: ignore?
306
} catch (InterruptedException JavaDoc ie) {
307                 // FIXME: ignore?
308
}
309         }
310         
311         return getRuntime().newFixnum(count);
312     }
313     
314     public IRubyObject dirname(IRubyObject arg) {
315         RubyString filename = RubyString.stringValue(arg);
316         String JavaDoc name = filename.toString().replace('\\', '/');
317         if (name.length() > 1 && name.charAt(name.length() - 1) == '/') {
318             name = name.substring(0, name.length() - 1);
319         }
320         //TODO deal with drive letters A: and UNC names
321
int index = name.lastIndexOf('/');
322         if (index == -1) {
323             return getRuntime().newString(".");
324         }
325         if (index == 0) {
326             return getRuntime().newString("/");
327         }
328         return getRuntime().newString(name.substring(0, index)).infectBy(filename);
329     }
330     
331     public IRubyObject extname(IRubyObject arg) {
332         RubyString filename = RubyString.stringValue(arg);
333         
334         String JavaDoc name = filename.toString();
335         
336         // trim off dir name, since it may have dots in it
337
//TODO deal with drive letters A: and UNC names
338
int index = name.lastIndexOf('/');
339         if (index == -1) {
340             // XXX actually, only on windows...
341
index = name.lastIndexOf('\\');
342         }
343         name = name.substring(index + 1);
344         
345         int ix = name.lastIndexOf(".");
346         if(ix == -1) {
347             return getRuntime().newString("");
348         } else {
349             return getRuntime().newString(name.substring(ix));
350         }
351     }
352     
353     public IRubyObject expand_path(IRubyObject[] args) {
354         checkArgumentCount(args, 1, 2);
355         String JavaDoc relativePath = RubyString.stringValue(args[0]).toString();
356         int pathLength = relativePath.length();
357         
358         if (pathLength >= 1 && relativePath.charAt(0) == '~') {
359             // Enebo : Should ~frogger\\foo work (it doesnt in linux ruby)?
360
int userEnd = relativePath.indexOf('/');
361             
362             if (userEnd == -1) {
363                 if (pathLength == 1) {
364                     // Single '~' as whole path to expand
365
relativePath = RubyDir.getHomeDirectoryPath(this).toString();
366                 } else {
367                     // No directory delimeter. Rest of string is username
368
userEnd = pathLength;
369                 }
370             }
371             
372             if (userEnd == 1) {
373                 // '~/...' as path to expand
374
relativePath = RubyDir.getHomeDirectoryPath(this).toString() +
375                         relativePath.substring(1);
376             } else if (userEnd > 1){
377                 // '~user/...' as path to expand
378
String JavaDoc user = relativePath.substring(1, userEnd);
379                 IRubyObject dir = RubyDir.getHomeDirectoryPath(this, user);
380                 
381                 if (dir.isNil()) {
382                     throw getRuntime().newArgumentError("user " + user + " does not exist");
383                 }
384                 
385                 relativePath = "" + dir +
386                         (pathLength == userEnd ? "" : relativePath.substring(userEnd));
387             }
388         }
389         
390         if (new File JavaDoc(relativePath).isAbsolute()) {
391             try {
392                 return getRuntime().newString(JRubyFile.create(relativePath, "").getCanonicalPath());
393             } catch(IOException JavaDoc e) {
394                 return getRuntime().newString(relativePath);
395             }
396         }
397         
398         String JavaDoc cwd = getRuntime().getCurrentDirectory();
399         if (args.length == 2 && !args[1].isNil()) {
400             cwd = RubyString.stringValue(args[1]).toString();
401         }
402         
403         // Something wrong we don't know the cwd...
404
if (cwd == null) {
405             return getRuntime().getNil();
406         }
407         
408         JRubyFile path = JRubyFile.create(cwd, relativePath);
409         
410         String JavaDoc extractedPath;
411         try {
412             extractedPath = path.getCanonicalPath();
413         } catch (IOException JavaDoc e) {
414             extractedPath = path.getAbsolutePath();
415         }
416         return getRuntime().newString(extractedPath);
417     }
418     
419     /**
420      * Returns true if path matches against pattern The pattern is not a regular expression;
421      * instead it follows rules similar to shell filename globbing. It may contain the following
422      * metacharacters:
423      * *: Glob - match any sequence chars (re: .*). If like begins with '.' then it doesn't.
424      * ?: Matches a single char (re: .).
425      * [set]: Matches a single char in a set (re: [...]).
426      *
427      */

428     // Fixme: implement FNM_PATHNAME, FNM_DOTMATCH, and FNM_CASEFOLD
429
public IRubyObject fnmatch(IRubyObject[] args) {
430         checkArgumentCount(args, 2, -1);
431         String JavaDoc pattern = args[0].convertToString().toString();
432         RubyString path = args[1].convertToString();
433         int opts = (int) (args.length > 2 ? args[2].convertToInteger().getLongValue() : 0);
434         
435         boolean dot = pattern.startsWith(".");
436         
437         pattern = pattern.replaceAll("(\\.)", "\\\\$1");
438         pattern = pattern.replaceAll("(?<=[^\\\\])\\*", ".*");
439         pattern = pattern.replaceAll("^\\*", ".*");
440         pattern = pattern.replaceAll("(?<=[^\\\\])\\?", ".");
441         pattern = pattern.replaceAll("^\\?", ".");
442         if ((opts & FNM_NOESCAPE) != FNM_NOESCAPE) {
443             pattern = pattern.replaceAll("\\\\([^\\\\*\\\\?])", "$1");
444         }
445         pattern = pattern.replaceAll("\\{", "\\\\{");
446         pattern = pattern.replaceAll("\\}", "\\\\}");
447         pattern = "^" + pattern + "$";
448         
449         if (path.toString().startsWith(".") && !dot) {
450             return getRuntime().newBoolean(false);
451         }
452         
453         return getRuntime().newBoolean(Pattern.matches(pattern, path.toString()));
454     }
455     
456     /*
457      * Fixme: This does not have exact same semantics as RubyArray.join, but they
458      * probably could be consolidated (perhaps as join(args[], sep, doChomp)).
459      */

460     public RubyString join(IRubyObject[] args) {
461         boolean isTainted = false;
462         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
463         
464         for (int i = 0; i < args.length; i++) {
465             if (args[i].isTaint()) {
466                 isTainted = true;
467             }
468             String JavaDoc element;
469             if (args[i] instanceof RubyString) {
470                 element = args[i].toString();
471             } else if (args[i] instanceof RubyArray) {
472                 // Fixme: Need infinite recursion check to put [...] and not go into a loop
473
element = join(((RubyArray) args[i]).toJavaArray()).toString();
474             } else {
475                 element = args[i].convertToString().toString();
476             }
477             
478             chomp(buffer);
479             if (i > 0 && !element.startsWith("/") && !element.startsWith("\\")) {
480                 buffer.append("/");
481             }
482             buffer.append(element);
483         }
484         
485         RubyString fixedStr = RubyString.newString(getRuntime(), buffer.toString());
486         fixedStr.setTaint(isTainted);
487         return fixedStr;
488     }
489     
490     private void chomp(StringBuffer JavaDoc buffer) {
491         int lastIndex = buffer.length() - 1;
492         
493         while (lastIndex >= 0 && (buffer.lastIndexOf("/") == lastIndex || buffer.lastIndexOf("\\") == lastIndex)) {
494             buffer.setLength(lastIndex);
495             lastIndex--;
496         }
497     }
498     
499     public IRubyObject lstat(IRubyObject filename) {
500         RubyString name = RubyString.stringValue(filename);
501         return getRuntime().newRubyFileStat(name.toString());
502     }
503     
504     public IRubyObject ctime(IRubyObject filename) {
505         RubyString name = RubyString.stringValue(filename);
506         return getRuntime().newTime(JRubyFile.create(getRuntime().getCurrentDirectory(),name.toString()).getParentFile().lastModified());
507     }
508     
509     public IRubyObject mtime(IRubyObject filename) {
510         RubyString name = RubyString.stringValue(filename);
511         
512         return getRuntime().newTime(JRubyFile.create(getRuntime().getCurrentDirectory(),name.toString()).lastModified());
513     }
514     
515     public IRubyObject open(IRubyObject[] args, Block block) {
516         return open(args, true, block);
517     }
518     
519     public IRubyObject open(IRubyObject[] args, boolean tryToYield, Block block) {
520         checkArgumentCount(args, 1, -1);
521         Ruby runtime = getRuntime();
522         ThreadContext tc = runtime.getCurrentContext();
523         
524         RubyString pathString = RubyString.stringValue(args[0]);
525         pathString.checkSafeString();
526         String JavaDoc path = pathString.toString();
527         
528         IOModes modes =
529                 args.length >= 2 ? getModes(args[1]) : new IOModes(runtime, IOModes.RDONLY);
530         RubyFile file = new RubyFile(runtime, this);
531         
532         RubyInteger fileMode =
533                 args.length >= 3 ? args[2].convertToInteger() : null;
534         
535         file.openInternal(path, modes);
536         
537         if (fileMode != null) {
538             chmod(new IRubyObject[] {fileMode, pathString});
539         }
540         
541         if (tryToYield && block.isGiven()) {
542             try {
543                 return tc.yield(file, block);
544             } finally {
545                 file.close();
546             }
547         }
548         
549         return file;
550     }
551     
552     public IRubyObject rename(IRubyObject oldName, IRubyObject newName) {
553         RubyString oldNameString = RubyString.stringValue(oldName);
554         RubyString newNameString = RubyString.stringValue(newName);
555         oldNameString.checkSafeString();
556         newNameString.checkSafeString();
557         JRubyFile oldFile = JRubyFile.create(getRuntime().getCurrentDirectory(),oldNameString.toString());
558         JRubyFile newFile = JRubyFile.create(getRuntime().getCurrentDirectory(),newNameString.toString());
559         
560         if (!oldFile.exists() || !newFile.getParentFile().exists()) {
561             throw getRuntime().newErrnoENOENTError("No such file or directory - " + oldNameString + " or " + newNameString);
562         }
563         oldFile.renameTo(JRubyFile.create(getRuntime().getCurrentDirectory(),newNameString.toString()));
564         
565         return RubyFixnum.zero(getRuntime());
566     }
567     
568     public IRubyObject size_p(IRubyObject filename) {
569         long size = 0;
570         
571         try {
572             FileInputStream JavaDoc fis = new FileInputStream JavaDoc(new File JavaDoc(filename.toString()));
573             FileChannel JavaDoc chan = fis.getChannel();
574             size = chan.size();
575             chan.close();
576             fis.close();
577         } catch (IOException JavaDoc ioe) {
578             // missing files or inability to open should just return nil
579
}
580         
581         if (size == 0) {
582             return getRuntime().getNil();
583         }
584         
585         return getRuntime().newFixnum(size);
586     }
587     
588     public RubyArray split(IRubyObject arg) {
589         RubyString filename = RubyString.stringValue(arg);
590         
591         return filename.getRuntime().newArray(dirname(filename),
592                 basename(new IRubyObject[] { filename }));
593     }
594     
595     public IRubyObject symlink_p(IRubyObject arg1) {
596         RubyString filename = RubyString.stringValue(arg1);
597         
598         JRubyFile file = JRubyFile.create(getRuntime().getCurrentDirectory(), filename.toString());
599         
600         try {
601             // Only way to determine symlink is to compare canonical and absolute files
602
// However symlinks in containing path must not produce false positives, so we check that first
603
File JavaDoc absoluteParent = file.getAbsoluteFile().getParentFile();
604             File JavaDoc canonicalParent = file.getAbsoluteFile().getParentFile().getCanonicalFile();
605             
606             if (canonicalParent.getAbsolutePath().equals(absoluteParent.getAbsolutePath())) {
607                 // parent doesn't change when canonicalized, compare absolute and canonical file directly
608
return file.getAbsolutePath().equals(file.getCanonicalPath()) ? getRuntime().getFalse() : getRuntime().getTrue();
609             }
610             
611             // directory itself has symlinks (canonical != absolute), so build new path with canonical parent and compare
612
file = JRubyFile.create(getRuntime().getCurrentDirectory(), canonicalParent.getAbsolutePath() + "/" + file.getName());
613             return file.getAbsolutePath().equals(file.getCanonicalPath()) ? getRuntime().getFalse() : getRuntime().getTrue();
614         } catch (IOException JavaDoc ioe) {
615             // problem canonicalizing the file; nothing we can do but return false
616
return getRuntime().getFalse();
617         }
618     }
619     
620     // Can we produce IOError which bypasses a close?
621
public IRubyObject truncate(IRubyObject arg1, IRubyObject arg2) {
622         RubyString filename = RubyString.stringValue(arg1);
623         RubyFixnum newLength = (RubyFixnum) arg2.convertToType("Fixnum", "to_int", true);
624         IRubyObject[] args = new IRubyObject[] { filename, getRuntime().newString("w+") };
625         RubyFile file = (RubyFile) open(args, false, null);
626         file.truncate(newLength);
627         file.close();
628         
629         return RubyFixnum.zero(getRuntime());
630     }
631     
632     /**
633      * This method does NOT set atime, only mtime, since Java doesn't support anything else.
634      */

635     public IRubyObject utime(IRubyObject[] args) {
636         checkArgumentCount(args, 2, -1);
637         
638         // Ignore access_time argument since Java does not support it.
639

640         long mtime;
641         if (args[1] instanceof RubyTime) {
642             mtime = ((RubyTime) args[1]).getJavaDate().getTime();
643         } else if (args[1] instanceof RubyNumeric) {
644             mtime = RubyNumeric.num2long(args[1]);
645         } else {
646             mtime = 0;
647         }
648         
649         for (int i = 2, j = args.length; i < j; i++) {
650             RubyString filename = RubyString.stringValue(args[i]);
651             filename.checkSafeString();
652             JRubyFile fileToTouch = JRubyFile.create(getRuntime().getCurrentDirectory(),filename.toString());
653             
654             if (!fileToTouch.exists()) {
655                 throw getRuntime().newErrnoENOENTError(" No such file or directory - \"" +
656                         filename + "\"");
657             }
658             
659             fileToTouch.setLastModified(mtime);
660         }
661         
662         return getRuntime().newFixnum(args.length - 2);
663     }
664     
665     public IRubyObject unlink(IRubyObject[] args) {
666         for (int i = 0; i < args.length; i++) {
667             RubyString filename = RubyString.stringValue(args[i]);
668             filename.checkSafeString();
669             JRubyFile lToDelete = JRubyFile.create(getRuntime().getCurrentDirectory(),filename.toString());
670             if (!lToDelete.exists()) {
671                 throw getRuntime().newErrnoENOENTError(" No such file or directory - \"" + filename + "\"");
672             }
673             if (!lToDelete.delete()) {
674                 return getRuntime().getFalse();
675             }
676         }
677         return getRuntime().newFixnum(args.length);
678     }
679     
680     // TODO: Figure out to_str and to_int conversion + precedence here...
681
private IOModes getModes(IRubyObject object) {
682         if (object instanceof RubyString) {
683             return new IOModes(getRuntime(), ((RubyString)object).toString());
684         } else if (object instanceof RubyFixnum) {
685             return new IOModes(getRuntime(), ((RubyFixnum)object).getLongValue());
686         }
687         
688         throw getRuntime().newTypeError("Invalid type for modes");
689     }
690     
691     
692 }
693
Popular Tags