|
1 /* |
|
2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Handler File IO Operations |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <errno.h> |
|
19 #include <fcntl.h> |
|
20 #include <locale.h> |
|
21 #include <unistd.h> |
|
22 #include <string> |
|
23 |
|
24 #include "javacommonutils.h" |
|
25 #include "jniarrayutils.h" |
|
26 #include "logger.h" |
|
27 |
|
28 #include "nativefileiohandler.h" |
|
29 |
|
30 using namespace std; |
|
31 using namespace java::util; |
|
32 using namespace java::fileutils; |
|
33 |
|
34 NativeFileIOHandler::NativeFileIOHandler(const std::wstring aName) |
|
35 { |
|
36 // Set the current locale to suit unicode for entire process |
|
37 setlocale(LC_ALL, ""); |
|
38 mFileName = aName; |
|
39 mFileDescriptor = 0; |
|
40 mClosedTemporarily = false; |
|
41 |
|
42 // Setting to -1 implies reading is not being done. |
|
43 // On call to openForReading, set this to 0 and increment on subsequent reads |
|
44 mReadPosition = -1; |
|
45 |
|
46 // Setting to -1 implies writing is not being done. |
|
47 // On call to openForWriting, set this to 0 and increment on subsequent writes |
|
48 mWritePosition = -1; |
|
49 } |
|
50 |
|
51 NativeFileIOHandler::~NativeFileIOHandler() |
|
52 { |
|
53 // Set the current locale to suit unicode for entire process |
|
54 if (mFileDescriptor) |
|
55 { |
|
56 close(mFileDescriptor); |
|
57 } |
|
58 } |
|
59 |
|
60 long NativeFileIOHandler::skip(const long aOffset) |
|
61 { |
|
62 JELOG2(EJavaFile); |
|
63 |
|
64 handleReopenCase(); |
|
65 |
|
66 // lseek can set the offset beyond end of file. |
|
67 // but there will be no scenario where read position goes beyond end of file. |
|
68 |
|
69 // First set file offset to read position. |
|
70 int newOffset = lseek(mFileDescriptor, mReadPosition, SEEK_SET); |
|
71 |
|
72 if (newOffset < 0) |
|
73 { |
|
74 WLOG1(EJavaFile, "NativeFileIOHandler::skip: Seek failure. %d", errno); |
|
75 return 0; |
|
76 } |
|
77 else |
|
78 { |
|
79 // Now set the file offset in relation to the current read position. |
|
80 newOffset = lseek(mFileDescriptor, aOffset, SEEK_CUR); |
|
81 if (newOffset < 0) |
|
82 { |
|
83 WLOG1(EJavaFile, "NativeFileIOHandler::skip: Seek failure. %d", |
|
84 errno); |
|
85 return 0; |
|
86 } |
|
87 } |
|
88 |
|
89 long retVal = newOffset - mReadPosition; |
|
90 mReadPosition = newOffset; |
|
91 return retVal; |
|
92 } |
|
93 |
|
94 int NativeFileIOHandler::readBytes(char* aBuffer, int aLength) |
|
95 { |
|
96 JELOG2(EJavaFile); |
|
97 |
|
98 // Throws exception in case of errors. |
|
99 handleReopenCase(); |
|
100 |
|
101 // lseek can set the offset beyond end of file. |
|
102 // but there will be no scenario where read position goes beyond end of file. |
|
103 int error = lseek(mFileDescriptor, mReadPosition, SEEK_SET); |
|
104 |
|
105 if (error < 0) |
|
106 { |
|
107 WLOG2( |
|
108 EJavaFile, |
|
109 "NativeFileIOHandler::readBytes:Seek failure. Read aborted:%d : Seek to: %d", |
|
110 errno, mReadPosition); |
|
111 // Errno cannot be thrown in S60. Causes random crashes. |
|
112 // So copy and throw. |
|
113 int err = errno; |
|
114 throw err; |
|
115 } |
|
116 |
|
117 int bytesRead = read(mFileDescriptor, aBuffer, aLength); |
|
118 if (bytesRead < 0) |
|
119 { |
|
120 LOG1(EJavaFile, EInfo, |
|
121 "NativeFileIOHandler::readBytes: Read failure: %d", errno); |
|
122 int err = errno; |
|
123 throw err; |
|
124 } |
|
125 |
|
126 // Adding 0 does no harm ;-) |
|
127 mReadPosition += bytesRead; |
|
128 return bytesRead; |
|
129 } |
|
130 |
|
131 int NativeFileIOHandler::writeBytes(char* aBuffer, int aLength) |
|
132 { |
|
133 JELOG2(EJavaFile); |
|
134 |
|
135 // Throws exception in case of error |
|
136 handleReopenCase(); |
|
137 |
|
138 // lseek can set the offset beyond end of file. |
|
139 // but there will be no scenario where read position goes beyond end of file. |
|
140 int error = lseek(mFileDescriptor, mWritePosition, SEEK_SET); |
|
141 if (error < 0) |
|
142 { |
|
143 WLOG1( |
|
144 EJavaFile, |
|
145 "NativeFileIOHandler::writeBytes: Seek failure. Write aborted: %d", |
|
146 errno); |
|
147 // Errno cannot be thrown in S60. Causes random crashes. |
|
148 // So copy and throw. |
|
149 int err = errno; |
|
150 throw err; |
|
151 } |
|
152 |
|
153 int bytesWritten = write(mFileDescriptor, aBuffer, aLength); |
|
154 if (bytesWritten <= 0) |
|
155 { |
|
156 LOG1(EJavaFile, EInfo, |
|
157 "NativeFileIOHandler::writeBytes: Write failure: %d", errno); |
|
158 int err = errno; |
|
159 throw err; |
|
160 } |
|
161 |
|
162 mWritePosition += bytesWritten; |
|
163 return bytesWritten; |
|
164 } |
|
165 |
|
166 void NativeFileIOHandler::stopReading() |
|
167 { |
|
168 JELOG2(EJavaFile); |
|
169 mReadPosition = -1; |
|
170 closeStream(); |
|
171 } |
|
172 |
|
173 void NativeFileIOHandler::stopWriting() |
|
174 { |
|
175 JELOG2(EJavaFile); |
|
176 mWritePosition = -1; |
|
177 closeStream(); |
|
178 } |
|
179 |
|
180 void NativeFileIOHandler::closeStream() |
|
181 { |
|
182 JELOG2(EJavaFile); |
|
183 if ((-1 == mReadPosition) && (-1 == mWritePosition)) |
|
184 { |
|
185 close(mFileDescriptor); |
|
186 mFileDescriptor = 0; |
|
187 } |
|
188 } |
|
189 |
|
190 void NativeFileIOHandler::openForReading() |
|
191 { |
|
192 JELOG2(EJavaFile); |
|
193 |
|
194 if (!mFileDescriptor) |
|
195 { |
|
196 // it will never come here if it is not a file. |
|
197 // so, if there is a trailing slash, remove it. |
|
198 char ch = mFileName.at(mFileName.length() - 1); |
|
199 if (ch == '\\' || ch == '/') |
|
200 { |
|
201 mFileName = mFileName.substr(0, mFileName.length() - 1); |
|
202 } |
|
203 |
|
204 char* utf8Name = JavaCommonUtils::wstringToUtf8(mFileName); |
|
205 if (access(utf8Name, R_OK) < 0) |
|
206 { |
|
207 // We do not have write access |
|
208 delete[] utf8Name; |
|
209 ELOG(EJavaFile, |
|
210 "NativeFileUtils::OpenForReading: Exiting in between. no read permission"); |
|
211 int error = errno; |
|
212 throw error; |
|
213 } |
|
214 mFileDescriptor = open(utf8Name, O_RDWR); |
|
215 |
|
216 // If open fails with Read Write mode, try read mode atleast. |
|
217 if (mFileDescriptor < 0) |
|
218 { |
|
219 mFileDescriptor = open(utf8Name, O_RDONLY); |
|
220 } |
|
221 |
|
222 delete[] utf8Name; |
|
223 if (mFileDescriptor < 0) |
|
224 { |
|
225 // There is some problem opening the file. Throw the cause for error. |
|
226 mFileDescriptor = 0; |
|
227 ELOG( |
|
228 EJavaFile, |
|
229 "NativeFileUtils::OpenForReading: Exiting in between unable to open in read only"); |
|
230 int error = errno; |
|
231 throw error; |
|
232 } |
|
233 } |
|
234 |
|
235 mReadPosition = 0; |
|
236 } |
|
237 |
|
238 void NativeFileIOHandler::openForWriting(const long aOffset) |
|
239 { |
|
240 JELOG2(EJavaFile); |
|
241 char* utf8Name = JavaCommonUtils::wstringToUtf8(mFileName); |
|
242 |
|
243 if (access(utf8Name, W_OK) < 0) |
|
244 { |
|
245 WLOG(EJavaFile, |
|
246 "NativeFileIOHandler::openForWriting: Access not allowed"); |
|
247 // We do not have write access |
|
248 delete[] utf8Name; |
|
249 int error = errno; |
|
250 throw error; |
|
251 } |
|
252 |
|
253 if (!mFileDescriptor) |
|
254 { |
|
255 // it will never come here if it is not a file. |
|
256 // so, if there is a trailing slash, remove it. |
|
257 char ch = mFileName.at(mFileName.length() - 1); |
|
258 if (ch == '\\' || ch == '/') |
|
259 { |
|
260 mFileName = mFileName.substr(0, mFileName.length() - 1); |
|
261 } |
|
262 |
|
263 mFileDescriptor = open(utf8Name, O_RDWR); |
|
264 |
|
265 if (mFileDescriptor < 0) |
|
266 { |
|
267 delete[] utf8Name; |
|
268 mFileDescriptor = 0; |
|
269 int error = errno; |
|
270 throw error; |
|
271 } |
|
272 } |
|
273 |
|
274 mWritePosition = 0; |
|
275 if (aOffset > 0) |
|
276 { |
|
277 // We will need to stat the file and find out its size just to make sure |
|
278 // lseek does not set the offset to beyond end of file. |
|
279 struct stat fileStat; |
|
280 int error = lstat(utf8Name, &fileStat); |
|
281 |
|
282 if (error < 0) |
|
283 { |
|
284 int error = errno; |
|
285 throw error; |
|
286 } |
|
287 long fileSize = fileStat.st_size; |
|
288 |
|
289 if (aOffset >= fileSize) |
|
290 { |
|
291 // Move to end of file |
|
292 if (lseek(mFileDescriptor, 0, SEEK_END) < 0) |
|
293 { |
|
294 delete[] utf8Name; |
|
295 int error = errno; |
|
296 throw error; |
|
297 } |
|
298 mWritePosition = fileSize; |
|
299 } |
|
300 else |
|
301 { |
|
302 // Move to given offset |
|
303 if (lseek(mFileDescriptor, aOffset, SEEK_SET) < 0) |
|
304 { |
|
305 delete[] utf8Name; |
|
306 int error = errno; |
|
307 throw error; |
|
308 } |
|
309 mWritePosition = aOffset; |
|
310 } |
|
311 } |
|
312 delete[] utf8Name; |
|
313 } |
|
314 |
|
315 void NativeFileIOHandler::closeFileToReopen() |
|
316 { |
|
317 JELOG2(EJavaFile); |
|
318 |
|
319 // We dont try to synchronize here. It must be done from java. |
|
320 // In case of multithreaded apps, set hidden should not be done while read |
|
321 // is in progress. |
|
322 if (mFileDescriptor) |
|
323 { |
|
324 LOG(EJavaFile, EInfo, |
|
325 "NativeFileUtils::closeFileToReopen: Closing already open Files"); |
|
326 LOG1(EJavaFile, EInfo, " Current Read Offset: %ld", |
|
327 mReadPosition); |
|
328 LOG1(EJavaFile, EInfo, " Current Write Offset: %ld", |
|
329 mWritePosition); |
|
330 mClosedTemporarily = true; |
|
331 close(mFileDescriptor); |
|
332 mFileDescriptor = 0; |
|
333 } |
|
334 } |
|
335 |
|
336 void NativeFileIOHandler::handleReopenCase() |
|
337 { |
|
338 JELOG2(EJavaFile); |
|
339 if (!mClosedTemporarily) |
|
340 { |
|
341 return; |
|
342 } |
|
343 |
|
344 if ((-1 == mWritePosition) && (-1 == mReadPosition)) |
|
345 { |
|
346 return; |
|
347 } |
|
348 |
|
349 if (mWritePosition > -1) |
|
350 { |
|
351 LOG(EJavaFile, EInfo, |
|
352 "NativeFileUtils::handleReopenCase: Reopening for write"); |
|
353 long curWritePos = mWritePosition; |
|
354 openForWriting(curWritePos); |
|
355 } |
|
356 else if (mReadPosition > -1) |
|
357 { |
|
358 LOG(EJavaFile, EInfo, |
|
359 "NativeFileUtils::handleReopenCase: Reopening for read"); |
|
360 long curReadPos = mReadPosition; |
|
361 openForReading(); |
|
362 mReadPosition = curReadPos; |
|
363 } |
|
364 |
|
365 LOG(EJavaFile, EInfo, "NativeFileUtils::handleReopenCase: File Open"); |
|
366 LOG1(EJavaFile, EInfo, " Setting Read Offset: %ld", mReadPosition); |
|
367 LOG1(EJavaFile, EInfo, " Setting Write Offset: %ld", mWritePosition); |
|
368 |
|
369 mClosedTemporarily = false; |
|
370 } |
|
371 |
|
372 long NativeFileIOHandler::available() |
|
373 { |
|
374 JELOG2(EJavaFile); |
|
375 char* utf8Name = JavaCommonUtils::wstringToUtf8(mFileName); |
|
376 |
|
377 struct stat fileStat; |
|
378 int error = lstat(utf8Name, &fileStat); |
|
379 |
|
380 if (error < 0) |
|
381 { |
|
382 int error = errno; |
|
383 throw error; |
|
384 } |
|
385 long fileSize = fileStat.st_size; |
|
386 |
|
387 if (mReadPosition > 0) |
|
388 { |
|
389 return (fileSize - mReadPosition); |
|
390 } |
|
391 else |
|
392 { |
|
393 return fileSize; |
|
394 } |
|
395 } |