1 // natFile.cc - Native part of File class for POSIX.
3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
15 #include <sys/param.h>
17 #include <sys/types.h>
31 #include <java/io/File.h>
32 #include <java/io/IOException.h>
33 #include <java/util/ArrayList.h>
34 #include <java/lang/String.h>
35 #include <java/io/FilenameFilter.h>
36 #include <java/io/FileFilter.h>
37 #include <java/lang/System.h>
40 java::io::File::_access (jint query
)
42 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
43 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
45 JvAssert (query
== READ
|| query
== WRITE
|| query
== EXISTS
);
50 else if (query
== WRITE
)
54 return ::access (buf
, mode
) == 0;
61 java::io::File::_stat (jint query
)
63 if (query
== ISHIDDEN
)
64 return getName()->charAt(0) == '.';
67 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
68 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
72 if (::stat (buf
, &sb
))
75 JvAssert (query
== DIRECTORY
|| query
== ISFILE
);
76 jboolean r
= S_ISDIR (sb
.st_mode
);
77 return query
== DIRECTORY
? r
: ! r
;
84 java::io::File::attr (jint query
)
86 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
87 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
92 // FIXME: not sure about return value here.
93 if (::stat (buf
, &sb
))
96 JvAssert (query
== MODIFIED
|| query
== LENGTH
);
97 return query
== MODIFIED
? (jlong
)sb
.st_mtime
* 1000 : sb
.st_size
;
99 // There's no good choice here.
105 java::io::File::getCanonicalPath (void)
107 // We use `+2' here because we might need to use `.' for our special
109 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 2);
110 char buf2
[MAXPATHLEN
];
111 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
113 // Special case: treat "" the same as ".".
120 if (realpath (buf
, buf2
) == NULL
)
122 // If realpath failed, we have to come up with a canonical path
123 // anyway. We do this with purely textual manipulation.
124 // FIXME: this isn't perfect. You can construct a case where
125 // we get a different answer from the JDK:
126 // mkdir -p /tmp/a/b/c
127 // ln -s /tmp/a/b /tmp/a/z
128 // ... getCanonicalPath("/tmp/a/z/c/nosuchfile")
129 // We will give /tmp/a/z/c/nosuchfile, while the JDK will
130 // give /tmp/a/b/c/nosuchfile.
134 // Not absolute, so start with current directory.
135 if (getcwd (buf2
, sizeof (buf2
)) == NULL
)
136 throw new IOException ();
137 out_idx
= strlen (buf2
);
145 while (buf
[in_idx
] != '\0')
148 while (buf
[in_idx
] == '/')
150 int elt_start
= in_idx
;
151 // Find next '/' or end of path.
152 while (buf
[in_idx
] != '\0' && buf
[in_idx
] != '/')
154 if (in_idx
== elt_start
)
156 // An empty component means we've reached the end.
159 int len
= in_idx
- elt_start
;
160 if (len
== 1 && buf
[in_idx
] == '.')
162 if (len
== 2 && buf
[in_idx
] == '.' && buf
[in_idx
+ 1] == '.')
164 // Found ".." component, lop off last part from existing
167 while (out_idx
> 0 && buf2
[out_idx
] != '/')
169 // Can't go up past "/".
175 // Append a real path component to the output.
177 buf2
[out_idx
++] = '/';
178 strncpy (&buf2
[out_idx
], &buf
[elt_start
], len
);
183 buf2
[out_idx
] = '\0';
186 // FIXME: what encoding to assume for file names? This affects many
188 return JvNewStringUTF (buf2
);
190 return JvNewStringUTF (buf
);
195 java::io::File::isAbsolute (void)
197 return path
->length() > 0 && path
->charAt(0) == '/';
201 java::io::File::performList (java::io::FilenameFilter
*filter
,
202 java::io::FileFilter
*fileFilter
,
203 java::lang::Class
*result_type
)
205 /* Some systems have dirent.h, but no directory reading functions like
207 #if defined(HAVE_DIRENT_H) && defined(HAVE_OPENDIR)
208 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
209 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
212 DIR *dir
= opendir (buf
);
216 java::util::ArrayList
*list
= new java::util::ArrayList ();
218 #ifdef HAVE_READDIR_R
219 int name_max
= pathconf (buf
, _PC_NAME_MAX
);
220 char dbuf
[sizeof (struct dirent
) + name_max
+ 1];
221 while (readdir_r (dir
, (struct dirent
*) dbuf
, &d
) == 0 && d
!= NULL
)
222 #else /* HAVE_READDIR_R */
223 while ((d
= readdir (dir
)) != NULL
)
224 #endif /* HAVE_READDIR_R */
226 // Omit "." and "..".
227 if (d
->d_name
[0] == '.'
228 && (d
->d_name
[1] == '\0'
229 || (d
->d_name
[1] == '.' && d
->d_name
[2] == '\0')))
232 jstring name
= JvNewStringUTF (d
->d_name
);
233 if (filter
&& ! filter
->accept(this, name
))
236 if (result_type
== &java::io::File::class$
)
238 java::io::File
*file
= new java::io::File (this, name
);
239 if (fileFilter
&& ! fileFilter
->accept(file
))
250 jobjectArray ret
= JvNewObjectArray (list
->size(), result_type
, NULL
);
253 #else /* HAVE_DIRENT_H && HAVE_OPENDIR */
255 #endif /* HAVE_DIRENT_H && HAVE_OPENDIR */
259 java::io::File::performMkdir (void)
261 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
262 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
266 return ::mkdir (buf
, 0755) == 0;
273 java::io::File::performSetReadOnly (void)
275 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
276 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
279 #if defined (HAVE_STAT) && defined (HAVE_CHMOD)
281 if (::stat (buf
, &sb
))
284 if (::chmod(buf
, sb
.st_mode
& 0555))
292 JArray
< ::java::io::File
*>*
293 java::io::File::performListRoots ()
295 ::java::io::File
*f
= new ::java::io::File (JvNewStringLatin1 ("/"));
296 JArray
<java::io::File
*> *unixroot
297 = reinterpret_cast <JArray
<java::io::File
*>*>
298 (JvNewObjectArray (1, &java::io::File::class$
, f
));
299 elements (unixroot
) [0] = f
;
304 java::io::File::performRenameTo (File
*dest
)
306 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
307 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
310 = (char *) __builtin_alloca (JvGetStringUTFLength (dest
->path
) + 1);
311 total
= JvGetStringUTFRegion (dest
->path
, 0, dest
->path
->length(), buf2
);
315 return ::rename (buf
, buf2
) == 0;
322 java::io::File::performSetLastModified (jlong time
)
327 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
328 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
331 tb
.actime
= time
/ 1000;
332 tb
.modtime
= time
/ 1000;
333 return ::utime (buf
, &tb
);
340 java::io::File::performCreate (void)
342 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
343 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
346 int fd
= ::open (buf
, O_CREAT
| O_EXCL
, 0644);
352 throw new IOException (JvNewStringLatin1 (strerror (errno
)));
362 java::io::File::performDelete (void)
364 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
365 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
372 if (errno
== ENOTDIR
)
374 return ::unlink (buf
) == 0;
375 #endif // HAVE_UNLINK
380 java::io::File::init_native ()
382 maxPathLen
= MAXPATHLEN
;
383 caseSensitive
= true;