1 // natFile.cc - Native part of File class for POSIX.
3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2006
4 Free Software Foundation
6 This file is part of libgcj.
8 This software is copyrighted work licensed under the terms of the
9 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
16 #include <sys/param.h>
18 #include <sys/types.h>
32 #include <java/io/File.h>
33 #include <java/io/IOException.h>
34 #include <java/util/ArrayList.h>
35 #include <java/lang/String.h>
36 #include <java/io/FilenameFilter.h>
37 #include <java/io/FileFilter.h>
38 #include <java/lang/System.h>
41 java::io::File::_access (jint query
)
43 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
44 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
46 JvAssert (query
== READ
|| query
== WRITE
|| query
== EXISTS
52 else if (query
== WRITE
)
54 else if (query
== EXISTS
)
58 return ::access (buf
, mode
) == 0;
65 java::io::File::_stat (jint query
)
67 if (query
== ISHIDDEN
)
68 return getName()->charAt(0) == '.';
71 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
72 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
76 if (::stat (buf
, &sb
))
79 JvAssert (query
== DIRECTORY
|| query
== ISFILE
);
80 jboolean r
= S_ISDIR (sb
.st_mode
);
81 return query
== DIRECTORY
? r
: ! r
;
88 java::io::File::attr (jint query
)
90 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
91 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
96 // FIXME: not sure about return value here.
97 if (::stat (buf
, &sb
))
100 JvAssert (query
== MODIFIED
|| query
== LENGTH
);
101 return query
== MODIFIED
? (jlong
)sb
.st_mtime
* 1000 : sb
.st_size
;
103 // There's no good choice here.
108 // These two methods are used to maintain dynamically allocated
109 // buffers for getCanonicalPath without the overhead of calling
110 // realloc every time a buffer is modified. Buffers are sized
111 // at the smallest multiple of CHUNKSIZ that is greater than or
112 // equal to the desired length. The default CHUNKSIZ is 256,
113 // longer than most paths, so in most cases a getCanonicalPath
114 // will require only one malloc per buffer.
117 #define CHUNKSIZ (1 << CHUNKLOG)
120 nextChunkSize (int size
)
122 return ((size
>> CHUNKLOG
) + ((size
& (CHUNKSIZ
- 1)) ? 1 : 0)) << CHUNKLOG
;
126 maybeGrowBuf (char *buf
, int *size
, int required
)
128 if (required
> *size
)
130 *size
= nextChunkSize (required
);
131 buf
= (char *) _Jv_Realloc (buf
, *size
);
136 // Return a canonical representation of the pathname of this file. On
137 // the GNU system this involves the removal of redundant separators,
138 // references to "." and "..", and symbolic links.
140 // The conversion proceeds on a component-by-component basis: symbolic
141 // links and references to ".." are resolved as and when they occur.
142 // This means that if "/foo/bar" is a symbolic link to "/baz" then the
143 // canonical form of "/foo/bar/.." is "/" and not "/foo".
145 // In order to mimic the behaviour of proprietary JVMs, non-existant
146 // path components are allowed (a departure from the normal GNU system
147 // convention). This means that if "/foo/bar" is a symbolic link to
148 // "/baz", the canonical form of "/non-existant-directory/../foo/bar"
152 java::io::File::getCanonicalPath (void)
154 jstring path
= getAbsolutePath ();
156 int len
= JvGetStringUTFLength (path
);
157 int srcl
= nextChunkSize (len
+ 1);
158 char *src
= (char *) _Jv_Malloc (srcl
);
159 JvGetStringUTFRegion (path
, 0, path
->length(), src
);
163 int dstl
= nextChunkSize (2);
164 char *dst
= (char *) _Jv_Malloc (dstl
);
168 bool fschecks
= true;
170 while (src
[srci
] != '\0')
173 while (src
[srci
] == '/')
177 while (src
[srci
] != '/' && src
[srci
] != '\0')
184 // Handle "." and "..".
185 if (len
== 1 && src
[tmpi
] == '.')
187 if (len
== 2 && src
[tmpi
] == '.' && src
[tmpi
+ 1] == '.')
189 while (dsti
> 1 && dst
[dsti
- 1] != '/')
193 // Reenable filesystem checking if disabled, as we might
194 // have reversed over whatever caused the problem before.
195 // At least one proprietary JVM has inconsistencies because
196 // it does not do this.
201 // Handle real path components.
202 dst
= maybeGrowBuf (dst
, &dstl
, dsti
+ (dsti
> 1 ? 1 : 0) + len
+ 1);
203 int dsti_save
= dsti
;
206 strncpy (&dst
[dsti
], &src
[tmpi
], len
);
208 if (fschecks
== false)
211 #if defined (HAVE_LSTAT) && defined (HAVE_READLINK)
214 if (::lstat (dst
, &sb
) == 0)
216 if (S_ISLNK (sb
.st_mode
))
219 char *tmp
= (char *) _Jv_Malloc (tmpl
);
223 tmpi
= ::readlink (dst
, tmp
, tmpl
);
229 throw new IOException (
230 JvNewStringLatin1 ("readlink failed"));
235 tmp
= (char *) _Jv_Realloc (tmp
, tmpl
);
238 // Prepend the link's path to src.
239 tmp
= maybeGrowBuf (tmp
, &tmpl
, tmpi
+ strlen (&src
[srci
]) + 1);
240 strcpy(&tmp
[tmpi
], &src
[srci
]);
246 // Either replace or append dst depending on whether the
247 // link is relative or absolute.
248 dsti
= src
[0] == '/' ? 1 : dsti_save
;
253 // Something doesn't exist, or we don't have permission to
254 // read it, or a previous path component is a directory, or
255 // a symlink is looped. Whatever, we can't check the
256 // filesystem any more.
259 #endif // HAVE_LSTAT && HAVE_READLINK
263 // FIXME: what encoding to assume for file names? This affects many
265 path
= JvNewStringUTF (dst
);
272 java::io::File::isAbsolute (void)
274 return path
->length() > 0 && path
->charAt(0) == '/';
278 java::io::File::performList (java::io::FilenameFilter
*filter
,
279 java::io::FileFilter
*fileFilter
,
280 java::lang::Class
*result_type
)
282 /* Some systems have dirent.h, but no directory reading functions like
284 #if defined(HAVE_DIRENT_H) && defined(HAVE_OPENDIR)
285 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
286 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
289 DIR *dir
= opendir (buf
);
293 java::util::ArrayList
*list
= new java::util::ArrayList ();
295 #if defined(HAVE_READDIR_R) && defined(_POSIX_PTHREAD_SEMANTICS)
296 int name_max
= pathconf (buf
, _PC_NAME_MAX
);
297 char dbuf
[sizeof (struct dirent
) + name_max
+ 1];
298 while (readdir_r (dir
, (struct dirent
*) dbuf
, &d
) == 0 && d
!= NULL
)
299 #else /* HAVE_READDIR_R */
300 while ((d
= readdir (dir
)) != NULL
)
301 #endif /* HAVE_READDIR_R */
303 // Omit "." and "..".
304 if (d
->d_name
[0] == '.'
305 && (d
->d_name
[1] == '\0'
306 || (d
->d_name
[1] == '.' && d
->d_name
[2] == '\0')))
309 jstring name
= JvNewStringUTF (d
->d_name
);
310 if (filter
&& ! filter
->accept(this, name
))
313 if (result_type
== &java::io::File::class$
)
315 java::io::File
*file
= new java::io::File (this, name
);
316 if (fileFilter
&& ! fileFilter
->accept(file
))
327 jobjectArray ret
= JvNewObjectArray (list
->size(), result_type
, NULL
);
330 #else /* HAVE_DIRENT_H && HAVE_OPENDIR */
332 #endif /* HAVE_DIRENT_H && HAVE_OPENDIR */
336 java::io::File::performMkdir (void)
338 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
339 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
343 return ::mkdir (buf
, 0755) == 0;
350 java::io::File::setFilePermissions (jboolean enable
,
354 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
355 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
357 JvAssert (permissions
== READ
|| permissions
== WRITE
|| permissions
== EXEC
);
358 #if defined (HAVE_STAT) && defined (HAVE_CHMOD)
362 if (::stat (buf
, &sb
))
367 if (permissions
== READ
)
369 else if (permissions
== WRITE
)
371 else if (permissions
== EXEC
)
376 if (permissions
== READ
)
377 mode
|= (S_IRUSR
| S_IRGRP
| S_IROTH
);
378 else if (permissions
== WRITE
)
379 mode
|= (S_IWUSR
| S_IWGRP
| S_IWOTH
);
380 else if (permissions
== EXEC
)
381 mode
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
385 mode
= sb
.st_mode
| mode
;
387 mode
= sb
.st_mode
& ~mode
;
389 if (::chmod(buf
, mode
) < 0)
398 java::io::File::performSetReadOnly (void)
400 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
401 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
404 #if defined (HAVE_STAT) && defined (HAVE_CHMOD)
406 if (::stat (buf
, &sb
))
409 if (::chmod(buf
, sb
.st_mode
& 0555))
417 JArray
< ::java::io::File
*>*
418 java::io::File::performListRoots ()
420 ::java::io::File
*f
= new ::java::io::File (JvNewStringLatin1 ("/"));
421 JArray
<java::io::File
*> *unixroot
422 = reinterpret_cast <JArray
<java::io::File
*>*>
423 (JvNewObjectArray (1, &java::io::File::class$
, f
));
424 elements (unixroot
) [0] = f
;
429 java::io::File::performRenameTo (File
*dest
)
431 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
432 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
435 = (char *) __builtin_alloca (JvGetStringUTFLength (dest
->path
) + 1);
436 total
= JvGetStringUTFRegion (dest
->path
, 0, dest
->path
->length(), buf2
);
440 return ::rename (buf
, buf2
) == 0;
447 java::io::File::performSetLastModified (jlong time
)
452 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
453 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
456 tb
.actime
= time
/ 1000;
457 tb
.modtime
= time
/ 1000;
458 return (::utime (buf
, &tb
) == 0);
465 java::io::File::performCreate (void)
467 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
468 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
471 int fd
= ::open (buf
, O_CREAT
| O_EXCL
, 0644);
477 throw new IOException (JvNewStringLatin1 (strerror (errno
)));
487 java::io::File::performDelete (void)
489 char *buf
= (char *) __builtin_alloca (JvGetStringUTFLength (path
) + 1);
490 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), buf
);
497 if (errno
== ENOTDIR
)
499 return ::unlink (buf
) == 0;
500 #endif // HAVE_UNLINK
505 java::io::File::init_native ()
508 maxPathLen
= MAXPATHLEN
;
510 /* Some systems do not have a limit on the length of a file name,
511 the GNU system is one such example. */
514 caseSensitive
= true;