blob: c217ea26b8014a0ab6dcaa75036e8db7104b3620 [file] [log] [blame]
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Elliott Hughesabf945f2010-06-03 19:55:20 -070018#define LOG_TAG "File"
19
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080020#include "JNIHelp.h"
Elliott Hughesa9f5c162010-06-16 16:32:18 -070021#include "JniConstants.h"
Elliott Hughesfb85a3a2011-01-16 16:06:11 -080022#include "JniException.h"
Elliott Hughes99c59bf2010-05-17 16:22:04 -070023#include "ScopedPrimitiveArray.h"
Elliott Hughesaaacdb02010-07-21 16:32:07 -070024#include "ScopedUtfChars.h"
Elliott Hughes95101d32010-11-05 10:49:14 -070025#include "readlink.h"
Elliott Hughesddafeb12011-02-18 15:14:29 -080026#include "toStringArray.h"
Elliott Hughes95101d32010-11-05 10:49:14 -070027
28#include <string>
Elliott Hughesddafeb12011-02-18 15:14:29 -080029#include <vector>
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080030
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080031#include <dirent.h>
32#include <errno.h>
Elliott Hughes08ec8fd2010-03-12 14:46:47 -080033#include <fcntl.h>
34#include <stdlib.h>
35#include <string.h>
36#include <sys/stat.h>
Elliott Hughes08ec8fd2010-03-12 14:46:47 -080037#include <sys/types.h>
38#include <time.h>
39#include <unistd.h>
40#include <utime.h>
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080041
Elliott Hughesaaacdb02010-07-21 16:32:07 -070042static jstring File_readlink(JNIEnv* env, jclass, jstring javaPath) {
43 ScopedUtfChars path(env, javaPath);
44 if (path.c_str() == NULL) {
Elliott Hughes64101122010-07-12 09:53:54 -070045 return NULL;
46 }
Elliott Hughes1326cfc2009-11-20 23:02:07 -080047
Elliott Hughes95101d32010-11-05 10:49:14 -070048 std::string result;
49 if (!readlink(path.c_str(), result)) {
50 jniThrowIOException(env, errno);
51 return NULL;
Elliott Hughes1326cfc2009-11-20 23:02:07 -080052 }
Elliott Hughes95101d32010-11-05 10:49:14 -070053 return env->NewStringUTF(result.c_str());
54}
55
56static jstring File_realpath(JNIEnv* env, jclass, jstring javaPath) {
57 ScopedUtfChars path(env, javaPath);
58 if (path.c_str() == NULL) {
59 return NULL;
60 }
61
62 extern bool realpath(const char* path, std::string& resolved);
63 std::string result;
64 if (!realpath(path.c_str(), result)) {
65 jniThrowIOException(env, errno);
66 return NULL;
67 }
68 return env->NewStringUTF(result.c_str());
Elliott Hughes1326cfc2009-11-20 23:02:07 -080069}
70
Elliott Hughesaaacdb02010-07-21 16:32:07 -070071static jboolean File_setLastModifiedImpl(JNIEnv* env, jclass, jstring javaPath, jlong ms) {
72 ScopedUtfChars path(env, javaPath);
73 if (path.c_str() == NULL) {
Elliott Hughes64101122010-07-12 09:53:54 -070074 return JNI_FALSE;
75 }
Elliott Hughes99c59bf2010-05-17 16:22:04 -070076
Elliott Hughes1326cfc2009-11-20 23:02:07 -080077 // We want to preserve the access time.
78 struct stat sb;
Elliott Hughesaaacdb02010-07-21 16:32:07 -070079 if (stat(path.c_str(), &sb) == -1) {
Elliott Hughes1326cfc2009-11-20 23:02:07 -080080 return JNI_FALSE;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080081 }
Elliott Hughes99c59bf2010-05-17 16:22:04 -070082
Elliott Hughes1326cfc2009-11-20 23:02:07 -080083 // TODO: we could get microsecond resolution with utimes(3), "legacy" though it is.
84 utimbuf times;
85 times.actime = sb.st_atime;
86 times.modtime = static_cast<time_t>(ms / 1000);
Elliott Hughesaaacdb02010-07-21 16:32:07 -070087 return (utime(path.c_str(), &times) == 0);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080088}
89
Elliott Hughesf226fd42009-12-10 13:18:35 -080090// Iterates over the filenames in the given directory.
91class ScopedReaddir {
92public:
93 ScopedReaddir(const char* path) {
94 mDirStream = opendir(path);
95 mIsBad = (mDirStream == NULL);
Elliott Hughes1326cfc2009-11-20 23:02:07 -080096 }
Elliott Hughesf226fd42009-12-10 13:18:35 -080097
Elliott Hughes1326cfc2009-11-20 23:02:07 -080098 ~ScopedReaddir() {
Elliott Hughesf226fd42009-12-10 13:18:35 -080099 if (mDirStream != NULL) {
100 closedir(mDirStream);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800101 }
102 }
Elliott Hughesf226fd42009-12-10 13:18:35 -0800103
104 // Returns the next filename, or NULL.
105 const char* next() {
Elliott Hughese9406612012-04-16 15:38:05 -0700106 if (mIsBad) {
107 return NULL;
108 }
Elliott Hughes46cbaab2012-10-26 15:13:02 -0700109 errno = 0;
110 dirent* result = readdir(mDirStream);
111 if (result != NULL) {
112 return result->d_name;
Elliott Hughesf226fd42009-12-10 13:18:35 -0800113 }
Elliott Hughes46cbaab2012-10-26 15:13:02 -0700114 if (errno != 0) {
115 mIsBad = true;
116 }
117 return NULL;
Elliott Hughes1326cfc2009-11-20 23:02:07 -0800118 }
Elliott Hughesf226fd42009-12-10 13:18:35 -0800119
120 // Has an error occurred on this stream?
121 bool isBad() const {
122 return mIsBad;
123 }
124
125private:
126 DIR* mDirStream;
Elliott Hughesf226fd42009-12-10 13:18:35 -0800127 bool mIsBad;
Elliott Hughes7ca6fd02010-03-29 20:51:48 -0700128
129 // Disallow copy and assignment.
130 ScopedReaddir(const ScopedReaddir&);
131 void operator=(const ScopedReaddir&);
Elliott Hughes1326cfc2009-11-20 23:02:07 -0800132};
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800133
Elliott Hughesddafeb12011-02-18 15:14:29 -0800134typedef std::vector<std::string> DirEntries;
Elliott Hughesf226fd42009-12-10 13:18:35 -0800135
136// Reads the directory referred to by 'pathBytes', adding each directory entry
137// to 'entries'.
Elliott Hughesaaacdb02010-07-21 16:32:07 -0700138static bool readDirectory(JNIEnv* env, jstring javaPath, DirEntries& entries) {
139 ScopedUtfChars path(env, javaPath);
140 if (path.c_str() == NULL) {
Elliott Hughes64101122010-07-12 09:53:54 -0700141 return false;
142 }
143
Elliott Hughesaaacdb02010-07-21 16:32:07 -0700144 ScopedReaddir dir(path.c_str());
Elliott Hughesf226fd42009-12-10 13:18:35 -0800145 const char* filename;
146 while ((filename = dir.next()) != NULL) {
147 if (strcmp(filename, ".") != 0 && strcmp(filename, "..") != 0) {
Elliott Hughesddafeb12011-02-18 15:14:29 -0800148 // TODO: this hides allocation failures from us. Push directory iteration up into Java?
149 entries.push_back(filename);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800150 }
Elliott Hughesf226fd42009-12-10 13:18:35 -0800151 }
Elliott Hughese9406612012-04-16 15:38:05 -0700152 return !dir.isBad();
Elliott Hughesf226fd42009-12-10 13:18:35 -0800153}
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800154
Elliott Hughesaaacdb02010-07-21 16:32:07 -0700155static jobjectArray File_listImpl(JNIEnv* env, jclass, jstring javaPath) {
Elliott Hughesf226fd42009-12-10 13:18:35 -0800156 // Read the directory entries into an intermediate form.
Elliott Hughesddafeb12011-02-18 15:14:29 -0800157 DirEntries entries;
158 if (!readDirectory(env, javaPath, entries)) {
Elliott Hughesf226fd42009-12-10 13:18:35 -0800159 return NULL;
160 }
161 // Translate the intermediate form into a Java String[].
Elliott Hughesddafeb12011-02-18 15:14:29 -0800162 return toStringArray(env, entries);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800163}
164
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800165static JNINativeMethod gMethods[] = {
Elliott Hughese22935d2010-08-12 17:27:27 -0700166 NATIVE_METHOD(File, listImpl, "(Ljava/lang/String;)[Ljava/lang/String;"),
Elliott Hughese22935d2010-08-12 17:27:27 -0700167 NATIVE_METHOD(File, readlink, "(Ljava/lang/String;)Ljava/lang/String;"),
Elliott Hughes95101d32010-11-05 10:49:14 -0700168 NATIVE_METHOD(File, realpath, "(Ljava/lang/String;)Ljava/lang/String;"),
Elliott Hughese22935d2010-08-12 17:27:27 -0700169 NATIVE_METHOD(File, setLastModifiedImpl, "(Ljava/lang/String;J)Z"),
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800170};
Elliott Hughes7cd67602012-05-03 17:21:04 -0700171void register_java_io_File(JNIEnv* env) {
172 jniRegisterNativeMethods(env, "java/io/File", gMethods, NELEM(gMethods));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800173}