]>
Commit | Line | Data |
---|---|---|
f1a1591b | 1 | // natFileWin32.cc - Native part of File class for Win32. |
878885b4 | 2 | |
5c30094f | 3 | /* Copyright (C) 1998, 1999, 2002, 2003, 2012 Free Software Foundation, Inc. |
878885b4 TT |
4 | |
5 | This file is part of libgcj. | |
6 | ||
7 | This software is copyrighted work licensed under the terms of the | |
8 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for | |
9 | details. */ | |
10 | ||
11 | #include <config.h> | |
5c144158 | 12 | #include <platform.h> |
878885b4 TT |
13 | |
14 | #include <stdio.h> | |
15 | #include <string.h> | |
16 | ||
30529b03 | 17 | #undef STRICT |
878885b4 | 18 | |
878885b4 TT |
19 | #include <java/io/File.h> |
20 | #include <java/io/IOException.h> | |
21 | #include <java/util/Vector.h> | |
22 | #include <java/lang/String.h> | |
23 | #include <java/io/FilenameFilter.h> | |
27fa520d | 24 | #include <java/io/FileFilter.h> |
878885b4 TT |
25 | #include <java/lang/System.h> |
26 | ||
3ccd3d70 RM |
27 | // Java timestamps are milliseconds since the UNIX epoch (00:00:00 UTC on |
28 | // January 1, 1970) while Win32 file-times are 100-nanosecond intervals | |
29 | // since the Win32 epoch (00:00:00 UTC on January 1, 1601). The following | |
30 | // constant represents the number of milliseconds to be added to a | |
31 | // Java timestamp to base it on the Win32 epoch. | |
32 | // | |
33 | // There were 369 years between 1601 and 1970, including 89 leap years | |
34 | // (since 1700, 1800 and 1900 were not leap years): | |
35 | // | |
36 | // (89*366 + 280*365) days * 86400 seconds/day = 11644473600 seconds | |
37 | // | |
38 | #define WIN32_EPOCH_MILLIS 11644473600000LL | |
39 | ||
878885b4 | 40 | jboolean |
5c30094f | 41 | java::io::File::access (jint query) |
878885b4 | 42 | { |
83c02e38 | 43 | JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); |
5c144158 | 44 | if (!canon) |
27fa520d | 45 | return false; |
878885b4 | 46 | |
e1bea0c0 MK |
47 | JvAssert (query == READ || query == WRITE || query == EXISTS |
48 | || query == EXEC); | |
878885b4 TT |
49 | |
50 | // FIXME: Is it possible to differentiate between existing and reading? | |
51 | // If the file exists but cannot be read because of the secuirty attributes | |
52 | // on an NTFS disk this wont work (it reports it can be read but cant) | |
53 | // Could we use something from the security API? | |
5c144158 | 54 | DWORD attributes = GetFileAttributes (canon); |
e1bea0c0 MK |
55 | // FIXME: handle EXEC |
56 | if (query == EXEC) | |
57 | return false; | |
878885b4 TT |
58 | if ((query == EXISTS) || (query == READ)) |
59 | return (attributes == 0xffffffff) ? false : true; | |
60 | else | |
83c02e38 ME |
61 | return ((attributes != 0xffffffff) && |
62 | ((attributes & FILE_ATTRIBUTE_READONLY) == 0)) ? true : false; | |
878885b4 TT |
63 | } |
64 | ||
65 | jboolean | |
5c30094f | 66 | java::io::File::stat (jint query) |
878885b4 | 67 | { |
83c02e38 | 68 | JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); |
5c144158 | 69 | if (!canon) |
27fa520d | 70 | return false; |
878885b4 TT |
71 | |
72 | JvAssert (query == DIRECTORY || query == ISFILE); | |
73 | ||
5c144158 | 74 | DWORD attributes = GetFileAttributes (canon); |
878885b4 TT |
75 | if (attributes == 0xffffffff) |
76 | return false; | |
77 | ||
78 | if (query == DIRECTORY) | |
79 | return attributes & FILE_ATTRIBUTE_DIRECTORY ? true : false; | |
80 | else | |
81 | return attributes & FILE_ATTRIBUTE_DIRECTORY ? false : true; | |
82 | } | |
83 | ||
84 | jlong | |
f4047540 | 85 | java::io::File::attr (jint query) |
878885b4 | 86 | { |
83c02e38 | 87 | JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); |
5c144158 | 88 | if (!canon) |
27fa520d | 89 | return false; |
878885b4 TT |
90 | |
91 | JvAssert (query == MODIFIED || query == LENGTH); | |
92 | ||
963f08a9 RM |
93 | WIN32_FIND_DATA info; |
94 | HANDLE sHandle; | |
5c144158 | 95 | if ( ( sHandle = FindFirstFile( canon, &info)) == INVALID_HANDLE_VALUE) |
878885b4 | 96 | return 0; |
963f08a9 RM |
97 | |
98 | FindClose( sHandle); | |
99 | ||
878885b4 | 100 | if (query == LENGTH) |
3ccd3d70 RM |
101 | return ((long long)info.nFileSizeHigh) << 32 |
102 | | (unsigned long long)info.nFileSizeLow; | |
103 | else | |
104 | { | |
105 | // The file time as returned by Windows is in terms of the number | |
106 | // of 100-nanosecond intervals since 00:00:00 UTC, January 1, 1601. | |
107 | return (((((long long)info.ftLastWriteTime.dwHighDateTime) << 32) | |
108 | | ((unsigned long long)info.ftLastWriteTime.dwLowDateTime)) | |
109 | - WIN32_EPOCH_MILLIS*10000LL) / 10000LL; | |
110 | } | |
878885b4 TT |
111 | } |
112 | ||
113 | jstring | |
114 | java::io::File::getCanonicalPath (void) | |
115 | { | |
83c02e38 | 116 | JV_TEMP_STRING_WIN32 (cpath, path); |
b82183ab ME |
117 | |
118 | // If the filename is blank, use the current directory. | |
83c02e38 ME |
119 | LPCTSTR thepath = cpath.buf(); |
120 | if (*thepath == 0) | |
121 | thepath = _T("."); | |
878885b4 TT |
122 | |
123 | LPTSTR unused; | |
83c02e38 | 124 | TCHAR buf2[MAX_PATH]; |
b82183ab | 125 | if(!GetFullPathName(thepath, MAX_PATH, buf2, &unused)) |
6344da6f | 126 | throw new IOException (JvNewStringLatin1 ("GetFullPathName failed")); |
878885b4 | 127 | |
83c02e38 | 128 | return _Jv_Win32NewString (buf2); |
878885b4 TT |
129 | } |
130 | ||
131 | jboolean | |
132 | java::io::File::isAbsolute (void) | |
133 | { | |
5bedfc93 | 134 | // See if the path represents a Windows UNC network path. |
3ccd3d70 | 135 | if (path->length () > 2 |
5bedfc93 | 136 | && (path->charAt (0) == '\\') && (path->charAt (1) == '\\')) |
878885b4 | 137 | return true; |
5bedfc93 RM |
138 | |
139 | // Note that the path is not an absolute path even if it starts with | |
140 | // a '/' or a '\' because it lacks a drive specifier. | |
141 | ||
878885b4 TT |
142 | if (path->length() < 3) |
143 | return false; | |
144 | // Hard-code A-Za-z because Windows (I think) can't use non-ASCII | |
145 | // letters as drive names. | |
146 | if ((path->charAt(0) < 'a' || path->charAt(0) > 'z') | |
147 | && (path->charAt(0) < 'A' || path->charAt(0) > 'Z')) | |
148 | return false; | |
149 | return (path->charAt(1) == ':' | |
5c144158 | 150 | && (path->charAt(2) == '/' || path->charAt(2) == '\\')); |
878885b4 TT |
151 | } |
152 | ||
3ccd3d70 RM |
153 | void java::io::File::init_native () |
154 | { | |
155 | maxPathLen = MAX_PATH; | |
156 | caseSensitive = false; | |
157 | } | |
27fa520d AM |
158 | |
159 | jobjectArray | |
f4047540 | 160 | java::io::File::performList (java::io::FilenameFilter *filter, |
5c144158 ME |
161 | java::io::FileFilter *fileFilter, |
162 | java::lang::Class *clazz) | |
878885b4 | 163 | { |
27fa520d AM |
164 | jstring canon = getCanonicalPath(); |
165 | if (! canon) | |
166 | return NULL; | |
83c02e38 ME |
167 | |
168 | int len = canon->length(); | |
169 | TCHAR buf[len + 5]; | |
170 | ||
171 | JV_TEMP_STRING_WIN32(canonstr, canon); | |
172 | ||
173 | _tcscpy(buf, canonstr); | |
174 | if (buf[len - 1] == _T('\\')) | |
175 | _tcscpy (&buf[len], _T("*.*")); | |
0ced4335 | 176 | else |
83c02e38 | 177 | _tcscpy (&buf[len], _T("\\*.*")); |
878885b4 TT |
178 | |
179 | WIN32_FIND_DATA data; | |
180 | HANDLE handle = FindFirstFile (buf, &data); | |
181 | if (handle == INVALID_HANDLE_VALUE) | |
182 | return NULL; | |
183 | ||
27fa520d | 184 | java::util::Vector *vec = new java::util::Vector (); |
878885b4 TT |
185 | |
186 | do | |
187 | { | |
83c02e38 ME |
188 | if (_tcscmp (data.cFileName, _T(".")) && |
189 | _tcscmp (data.cFileName, _T(".."))) | |
878885b4 | 190 | { |
83c02e38 | 191 | jstring name = _Jv_Win32NewString (data.cFileName); |
f4047540 | 192 | |
6344da6f | 193 | if (filter && !filter->accept(this, name)) |
83c02e38 | 194 | continue; |
6344da6f | 195 | if (clazz == &java::io::File::class$) |
83c02e38 | 196 | { |
27fa520d | 197 | java::io::File *file = new java::io::File (this, name); |
6344da6f | 198 | if (fileFilter && !fileFilter->accept(file)) |
83c02e38 ME |
199 | continue; |
200 | vec->addElement (file); | |
201 | } | |
202 | else | |
203 | vec->addElement (name); | |
27fa520d | 204 | } |
878885b4 TT |
205 | } |
206 | while (FindNextFile (handle, &data)); | |
207 | ||
208 | if (GetLastError () != ERROR_NO_MORE_FILES) | |
209 | return NULL; | |
210 | ||
211 | FindClose (handle); | |
212 | ||
6344da6f | 213 | jobjectArray ret = JvNewObjectArray (vec->size(), clazz, NULL); |
878885b4 | 214 | vec->copyInto (ret); |
27fa520d | 215 | return ret; |
878885b4 TT |
216 | } |
217 | ||
e1bea0c0 MK |
218 | jboolean |
219 | java::io::File::setFilePermissions (jboolean enable, | |
220 | jboolean ownerOnly, | |
221 | jint permissions) | |
222 | { | |
223 | JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); | |
224 | if (!canon) | |
225 | return false; | |
226 | ||
227 | DWORD attrs = GetFileAttributes (canon); | |
228 | if (attrs != INVALID_FILE_ATTRIBUTES) | |
229 | { | |
230 | // FIXME: implement | |
231 | return false; | |
232 | } | |
233 | else | |
234 | return false; | |
235 | } | |
236 | ||
878885b4 TT |
237 | jboolean |
238 | java::io::File::performMkdir (void) | |
239 | { | |
83c02e38 | 240 | JV_TEMP_STRING_WIN32 (cpath, path); |
5c144158 | 241 | return (CreateDirectory(cpath, NULL)) ? true : false; |
878885b4 TT |
242 | } |
243 | ||
244 | jboolean | |
245 | java::io::File::performRenameTo (File *dest) | |
246 | { | |
83c02e38 ME |
247 | JV_TEMP_STRING_WIN32 (pathFrom, path); |
248 | JV_TEMP_STRING_WIN32 (pathTo, dest->path); | |
5c144158 | 249 | return (MoveFile(pathFrom, pathTo)) ? true : false; |
878885b4 TT |
250 | } |
251 | ||
f4047540 BM |
252 | jboolean |
253 | java::io::File::performDelete () | |
878885b4 | 254 | { |
83c02e38 | 255 | JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); |
5c144158 ME |
256 | if (!canon) |
257 | return false; | |
878885b4 | 258 | |
5c144158 | 259 | DWORD attributes = GetFileAttributes (canon); |
878885b4 TT |
260 | if (attributes == 0xffffffff) |
261 | return false; | |
262 | ||
263 | if (attributes & FILE_ATTRIBUTE_DIRECTORY) | |
5c144158 | 264 | return (RemoveDirectory (canon)) ? true : false; |
878885b4 | 265 | else |
5c144158 | 266 | return (DeleteFile (canon)) ? true : false; |
878885b4 | 267 | } |
f4047540 | 268 | |
3ccd3d70 RM |
269 | jboolean java::io::File::performCreate (void) |
270 | { | |
83c02e38 | 271 | JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); |
5c144158 ME |
272 | if (!canon) |
273 | return false; | |
3ccd3d70 | 274 | |
5c144158 | 275 | HANDLE h = CreateFile (canon, 0, 0, NULL, CREATE_NEW, |
3ccd3d70 RM |
276 | FILE_ATTRIBUTE_NORMAL, NULL); |
277 | if (h != INVALID_HANDLE_VALUE) | |
278 | { | |
279 | CloseHandle (h); | |
280 | return true; | |
281 | } | |
282 | else | |
283 | { | |
284 | if (GetLastError () == ERROR_ALREADY_EXISTS) | |
285 | return false; | |
286 | else | |
287 | throw new IOException (JvNewStringLatin1 ("CreateFile failed")); | |
288 | } | |
289 | } | |
290 | ||
291 | jboolean java::io::File::performSetReadOnly () | |
292 | { | |
83c02e38 | 293 | JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); |
5c144158 ME |
294 | if (!canon) |
295 | return false; | |
3ccd3d70 | 296 | |
5c144158 | 297 | DWORD attrs = GetFileAttributes (canon); |
3ccd3d70 RM |
298 | if (attrs != INVALID_FILE_ATTRIBUTES) |
299 | { | |
5c144158 | 300 | if (SetFileAttributes (canon, attrs | FILE_ATTRIBUTE_READONLY) != 0) |
3ccd3d70 RM |
301 | return true; |
302 | else | |
303 | return false; | |
304 | } | |
305 | else | |
306 | return false; | |
307 | } | |
308 | ||
309 | jboolean java::io::File::performSetLastModified (jlong time) | |
310 | { | |
83c02e38 | 311 | JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); |
5c144158 ME |
312 | if (!canon) |
313 | return false; | |
3ccd3d70 RM |
314 | |
315 | FILETIME modTime; | |
316 | long long mTime100ns = ((long long) time /* Ha! */ | |
317 | + WIN32_EPOCH_MILLIS) * 10000LL; | |
318 | ||
319 | modTime.dwLowDateTime = (DWORD) mTime100ns; | |
320 | modTime.dwHighDateTime = (DWORD) (mTime100ns >> 32); | |
321 | ||
322 | jboolean retVal = false; | |
5c144158 | 323 | HANDLE h = CreateFile (canon, FILE_WRITE_ATTRIBUTES, |
3ccd3d70 RM |
324 | FILE_SHARE_READ | FILE_SHARE_WRITE, |
325 | NULL, OPEN_EXISTING, 0, NULL); | |
326 | ||
327 | if (h != INVALID_HANDLE_VALUE) | |
328 | { | |
329 | if (SetFileTime (h, NULL, &modTime, &modTime) != 0) | |
330 | retVal = true; | |
331 | ||
332 | CloseHandle (h); | |
333 | } | |
334 | ||
335 | return retVal; | |
336 | } | |
337 | ||
338 | JArray<java::io::File*>* java::io::File::performListRoots () | |
339 | { | |
340 | DWORD drivesBitmap = GetLogicalDrives (); | |
341 | DWORD mask; | |
342 | ||
343 | // Possible drive letters are from ASCII 'A'-'Z'. | |
344 | int numDrives = 0; | |
345 | mask = 1; | |
346 | for (int i = 0; i < 26; i++) | |
347 | { | |
348 | if ((drivesBitmap & mask) != 0) | |
349 | numDrives++; | |
350 | mask <<= 1; | |
351 | } | |
352 | ||
353 | JArray<java::io::File *> *roots | |
354 | = reinterpret_cast <JArray<java::io::File *>*> | |
355 | (JvNewObjectArray (numDrives, &java::io::File::class$, NULL)); | |
356 | ||
357 | ::java::io::File **rootsArray = elements (roots); | |
358 | ||
359 | char aDriveRoot[] = {'A', ':', '\\', '\0'}; | |
360 | mask = 1; | |
361 | for (int i = 0, j = 0; i < 26; i++) | |
362 | { | |
363 | if ((drivesBitmap & mask) != 0) | |
364 | { | |
365 | rootsArray[j] | |
366 | = new ::java::io::File (JvNewStringLatin1 (aDriveRoot)); | |
367 | j++; | |
368 | } | |
369 | mask <<= 1; | |
370 | aDriveRoot[0]++; | |
371 | } | |
372 | ||
373 | return roots; | |
374 | } |