/src/libreoffice/sal/osl/unx/file.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <config_features.h> |
21 | | #include <o3tl/safeint.hxx> |
22 | | #include <o3tl/typed_flags_set.hxx> |
23 | | #include <sal/log.hxx> |
24 | | #include <osl/detail/file.h> |
25 | | #include <rtl/byteseq.h> |
26 | | #include <rtl/string.hxx> |
27 | | #include <o3tl/string_view.hxx> |
28 | | |
29 | | #include <setallowedpaths.hxx> |
30 | | |
31 | | #include "system.hxx" |
32 | | #include "createfilehandlefromfd.hxx" |
33 | | #include "file_error_transl.hxx" |
34 | | #include "file_impl.hxx" |
35 | | #include "file_url.hxx" |
36 | | #include "uunxapi.hxx" |
37 | | #include "unixerrnostring.hxx" |
38 | | |
39 | | #include <algorithm> |
40 | | #include <atomic> |
41 | | #include <cassert> |
42 | | #include <fcntl.h> |
43 | | #include <limits> |
44 | | #include <limits.h> |
45 | | #include <utility> |
46 | | |
47 | | #include <string.h> |
48 | | #include <pthread.h> |
49 | | #include <sys/mman.h> |
50 | | #include <sys/stat.h> |
51 | | #include <unistd.h> |
52 | | |
53 | | #if defined(MACOSX) |
54 | | |
55 | | #include <sys/param.h> |
56 | | #include <sys/mount.h> |
57 | | #define HAVE_O_EXLOCK |
58 | | |
59 | | #include <CoreFoundation/CoreFoundation.h> |
60 | | |
61 | | #endif /* MACOSX */ |
62 | | |
63 | | #ifdef ANDROID |
64 | | #include <osl/detail/android-bootstrap.h> |
65 | | #include <android/log.h> |
66 | | #include <android/asset_manager.h> |
67 | | #endif |
68 | | |
69 | | #include <vector> |
70 | | |
71 | | #ifdef LINUX |
72 | | #include <sys/vfs.h> |
73 | | // As documented by the kernel |
74 | | constexpr decltype(std::declval<struct statfs>().f_type) SMB_SUPER_MAGIC = 0x517B; |
75 | | constexpr decltype(std::declval<struct statfs>().f_type) CIFS_SUPER_MAGIC = 0xFF534D42; |
76 | | constexpr decltype(std::declval<struct statfs>().f_type) SMB2_SUPER_MAGIC = 0xFE534D42; |
77 | | #endif |
78 | | |
79 | | namespace { |
80 | | |
81 | | enum class State |
82 | | { |
83 | | Seekable = 1, /*< default */ |
84 | | Readable = 2, /*< default */ |
85 | | Writeable = 4, /*< open() sets, write() requires, else osl_File_E_BADF */ |
86 | | Modified = 8 /*< write() sets, flush() resets */ |
87 | | }; |
88 | | |
89 | | } |
90 | | |
91 | | template<> struct o3tl::typed_flags<State>: o3tl::is_typed_flags<State, 15> {}; |
92 | | |
93 | | namespace { |
94 | | |
95 | | struct FileHandle_Impl |
96 | | { |
97 | | pthread_mutex_t m_mutex; |
98 | | OString m_strFilePath; /*< holds native file path */ |
99 | | int m_fd; |
100 | | |
101 | | enum Kind |
102 | | { |
103 | | KIND_FD = 1, |
104 | | KIND_MEM = 2 |
105 | | }; |
106 | | int m_kind; |
107 | | /** State |
108 | | */ |
109 | | State m_state; |
110 | | |
111 | | sal_uInt64 m_size; /*< file size */ |
112 | | off_t m_offset; /*< physical offset from begin of file */ |
113 | | // m_fileptr is hit hard in some situations, where the overhead of a mutex starts to show up, so use an atomic |
114 | | std::atomic<off_t> m_fileptr; /*< logical offset from begin of file */ |
115 | | |
116 | | off_t m_bufptr; /*< buffer offset from begin of file */ |
117 | | size_t m_buflen; /*< buffer filled [0, m_bufsiz - 1] */ |
118 | | |
119 | | size_t m_bufsiz; |
120 | | sal_uInt8 * m_buffer; |
121 | | #ifdef ANDROID |
122 | | rtl_String* m_memstreambuf; /*< used for in-memory streams */ |
123 | | #endif |
124 | | |
125 | | explicit FileHandle_Impl(int fd, Kind kind = KIND_FD, OString path = "<anon>"_ostr); |
126 | | ~FileHandle_Impl(); |
127 | | |
128 | | static size_t getpagesize(); |
129 | | |
130 | | sal_uInt64 getPos() const; |
131 | | void setPos(sal_uInt64 uPos); |
132 | | |
133 | | sal_uInt64 getSize() const; |
134 | | oslFileError setSize(sal_uInt64 uSize); |
135 | | |
136 | | oslFileError readAt( |
137 | | off_t nOffset, |
138 | | void* pBuffer, |
139 | | size_t nBytesRequested, |
140 | | sal_uInt64* pBytesRead); |
141 | | |
142 | | oslFileError writeAt( |
143 | | off_t nOffset, |
144 | | void const* pBuffer, |
145 | | size_t nBytesToWrite, |
146 | | sal_uInt64* pBytesWritten); |
147 | | |
148 | | oslFileError readFileAt( |
149 | | off_t nOffset, |
150 | | void* pBuffer, |
151 | | size_t nBytesRequested, |
152 | | sal_uInt64* pBytesRead); |
153 | | |
154 | | oslFileError writeFileAt( |
155 | | off_t nOffset, |
156 | | void const* pBuffer, |
157 | | size_t nBytesToWrite, |
158 | | sal_uInt64* pBytesWritten); |
159 | | |
160 | | oslFileError readLineAt( |
161 | | off_t nOffset, |
162 | | sal_Sequence** ppSequence, |
163 | | sal_uInt64* pBytesRead); |
164 | | |
165 | | static oslFileError writeSequence_Impl( |
166 | | sal_Sequence** ppSequence, |
167 | | size_t* pnOffset, |
168 | | const void* pBuffer, |
169 | | size_t nBytes); |
170 | | |
171 | | oslFileError syncFile(); |
172 | | |
173 | | class Guard |
174 | | { |
175 | | pthread_mutex_t *m_mutex; |
176 | | |
177 | | public: |
178 | | explicit Guard(pthread_mutex_t *pMutex); |
179 | | ~Guard(); |
180 | | }; |
181 | | }; |
182 | | |
183 | | } |
184 | | |
185 | | FileHandle_Impl::Guard::Guard(pthread_mutex_t * pMutex) |
186 | 97.5M | : m_mutex(pMutex) |
187 | 97.5M | { |
188 | 97.5M | assert(m_mutex); |
189 | 97.5M | (void) pthread_mutex_lock(m_mutex); // ignoring EINVAL if a null mutex is passed ... |
190 | 97.5M | } |
191 | | |
192 | | FileHandle_Impl::Guard::~Guard() |
193 | 97.5M | { |
194 | 97.5M | assert(m_mutex); |
195 | 97.5M | (void) pthread_mutex_unlock(m_mutex); |
196 | 97.5M | } |
197 | | |
198 | | FileHandle_Impl::FileHandle_Impl(int fd, enum Kind kind, OString path) |
199 | 942k | : m_strFilePath(std::move(path)), |
200 | 942k | m_fd (fd), |
201 | 942k | m_kind (kind), |
202 | 942k | m_state (State::Seekable | State::Readable), |
203 | 942k | m_size (0), |
204 | 942k | m_offset (0), |
205 | 942k | m_fileptr (0), |
206 | 942k | m_bufptr (-1), |
207 | 942k | m_buflen (0), |
208 | 942k | m_bufsiz (0), |
209 | 942k | m_buffer (nullptr) |
210 | 942k | { |
211 | 942k | (void) pthread_mutex_init(&m_mutex, nullptr); |
212 | 942k | if (m_kind == KIND_FD) |
213 | 942k | { |
214 | 942k | size_t const pagesize = getpagesize(); |
215 | 942k | if (pagesize != size_t(-1)) |
216 | 942k | { |
217 | 942k | m_bufsiz = pagesize; |
218 | 942k | m_buffer = static_cast<sal_uInt8 *>(calloc(1, m_bufsiz)); |
219 | 942k | } |
220 | 942k | } |
221 | 942k | } |
222 | | |
223 | | FileHandle_Impl::~FileHandle_Impl() |
224 | 942k | { |
225 | 942k | if (m_kind == KIND_FD) |
226 | 942k | { |
227 | 942k | free(m_buffer); |
228 | 942k | m_buffer = nullptr; |
229 | 942k | } |
230 | | |
231 | 942k | (void) pthread_mutex_destroy(&m_mutex); // ignoring EBUSY ... |
232 | 942k | } |
233 | | |
234 | | size_t FileHandle_Impl::getpagesize() |
235 | 942k | { |
236 | 942k | return sal::static_int_cast< size_t >(::sysconf(_SC_PAGESIZE)); |
237 | 942k | } |
238 | | |
239 | | sal_uInt64 FileHandle_Impl::getPos() const |
240 | 8.08M | { |
241 | 8.08M | return sal::static_int_cast< sal_uInt64 >(m_fileptr.load()); |
242 | 8.08M | } |
243 | | |
244 | | void FileHandle_Impl::setPos(sal_uInt64 uPos) |
245 | 55.2M | { |
246 | 55.2M | m_fileptr = sal::static_int_cast< off_t >(uPos); |
247 | 55.2M | } |
248 | | |
249 | | sal_uInt64 FileHandle_Impl::getSize() const |
250 | 7.63M | { |
251 | 7.63M | off_t const bufend = std::max(off_t(0), m_bufptr) + m_buflen; |
252 | 7.63M | return std::max(m_size, sal::static_int_cast< sal_uInt64 >(bufend)); |
253 | 7.63M | } |
254 | | |
255 | | oslFileError FileHandle_Impl::setSize(sal_uInt64 uSize) |
256 | 9.06k | { |
257 | 9.06k | off_t const nSize = sal::static_int_cast< off_t >(uSize); |
258 | 9.06k | if (ftruncate_with_name(m_fd, nSize, m_strFilePath) == -1) |
259 | 0 | { |
260 | | /* Failure. Save original result. Try fallback algorithm */ |
261 | 0 | oslFileError result = oslTranslateFileError(errno); |
262 | | |
263 | | /* Check against current size. Fail upon 'shrink' */ |
264 | 0 | if (uSize <= getSize()) |
265 | 0 | { |
266 | | /* Failure upon 'shrink'. Return original result */ |
267 | 0 | return result; |
268 | 0 | } |
269 | | |
270 | | /* Save current position */ |
271 | 0 | off_t const nCurPos = lseek(m_fd, off_t(0), SEEK_CUR); |
272 | 0 | if (nCurPos == off_t(-1)) |
273 | 0 | { |
274 | 0 | int e = errno; |
275 | 0 | SAL_INFO("sal.file", "lseek(" << m_fd << ",0,SEEK_CUR): " << UnixErrnoString(e)); |
276 | 0 | return result; |
277 | 0 | } |
278 | 0 | else |
279 | 0 | SAL_INFO("sal.file", "lseek(" << m_fd << ",0,SEEK_CUR): OK"); |
280 | | |
281 | | /* Try 'expand' via 'lseek()' and 'write()' */ |
282 | 0 | if (lseek(m_fd, static_cast<off_t>(nSize - 1), SEEK_SET) == -1) |
283 | 0 | { |
284 | 0 | int e = errno; |
285 | 0 | SAL_INFO("sal.file", "lseek(" << m_fd << "," << nSize - 1 << ",SEEK_SET): " << UnixErrnoString(e)); |
286 | 0 | return result; |
287 | 0 | } |
288 | 0 | else |
289 | 0 | SAL_INFO("sal.file", "lseek(" << m_fd << "," << nSize - 1 << ",SEEK_SET): OK"); |
290 | | |
291 | 0 | if (write(m_fd, "", size_t(1)) == -1) |
292 | 0 | { |
293 | | /* Failure. Restore saved position */ |
294 | 0 | int e = errno; |
295 | 0 | SAL_INFO("sal.file", "write(" << m_fd << ",\"\",1): " << UnixErrnoString(e)); |
296 | 0 | (void) lseek(m_fd, nCurPos, SEEK_SET); |
297 | 0 | return result; |
298 | 0 | } |
299 | 0 | else |
300 | 0 | SAL_INFO("sal.file", "write(" << m_fd << ",\"\",1): OK"); |
301 | | |
302 | | /* Success. Restore saved position */ |
303 | 0 | if (lseek(m_fd, nCurPos, SEEK_SET) == -1) |
304 | 0 | return result; |
305 | 0 | } |
306 | | |
307 | 9.06k | m_size = sal::static_int_cast< sal_uInt64 >(nSize); |
308 | 9.06k | return osl_File_E_None; |
309 | 9.06k | } |
310 | | |
311 | | oslFileError FileHandle_Impl::readAt( |
312 | | off_t nOffset, |
313 | | void * pBuffer, |
314 | | size_t nBytesRequested, |
315 | | sal_uInt64 * pBytesRead) |
316 | 13.6M | { |
317 | 13.6M | SAL_WARN_IF(!(m_state & State::Seekable), "sal.osl", "FileHandle_Impl::readAt(): not seekable"); |
318 | 13.6M | if (!(m_state & State::Seekable)) |
319 | 0 | return osl_File_E_SPIPE; |
320 | | |
321 | 13.6M | SAL_WARN_IF(!(m_state & State::Readable), "sal.osl", "FileHandle_Impl::readAt(): not readable"); |
322 | 13.6M | if (!(m_state & State::Readable)) |
323 | 0 | return osl_File_E_BADF; |
324 | | |
325 | 13.6M | if (m_kind == KIND_MEM) |
326 | 0 | { |
327 | 0 | ssize_t nBytes; |
328 | |
|
329 | 0 | m_offset = nOffset; |
330 | |
|
331 | 0 | if (o3tl::make_unsigned(m_offset) >= m_size) |
332 | 0 | { |
333 | 0 | nBytes = 0; |
334 | 0 | } |
335 | 0 | else |
336 | 0 | { |
337 | 0 | nBytes = std::min(nBytesRequested, static_cast<size_t>(m_size - m_offset)); |
338 | 0 | memmove(pBuffer, m_buffer + m_offset, nBytes); |
339 | 0 | m_offset += nBytes; |
340 | 0 | } |
341 | 0 | *pBytesRead = nBytes; |
342 | 0 | return osl_File_E_None; |
343 | 0 | } |
344 | | |
345 | 13.6M | ssize_t nBytes = ::pread(m_fd, pBuffer, nBytesRequested, nOffset); |
346 | 13.6M | if ((nBytes == -1) && (errno == EOVERFLOW)) |
347 | 0 | { |
348 | | /* Some 'pread()'s fail with EOVERFLOW when reading at (or past) |
349 | | * end-of-file, different from 'lseek() + read()' behaviour. |
350 | | * Returning '0 bytes read' and 'osl_File_E_None' instead. |
351 | | */ |
352 | 0 | nBytes = 0; |
353 | 0 | } |
354 | | |
355 | 13.6M | if (nBytes == -1) |
356 | 0 | return oslTranslateFileError(errno); |
357 | | |
358 | 13.6M | *pBytesRead = nBytes; |
359 | | |
360 | 13.6M | return osl_File_E_None; |
361 | 13.6M | } |
362 | | |
363 | | oslFileError FileHandle_Impl::writeAt( |
364 | | off_t nOffset, |
365 | | void const * pBuffer, |
366 | | size_t nBytesToWrite, |
367 | | sal_uInt64 * pBytesWritten) |
368 | 1.12M | { |
369 | 1.12M | SAL_WARN_IF(!(m_state & State::Seekable), "sal.osl", "FileHandle_Impl::writeAt(): not seekable"); |
370 | 1.12M | if (!(m_state & State::Seekable)) |
371 | 0 | return osl_File_E_SPIPE; |
372 | | |
373 | 1.12M | SAL_WARN_IF(!(m_state & State::Writeable), "sal.osl", "FileHandle_Impl::writeAt(): not writeable"); |
374 | 1.12M | if (!(m_state & State::Writeable)) |
375 | 0 | return osl_File_E_BADF; |
376 | | |
377 | 1.12M | ssize_t nBytes = ::pwrite(m_fd, pBuffer, nBytesToWrite, nOffset); |
378 | 1.12M | if (nBytes == -1) |
379 | 0 | return oslTranslateFileError(errno); |
380 | | |
381 | 1.12M | m_size = std::max(m_size, sal::static_int_cast< sal_uInt64 >(nOffset + nBytes)); |
382 | | |
383 | 1.12M | *pBytesWritten = nBytes; |
384 | | |
385 | 1.12M | return osl_File_E_None; |
386 | 1.12M | } |
387 | | |
388 | | oslFileError FileHandle_Impl::readFileAt( |
389 | | off_t nOffset, |
390 | | void* pBuffer, |
391 | | size_t nBytesRequested, |
392 | | sal_uInt64* pBytesRead) |
393 | 39.4M | { |
394 | 39.4M | if (!(m_state & State::Seekable)) |
395 | 0 | { |
396 | | // not seekable (pipe) |
397 | 0 | ssize_t nBytes = ::read(m_fd, pBuffer, nBytesRequested); |
398 | 0 | if (nBytes == -1) |
399 | 0 | return oslTranslateFileError(errno); |
400 | | |
401 | 0 | *pBytesRead = nBytes; |
402 | |
|
403 | 0 | return osl_File_E_None; |
404 | 0 | } |
405 | | |
406 | 39.4M | if (m_kind == KIND_MEM || !m_buffer) |
407 | 0 | { |
408 | | // not buffered |
409 | 0 | return readAt(nOffset, pBuffer, nBytesRequested, pBytesRead); |
410 | 0 | } |
411 | | |
412 | 39.4M | sal_uInt8 *buffer = static_cast<sal_uInt8*>(pBuffer); |
413 | 40.6M | for (*pBytesRead = 0; nBytesRequested > 0; ) |
414 | 40.4M | { |
415 | 40.4M | off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz; |
416 | 40.4M | size_t const bufpos = nOffset % m_bufsiz; |
417 | | |
418 | 40.4M | if (bufptr != m_bufptr) |
419 | 13.1M | { |
420 | | // flush current buffer |
421 | 13.1M | oslFileError result = syncFile(); |
422 | 13.1M | if (result != osl_File_E_None) |
423 | 0 | return result; |
424 | | |
425 | 13.1M | m_bufptr = -1; |
426 | 13.1M | m_buflen = 0; |
427 | | |
428 | 13.1M | if (nBytesRequested >= m_bufsiz) |
429 | 13.0M | { |
430 | | // buffer too small, read through from file |
431 | 13.0M | sal_uInt64 uDone = 0; |
432 | 13.0M | result = readAt(nOffset, &(buffer[*pBytesRead]), nBytesRequested, &uDone); |
433 | 13.0M | if (result != osl_File_E_None) |
434 | 0 | return result; |
435 | | |
436 | 13.0M | *pBytesRead += uDone; |
437 | | |
438 | 13.0M | return osl_File_E_None; |
439 | 13.0M | } |
440 | | |
441 | | // update buffer (pointer) |
442 | 132k | sal_uInt64 uDone = 0; |
443 | 132k | result = readAt(bufptr, m_buffer, m_bufsiz, &uDone); |
444 | 132k | if (result != osl_File_E_None) |
445 | 0 | return result; |
446 | | |
447 | 132k | m_bufptr = bufptr; |
448 | 132k | m_buflen = uDone; |
449 | 132k | } |
450 | | |
451 | 27.4M | if (bufpos >= m_buflen) |
452 | 26.1M | { |
453 | | // end of file |
454 | 26.1M | return osl_File_E_None; |
455 | 26.1M | } |
456 | | |
457 | 1.22M | size_t const bytes = std::min(m_buflen - bufpos, nBytesRequested); |
458 | 1.22M | SAL_INFO("sal.fileio", "FileHandle_Impl::readFileAt(" << m_fd << ", " << nOffset << ", " << bytes << ")"); |
459 | | |
460 | 1.22M | memcpy(&(buffer[*pBytesRead]), &(m_buffer[bufpos]), bytes); |
461 | 1.22M | nBytesRequested -= bytes; |
462 | 1.22M | *pBytesRead += bytes; |
463 | 1.22M | nOffset += bytes; |
464 | 1.22M | } |
465 | | |
466 | 214k | return osl_File_E_None; |
467 | 39.4M | } |
468 | | |
469 | | oslFileError FileHandle_Impl::writeFileAt( |
470 | | off_t nOffset, |
471 | | void const * pBuffer, |
472 | | size_t nBytesToWrite, |
473 | | sal_uInt64 * pBytesWritten) |
474 | 2.39M | { |
475 | 2.39M | if (!(m_state & State::Seekable)) |
476 | 0 | { |
477 | | // not seekable (pipe) |
478 | 0 | ssize_t nBytes = ::write(m_fd, pBuffer, nBytesToWrite); |
479 | 0 | if (nBytes == -1) |
480 | 0 | return oslTranslateFileError(errno); |
481 | | |
482 | 0 | *pBytesWritten = nBytes; |
483 | |
|
484 | 0 | return osl_File_E_None; |
485 | 0 | } |
486 | 2.39M | if (!m_buffer) |
487 | 0 | { |
488 | | // not buffered |
489 | 0 | return writeAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten); |
490 | 0 | } |
491 | | |
492 | 2.39M | sal_uInt8 const * buffer = static_cast<sal_uInt8 const *>(pBuffer); |
493 | 4.44M | for (*pBytesWritten = 0; nBytesToWrite > 0;) |
494 | 2.53M | { |
495 | 2.53M | off_t const bufptr = (nOffset / m_bufsiz) * m_bufsiz; |
496 | 2.53M | size_t const bufpos = nOffset % m_bufsiz; |
497 | 2.53M | if (bufptr != m_bufptr) |
498 | 963k | { |
499 | | // flush current buffer |
500 | 963k | oslFileError result = syncFile(); |
501 | 963k | if (result != osl_File_E_None) |
502 | 0 | return result; |
503 | 963k | m_bufptr = -1; |
504 | 963k | m_buflen = 0; |
505 | | |
506 | 963k | if (nBytesToWrite >= m_bufsiz) |
507 | 476k | { |
508 | | // buffer too small, write through to file |
509 | 476k | sal_uInt64 uDone = 0; |
510 | 476k | result = writeAt(nOffset, &(buffer[*pBytesWritten]), nBytesToWrite, &uDone); |
511 | 476k | if (result != osl_File_E_None) |
512 | 0 | return result; |
513 | | |
514 | 476k | if (uDone != nBytesToWrite) |
515 | 0 | return osl_File_E_IO; |
516 | | |
517 | 476k | *pBytesWritten += uDone; |
518 | | |
519 | 476k | return osl_File_E_None; |
520 | 476k | } |
521 | | |
522 | | // update buffer (pointer) |
523 | 487k | sal_uInt64 uDone = 0; |
524 | 487k | result = readAt(bufptr, m_buffer, m_bufsiz, &uDone); |
525 | 487k | if (result != osl_File_E_None) |
526 | 0 | return result; |
527 | | |
528 | 487k | m_bufptr = bufptr; |
529 | 487k | m_buflen = uDone; |
530 | 487k | } |
531 | | |
532 | 2.05M | size_t const bytes = std::min(m_bufsiz - bufpos, nBytesToWrite); |
533 | 2.05M | SAL_INFO("sal.fileio", "FileHandle_Impl::writeFileAt(" << m_fd << ", " << nOffset << ", " << bytes << ")"); |
534 | | |
535 | 2.05M | memcpy(&(m_buffer[bufpos]), &(buffer[*pBytesWritten]), bytes); |
536 | 2.05M | nBytesToWrite -= bytes; |
537 | 2.05M | *pBytesWritten += bytes; |
538 | 2.05M | nOffset += bytes; |
539 | | |
540 | 2.05M | m_buflen = std::max(m_buflen, bufpos + bytes); |
541 | 2.05M | m_state |= State::Modified; |
542 | 2.05M | } |
543 | | |
544 | 1.91M | return osl_File_E_None; |
545 | 2.39M | } |
546 | | |
547 | | oslFileError FileHandle_Impl::readLineAt( |
548 | | off_t nOffset, |
549 | | sal_Sequence ** ppSequence, |
550 | | sal_uInt64 * pBytesRead) |
551 | 505 | { |
552 | 505 | oslFileError result = osl_File_E_None; |
553 | | |
554 | 505 | off_t bufptr = nOffset / m_bufsiz * m_bufsiz; |
555 | 505 | if (bufptr != m_bufptr) |
556 | 101 | { |
557 | | /* flush current buffer */ |
558 | 101 | result = syncFile(); |
559 | 101 | if (result != osl_File_E_None) |
560 | 0 | return result; |
561 | | |
562 | | /* update buffer (pointer) */ |
563 | 101 | sal_uInt64 uDone = 0; |
564 | 101 | result = readAt(bufptr, m_buffer, m_bufsiz, &uDone); |
565 | 101 | if (result != osl_File_E_None) |
566 | 0 | return result; |
567 | | |
568 | 101 | m_bufptr = bufptr; |
569 | 101 | m_buflen = uDone; |
570 | 101 | } |
571 | | |
572 | 505 | static int const LINE_STATE_BEGIN = 0; |
573 | 505 | static int const LINE_STATE_CR = 1; |
574 | 505 | static int const LINE_STATE_LF = 2; |
575 | | |
576 | 505 | size_t bufpos = nOffset - m_bufptr, curpos = bufpos, dstpos = 0; |
577 | 505 | int state = (bufpos >= m_buflen) ? LINE_STATE_LF : LINE_STATE_BEGIN; |
578 | | |
579 | 17.1k | while (state != LINE_STATE_LF) |
580 | 16.6k | { |
581 | 16.6k | if (curpos >= m_buflen) |
582 | 0 | { |
583 | | /* buffer examined */ |
584 | 0 | if (curpos > bufpos) |
585 | 0 | { |
586 | | /* flush buffer to sequence */ |
587 | 0 | result = writeSequence_Impl( |
588 | 0 | ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos); |
589 | 0 | if (result != osl_File_E_None) |
590 | 0 | return result; |
591 | | |
592 | 0 | *pBytesRead += curpos - bufpos; |
593 | 0 | nOffset += curpos - bufpos; |
594 | 0 | } |
595 | | |
596 | 0 | bufptr = nOffset / m_bufsiz * m_bufsiz; |
597 | 0 | if (bufptr != m_bufptr) |
598 | 0 | { |
599 | | /* update buffer (pointer) */ |
600 | 0 | sal_uInt64 uDone = 0; |
601 | 0 | result = readAt(bufptr, m_buffer, m_bufsiz, &uDone); |
602 | 0 | if (result != osl_File_E_None) |
603 | 0 | return result; |
604 | | |
605 | 0 | m_bufptr = bufptr; |
606 | 0 | m_buflen = uDone; |
607 | 0 | } |
608 | | |
609 | 0 | bufpos = nOffset - m_bufptr; |
610 | 0 | curpos = bufpos; |
611 | 0 | if (bufpos >= m_buflen) |
612 | 0 | break; |
613 | 0 | } |
614 | | |
615 | 16.6k | switch (state) |
616 | 16.6k | { |
617 | 0 | case LINE_STATE_CR: |
618 | 0 | state = LINE_STATE_LF; |
619 | 0 | switch (m_buffer[curpos]) |
620 | 0 | { |
621 | 0 | case 0x0A: /* CRLF */ |
622 | | /* eat current char */ |
623 | 0 | curpos++; |
624 | 0 | break; |
625 | 0 | default: /* single CR */ |
626 | | /* keep current char */ |
627 | 0 | break; |
628 | 0 | } |
629 | 0 | break; |
630 | 16.6k | default: |
631 | | /* determine next state */ |
632 | 16.6k | switch (m_buffer[curpos]) |
633 | 16.6k | { |
634 | 404 | case 0x0A: /* single LF */ |
635 | 404 | state = LINE_STATE_LF; |
636 | 404 | break; |
637 | 0 | case 0x0D: /* CR */ |
638 | 0 | state = LINE_STATE_CR; |
639 | 0 | break; |
640 | 16.2k | default: /* advance to next char */ |
641 | 16.2k | curpos++; |
642 | 16.2k | break; |
643 | 16.6k | } |
644 | 16.6k | if (state != LINE_STATE_BEGIN) |
645 | 404 | { |
646 | | /* skip the newline char */ |
647 | 404 | curpos++; |
648 | | |
649 | | /* flush buffer to sequence */ |
650 | 404 | result = writeSequence_Impl( |
651 | 404 | ppSequence, &dstpos, &(m_buffer[bufpos]), curpos - bufpos - 1); |
652 | 404 | if (result != osl_File_E_None) |
653 | 0 | return result; |
654 | | |
655 | 404 | *pBytesRead += curpos - bufpos; |
656 | 404 | nOffset += curpos - bufpos; |
657 | 404 | } |
658 | 16.6k | break; |
659 | 16.6k | } |
660 | 16.6k | } |
661 | | |
662 | 505 | result = writeSequence_Impl(ppSequence, &dstpos, nullptr, 0); |
663 | 505 | if (result != osl_File_E_None) |
664 | 0 | return result; |
665 | | |
666 | 505 | if (dstpos > 0) |
667 | 404 | return osl_File_E_None; |
668 | | |
669 | 101 | if (bufpos >= m_buflen) |
670 | 101 | return osl_File_E_AGAIN; |
671 | | |
672 | 0 | return osl_File_E_None; |
673 | 101 | } |
674 | | |
675 | | oslFileError FileHandle_Impl::writeSequence_Impl( |
676 | | sal_Sequence ** ppSequence, |
677 | | size_t * pnOffset, |
678 | | const void * pBuffer, |
679 | | size_t nBytes) |
680 | 909 | { |
681 | 909 | sal_Int32 nElements = *pnOffset + nBytes; |
682 | 909 | if (!*ppSequence) |
683 | 0 | { |
684 | | /* construct sequence */ |
685 | 0 | rtl_byte_sequence_constructNoDefault(ppSequence, nElements); |
686 | 0 | } |
687 | 909 | else if (nElements != (*ppSequence)->nElements) |
688 | 505 | { |
689 | | /* resize sequence */ |
690 | 505 | rtl_byte_sequence_realloc(ppSequence, nElements); |
691 | 505 | } |
692 | | |
693 | 909 | if (*ppSequence && nBytes != 0) |
694 | 404 | { |
695 | | /* fill sequence */ |
696 | 404 | memcpy(&((*ppSequence)->elements[*pnOffset]), pBuffer, nBytes); |
697 | 404 | *pnOffset += nBytes; |
698 | 404 | } |
699 | | |
700 | 909 | return (*ppSequence) ? osl_File_E_None : osl_File_E_NOMEM; |
701 | 909 | } |
702 | | |
703 | | oslFileError FileHandle_Impl::syncFile() |
704 | 15.4M | { |
705 | 15.4M | oslFileError result = osl_File_E_None; |
706 | 15.4M | if (m_state & State::Modified) |
707 | 647k | { |
708 | 647k | sal_uInt64 uDone = 0; |
709 | 647k | result = writeAt(m_bufptr, m_buffer, m_buflen, &uDone); |
710 | 647k | if (result != osl_File_E_None) |
711 | 0 | return result; |
712 | | |
713 | 647k | if (uDone != m_buflen) |
714 | 0 | return osl_File_E_IO; |
715 | | |
716 | 647k | m_state &= ~State::Modified; |
717 | 647k | } |
718 | | |
719 | 15.4M | return result; |
720 | 15.4M | } |
721 | | |
722 | | oslFileHandle osl::detail::createFileHandleFromFD(int fd) |
723 | 0 | { |
724 | 0 | if (fd == -1) |
725 | 0 | return nullptr; // EINVAL |
726 | | |
727 | 0 | struct stat aFileStat; |
728 | 0 | if (fstat(fd, &aFileStat) == -1) |
729 | 0 | return nullptr; // EBADF |
730 | | |
731 | 0 | FileHandle_Impl *pImpl = new FileHandle_Impl(fd); |
732 | | |
733 | | // assume writeable |
734 | 0 | pImpl->m_state |= State::Writeable; |
735 | 0 | if (!S_ISREG(aFileStat.st_mode)) |
736 | 0 | { |
737 | | /* not a regular file, mark not seekable */ |
738 | 0 | pImpl->m_state &= ~State::Seekable; |
739 | 0 | } |
740 | 0 | else |
741 | 0 | { |
742 | | /* regular file, init current size */ |
743 | 0 | pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size); |
744 | 0 | } |
745 | |
|
746 | 0 | SAL_INFO("sal.file", "osl::detail::createFileHandleFromFD(" << pImpl->m_fd << ", writeable) => " << pImpl->m_strFilePath); |
747 | | |
748 | 0 | return static_cast<oslFileHandle>(pImpl); |
749 | 0 | } |
750 | | |
751 | | static void osl_file_adjustLockFlags(const OString& path, int *flags, sal_uInt32 *uFlags) |
752 | 83.4k | { |
753 | | #ifdef MACOSX |
754 | | (void) uFlags; |
755 | | |
756 | | /* |
757 | | * The AFP implementation of MacOS X 10.4 treats O_EXLOCK in a way |
758 | | * that makes it impossible for OOo to create a backup copy of the |
759 | | * file it keeps opened. OTOH O_SHLOCK for AFP behaves as desired by |
760 | | * the OOo file handling, so we need to check the path of the file |
761 | | * for the filesystem name. |
762 | | */ |
763 | | struct statfs s; |
764 | | if(statfs(path.getStr(), &s) >= 0) |
765 | | { |
766 | | if(strncmp("afpfs", s.f_fstypename, 5) == 0) |
767 | | { |
768 | | *flags &= ~O_EXLOCK; |
769 | | *flags |= O_SHLOCK; |
770 | | } |
771 | | else |
772 | | { |
773 | | /* Needed flags to allow opening a webdav file */ |
774 | | *flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK); |
775 | | } |
776 | | } |
777 | | #elif defined(LINUX) |
778 | | (void) flags; |
779 | | |
780 | | /* get filesystem info */ |
781 | 83.4k | struct statfs aFileStatFs; |
782 | 83.4k | if (statfs(path.getStr(), &aFileStatFs) < 0) |
783 | 11.5k | { |
784 | 11.5k | int e = errno; |
785 | 11.5k | SAL_INFO("sal.file", "statfs(" << path << "): " << UnixErrnoString(e)); |
786 | 11.5k | } |
787 | 71.8k | else |
788 | 71.8k | { |
789 | 71.8k | SAL_INFO("sal.file", "statfs(" << path << "): OK"); |
790 | | |
791 | | // We avoid locking if on a Linux CIFS mount otherwise this |
792 | | // fill fail later on when opening the file for reading |
793 | | // during backup creation at save time (even though this is a |
794 | | // write lock and not a read lock). |
795 | | // Fixes the following bug: |
796 | | // https://bugs.documentfoundation.org/show_bug.cgi?id=55004 |
797 | 71.8k | switch (aFileStatFs.f_type) { |
798 | 0 | case SMB_SUPER_MAGIC: |
799 | 0 | case CIFS_SUPER_MAGIC: |
800 | 0 | case SMB2_SUPER_MAGIC: |
801 | 0 | *uFlags |= osl_File_OpenFlag_NoLock; |
802 | 0 | break; |
803 | 71.8k | default: |
804 | 71.8k | break; |
805 | 71.8k | } |
806 | 71.8k | } |
807 | | #else |
808 | | (void) path; |
809 | | (void) flags; |
810 | | (void) uFlags; |
811 | | #endif |
812 | 83.4k | } |
813 | | |
814 | | static bool osl_file_queryLocking(sal_uInt32 uFlags) |
815 | 942k | { |
816 | 942k | #if !defined HAVE_O_EXLOCK |
817 | 942k | if (!(uFlags & osl_File_OpenFlag_NoLock) |
818 | 74.2k | && ((uFlags & osl_File_OpenFlag_Write) |
819 | 20.5k | || (uFlags & osl_File_OpenFlag_Create))) |
820 | 64.9k | { |
821 | 64.9k | static bool enabled = getenv("SAL_ENABLE_FILE_LOCKING") != nullptr; |
822 | | // getenv is not thread safe, so minimize use of result |
823 | 64.9k | return enabled; |
824 | 64.9k | } |
825 | | #else |
826 | | (void) uFlags; |
827 | | #endif |
828 | 877k | return false; |
829 | 942k | } |
830 | | |
831 | | static bool abortOnForbidden = false; |
832 | | static std::vector<OString> allowedPathsRead; |
833 | | static std::vector<OString> allowedPathsReadWrite; |
834 | | static std::vector<OString> allowedPathsExecute; |
835 | | |
836 | | static OString getParentFolder(std::string_view rFilePath) |
837 | 0 | { |
838 | 0 | sal_Int32 n = rFilePath.find_last_of('/'); |
839 | 0 | OString folderPath; |
840 | 0 | if (n < 1) |
841 | 0 | folderPath = "."_ostr; |
842 | 0 | else |
843 | 0 | folderPath = OString(rFilePath.substr(0, n)); |
844 | |
|
845 | 0 | return folderPath; |
846 | 0 | } |
847 | | |
848 | | void setAllowedPaths( |
849 | | std::u16string_view aPaths |
850 | | ) |
851 | 0 | { |
852 | 0 | allowedPathsRead.clear(); |
853 | 0 | allowedPathsReadWrite.clear(); |
854 | 0 | allowedPathsExecute.clear(); |
855 | |
|
856 | 0 | char eType = 'r'; |
857 | 0 | sal_Int32 nIndex = 0; |
858 | 0 | do |
859 | 0 | { |
860 | 0 | OString aPath = rtl::OUStringToOString( |
861 | 0 | o3tl::getToken(aPaths, 0, ':', nIndex), |
862 | 0 | RTL_TEXTENCODING_UTF8); |
863 | |
|
864 | 0 | if (aPath.getLength() == 0) |
865 | 0 | continue; |
866 | | |
867 | 0 | if (aPath.getLength() == 1) |
868 | 0 | { |
869 | 0 | eType = aPath[0]; |
870 | 0 | continue; |
871 | 0 | } |
872 | | |
873 | 0 | char resolvedPath[PATH_MAX]; |
874 | 0 | bool isResolved = !!realpath(aPath.getStr(), resolvedPath); |
875 | 0 | bool notExists = !isResolved && errno == ENOENT; |
876 | |
|
877 | 0 | if (notExists) |
878 | 0 | { |
879 | 0 | sal_Int32 n = aPath.lastIndexOf('/'); |
880 | 0 | OString folderPath = getParentFolder(aPath); |
881 | 0 | isResolved = !!realpath(folderPath.getStr(), resolvedPath); |
882 | 0 | notExists = !isResolved && errno == ENOENT; |
883 | |
|
884 | 0 | if (notExists || !isResolved || strlen(resolvedPath) + aPath.getLength() - n + 1 >= PATH_MAX) |
885 | 0 | return; // too bad |
886 | 0 | else |
887 | 0 | { |
888 | 0 | strcat(resolvedPath, aPath.getStr() + n); |
889 | 0 | } |
890 | 0 | } |
891 | | |
892 | 0 | if (isResolved) |
893 | 0 | { |
894 | 0 | OString aPushPath(resolvedPath, strlen(resolvedPath)); |
895 | 0 | if (eType == 'r') |
896 | 0 | allowedPathsRead.push_back(aPushPath); |
897 | 0 | else if (eType == 'w') |
898 | 0 | { |
899 | 0 | allowedPathsRead.push_back(aPushPath); |
900 | 0 | allowedPathsReadWrite.push_back(aPushPath); |
901 | 0 | } |
902 | 0 | else if (eType == 'x') |
903 | 0 | allowedPathsExecute.push_back(aPushPath); |
904 | 0 | } |
905 | 0 | } |
906 | 0 | while (nIndex != -1); |
907 | | |
908 | 0 | abortOnForbidden = !!getenv("SAL_ABORT_ON_FORBIDDEN"); |
909 | 0 | } |
910 | | |
911 | | bool isForbidden(const OString &filePath, sal_uInt32 nFlags) |
912 | 2.05M | { |
913 | | // avoid realpath cost unless configured |
914 | 2.05M | if (allowedPathsRead.size() == 0) |
915 | 2.05M | return false; |
916 | | |
917 | 0 | char resolvedPath[PATH_MAX]; |
918 | 0 | if (!realpath(filePath.getStr(), resolvedPath)) |
919 | 0 | { |
920 | | // write calls path a non-existent path that realpath will |
921 | | // fail to resolve. Thankfully our I/O APIs don't allow |
922 | | // symlink creation to race here. |
923 | 0 | sal_Int32 n = filePath.lastIndexOf('/'); |
924 | 0 | OString folderPath = getParentFolder(filePath); |
925 | |
|
926 | 0 | bool isResolved = !!realpath(folderPath.getStr(), resolvedPath); |
927 | 0 | bool notExists = !isResolved && errno == ENOENT; |
928 | 0 | if (notExists) // folder doesn't exist, check parent, in the end of chain checks "." |
929 | 0 | return isForbidden(folderPath, nFlags); |
930 | 0 | else if (!isResolved || strlen(resolvedPath) + filePath.getLength() - n + 1 >= PATH_MAX) |
931 | 0 | return true; // too bad |
932 | 0 | else |
933 | 0 | { |
934 | 0 | strcat(resolvedPath, filePath.getStr() + n); |
935 | 0 | } |
936 | 0 | } |
937 | | |
938 | 0 | const std::vector<OString> *pCheckPaths = &allowedPathsRead; |
939 | 0 | if (nFlags & osl_File_OpenFlag_Write || |
940 | 0 | nFlags & osl_File_OpenFlag_Create) |
941 | 0 | pCheckPaths = &allowedPathsReadWrite; |
942 | 0 | else if (nFlags & 0x80) |
943 | 0 | pCheckPaths = &allowedPathsExecute; |
944 | |
|
945 | 0 | bool allowed = false; |
946 | 0 | for (const auto &it : *pCheckPaths) { |
947 | 0 | if (!strncmp(resolvedPath, it.getStr(), it.getLength())) |
948 | 0 | { |
949 | 0 | allowed = true; |
950 | 0 | break; |
951 | 0 | } |
952 | 0 | } |
953 | |
|
954 | 0 | if (!allowed) |
955 | 0 | SAL_WARN("sal.osl", "access outside sandbox to " << |
956 | 0 | ((nFlags & osl_File_OpenFlag_Write || |
957 | 0 | nFlags & osl_File_OpenFlag_Create) ? "w" : |
958 | 0 | (nFlags & 0x80) ? "x" : "r") << ":" << |
959 | 0 | filePath << " which is really " << resolvedPath << |
960 | 0 | (allowed ? " allowed " : " forbidden") << |
961 | 0 | " check list: " << pCheckPaths->size()); |
962 | | |
963 | 0 | if (abortOnForbidden && !allowed) |
964 | 0 | abort(); // a bit abrupt - but don't try to escape. |
965 | | |
966 | 0 | return !allowed; |
967 | 0 | } |
968 | | |
969 | | #ifdef HAVE_O_EXLOCK |
970 | | #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK ) |
971 | | #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK ) |
972 | | #else |
973 | 553k | #define OPEN_WRITE_FLAGS ( O_RDWR ) |
974 | 888k | #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR ) |
975 | | #endif |
976 | | |
977 | | #if defined ANDROID |
978 | | |
979 | | namespace { |
980 | | |
981 | | static oslFileError openMemoryAsFile(const OString &rData, |
982 | | oslFileHandle *pHandle, |
983 | | const OString& path) |
984 | | { |
985 | | const char *address = rData.getStr(); |
986 | | size_t size = rData.getLength(); |
987 | | |
988 | | FileHandle_Impl *pImpl = new FileHandle_Impl(-1, FileHandle_Impl::KIND_MEM, path); |
989 | | pImpl->m_size = sal::static_int_cast< sal_uInt64 >(size); |
990 | | |
991 | | *pHandle = (oslFileHandle)(pImpl); |
992 | | |
993 | | pImpl->m_bufptr = 0; |
994 | | pImpl->m_buflen = size; |
995 | | pImpl->m_memstreambuf = rData.pData; |
996 | | rtl_string_acquire(pImpl->m_memstreambuf); |
997 | | |
998 | | pImpl->m_bufsiz = size; |
999 | | pImpl->m_buffer = reinterpret_cast<sal_uInt8*>(const_cast<char *>(address)); |
1000 | | |
1001 | | return osl_File_E_None; |
1002 | | } |
1003 | | |
1004 | | /* |
1005 | | * Reading files from /assets/ on Android via a transition into the VM |
1006 | | * shows on profiles and is rather slow; so we cache small files as |
1007 | | * used by UNO, UI-builder etc. |
1008 | | */ |
1009 | | class AndroidFileCache { |
1010 | | public: |
1011 | | struct Entry { |
1012 | | OString maFilePath; |
1013 | | OString maData; |
1014 | | }; |
1015 | | AndroidFileCache(size_t nElements) |
1016 | | : mnCur(0) |
1017 | | { |
1018 | | maEntries.resize(nElements); |
1019 | | assert (maEntries.size() == nElements); |
1020 | | } |
1021 | | Entry *find(const char *cpFilePath) |
1022 | | { |
1023 | | for (auto &it : maEntries) |
1024 | | { |
1025 | | if (!strcmp(it.maFilePath.getStr(), cpFilePath)) |
1026 | | return ⁢ |
1027 | | } |
1028 | | return nullptr; |
1029 | | } |
1030 | | // no clever LRU - but - good enough for now. |
1031 | | void insert(const char *cpFilePath, OString &rData) |
1032 | | { |
1033 | | assert (maEntries.size() > 0); |
1034 | | if (++mnCur >= maEntries.size()) |
1035 | | mnCur = 0; |
1036 | | maEntries[mnCur].maFilePath = OString(cpFilePath, strlen(cpFilePath)); |
1037 | | maEntries[mnCur].maData = rData; |
1038 | | } |
1039 | | static AndroidFileCache &getHitCache() |
1040 | | { |
1041 | | static AndroidFileCache *pCache = new AndroidFileCache(16); |
1042 | | return *pCache; |
1043 | | } |
1044 | | static AndroidFileCache &getMissCache() |
1045 | | { |
1046 | | static AndroidFileCache *pCache = new AndroidFileCache(32); |
1047 | | return *pCache; |
1048 | | } |
1049 | | private: |
1050 | | size_t mnCur; |
1051 | | std::vector<Entry> maEntries; |
1052 | | }; |
1053 | | |
1054 | | } // namespace |
1055 | | |
1056 | | #endif |
1057 | | |
1058 | | oslFileError openFilePath(const OString& filePath, oslFileHandle* pHandle, |
1059 | | sal_uInt32 uFlags, mode_t mode) |
1060 | 951k | { |
1061 | 951k | oslFileError eRet; |
1062 | | |
1063 | | #ifdef ANDROID |
1064 | | /* Opening a file from /assets read-only means |
1065 | | * we should mmap it from the .apk file |
1066 | | */ |
1067 | | if (o3tl::starts_with(filePath, "/assets/")) |
1068 | | { |
1069 | | OString aData; |
1070 | | bool bCache = true; |
1071 | | |
1072 | | const char *cpAssetsPath = filePath.getStr() + sizeof("/assets/") - 1; |
1073 | | // some requests are /assets//foo... |
1074 | | if (cpAssetsPath[0] == '/') |
1075 | | { |
1076 | | __android_log_print(ANDROID_LOG_DEBUG,"libo:sal/osl/unx/file", "double-slash in path: %s", filePath.getStr()); |
1077 | | cpAssetsPath++; |
1078 | | } |
1079 | | |
1080 | | AndroidFileCache::Entry *pHit = AndroidFileCache::getHitCache().find(cpAssetsPath); |
1081 | | if (pHit) |
1082 | | aData = pHit->maData; |
1083 | | |
1084 | | else |
1085 | | { |
1086 | | bCache = false; |
1087 | | AndroidFileCache::Entry *pMiss = AndroidFileCache::getMissCache().find(cpAssetsPath); |
1088 | | if (pMiss) |
1089 | | { |
1090 | | errno = ENOENT; |
1091 | | __android_log_print(ANDROID_LOG_ERROR,"libo:sal/osl/unx/file", "miss cache: failed to open %s", filePath.getStr()); |
1092 | | return osl_File_E_NOENT; |
1093 | | } |
1094 | | AAssetManager* mgr = lo_get_native_assetmgr(); |
1095 | | AAsset* asset = AAssetManager_open(mgr, cpAssetsPath, AASSET_MODE_BUFFER); |
1096 | | if (!asset) |
1097 | | { |
1098 | | AndroidFileCache::getMissCache().insert(cpAssetsPath, aData); |
1099 | | errno = ENOENT; |
1100 | | __android_log_print(ANDROID_LOG_ERROR,"libo:sal/osl/unx/file", "failed to open %s", filePath.getStr()); |
1101 | | return osl_File_E_NOENT; |
1102 | | } |
1103 | | else |
1104 | | { |
1105 | | rtl_String *pData = nullptr; |
1106 | | size_t size = AAsset_getLength(asset); |
1107 | | rtl_string_new_WithLength(&pData, size); |
1108 | | pData->length = size; |
1109 | | AAsset_read(asset, pData->buffer, size); |
1110 | | AAsset_close(asset); |
1111 | | |
1112 | | aData = OString(pData, SAL_NO_ACQUIRE); |
1113 | | |
1114 | | if (pData->length < 50 * 1024) |
1115 | | AndroidFileCache::getHitCache().insert(cpAssetsPath, aData); |
1116 | | } |
1117 | | } |
1118 | | |
1119 | | if (uFlags & osl_File_OpenFlag_Write) |
1120 | | { |
1121 | | // It seems to work better to silently "open" it read-only |
1122 | | // and let write attempts, if any, fail later. Otherwise |
1123 | | // loading a document from /assets fails with that idiotic |
1124 | | // "General Error" dialog... |
1125 | | } |
1126 | | SAL_INFO("sal.file", "osl_openFile(" << filePath << ") => '" << cpAssetsPath << "'" |
1127 | | << aData.getLength() << " bytes from file " << (bCache ? "cache" : "system")); |
1128 | | return openMemoryAsFile(aData, pHandle, filePath); |
1129 | | } |
1130 | | #endif |
1131 | | |
1132 | | /* set mode and flags */ |
1133 | 951k | int defmode = (uFlags & osl_File_OpenFlag_Private) ? S_IRUSR : S_IRUSR | S_IRGRP | S_IROTH; |
1134 | 951k | int flags = O_RDONLY; |
1135 | | |
1136 | 951k | if (uFlags & osl_File_OpenFlag_Write) |
1137 | 553k | { |
1138 | 553k | defmode |= (uFlags & osl_File_OpenFlag_Private) ? S_IWUSR : S_IWUSR | S_IWGRP | S_IWOTH; |
1139 | 553k | flags = OPEN_WRITE_FLAGS; |
1140 | 553k | } |
1141 | | |
1142 | 951k | if (uFlags & osl_File_OpenFlag_Create) |
1143 | 888k | { |
1144 | 888k | defmode |= (uFlags & osl_File_OpenFlag_Private) ? S_IWUSR : S_IWUSR | S_IWGRP | S_IWOTH; |
1145 | 888k | flags = OPEN_CREATE_FLAGS; |
1146 | 888k | } |
1147 | | |
1148 | 951k | if (mode == mode_t(-1)) |
1149 | 951k | mode = defmode; |
1150 | | |
1151 | | /* Check for flags passed in from SvFileStream::Open() */ |
1152 | 951k | if (uFlags & osl_File_OpenFlag_Trunc) |
1153 | 0 | flags |= O_TRUNC; |
1154 | | |
1155 | 951k | if (!(uFlags & osl_File_OpenFlag_NoExcl)) |
1156 | 461k | flags |= O_EXCL; |
1157 | | |
1158 | 951k | if (uFlags & osl_File_OpenFlag_NoLock) |
1159 | 868k | { |
1160 | | #ifdef HAVE_O_EXLOCK |
1161 | | flags &= ~(O_EXLOCK | O_SHLOCK | O_NONBLOCK); |
1162 | | #endif /* HAVE_O_EXLOCK */ |
1163 | 868k | } |
1164 | 83.4k | else |
1165 | 83.4k | { |
1166 | 83.4k | osl_file_adjustLockFlags (filePath, &flags, &uFlags); |
1167 | 83.4k | } |
1168 | | |
1169 | | // O_EXCL can be set only when O_CREAT is set |
1170 | 951k | if (flags & O_EXCL && !(flags & O_CREAT)) |
1171 | 63.1k | flags &= ~O_EXCL; |
1172 | | |
1173 | | // set close-on-exec by default |
1174 | 951k | flags |= O_CLOEXEC; |
1175 | | |
1176 | | // Sandboxing hook |
1177 | 951k | if (isForbidden( filePath, uFlags )) |
1178 | 0 | return osl_File_E_ACCES; |
1179 | | |
1180 | | /* open the file */ |
1181 | 951k | int fd = open_c( filePath, flags, mode ); |
1182 | 951k | if (fd == -1) |
1183 | 9.21k | { |
1184 | 9.21k | return oslTranslateFileError(errno); |
1185 | 9.21k | } |
1186 | | |
1187 | 942k | #if !HAVE_FEATURE_MACOSX_SANDBOX |
1188 | | /* reset O_NONBLOCK flag */ |
1189 | 942k | if (flags & O_NONBLOCK) |
1190 | 0 | { |
1191 | 0 | int f = fcntl(fd, F_GETFL, 0); |
1192 | 0 | if (f == -1) |
1193 | 0 | { |
1194 | 0 | int e = errno; |
1195 | 0 | SAL_INFO("sal.file", "fcntl(" << fd << ",F_GETFL,0): " << UnixErrnoString(e)); |
1196 | 0 | eRet = oslTranslateFileError(e); |
1197 | 0 | (void) close(fd); |
1198 | 0 | SAL_INFO("sal.file", "close(" << fd << ")"); |
1199 | 0 | return eRet; |
1200 | 0 | } |
1201 | 0 | else |
1202 | 0 | SAL_INFO("sal.file", "fcntl(" << fd << ",F_GETFL,0): OK"); |
1203 | | |
1204 | 0 | if (fcntl(fd, F_SETFL, (f & ~O_NONBLOCK)) == -1) |
1205 | 0 | { |
1206 | 0 | int e = errno; |
1207 | 0 | SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETFL,(f & ~O_NONBLOCK)): " << UnixErrnoString(e)); |
1208 | 0 | eRet = oslTranslateFileError(e); |
1209 | 0 | (void) close(fd); |
1210 | 0 | SAL_INFO("sal.file", "close(" << fd << ")"); |
1211 | 0 | return eRet; |
1212 | 0 | } |
1213 | 0 | else |
1214 | 0 | SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETFL,(f & ~O_NONBLOCK)): OK"); |
1215 | 0 | } |
1216 | 942k | #endif |
1217 | | |
1218 | | /* get file status (mode, size) */ |
1219 | 942k | struct stat aFileStat; |
1220 | 942k | if (fstat(fd, &aFileStat) == -1) |
1221 | 0 | { |
1222 | 0 | int e = errno; |
1223 | 0 | SAL_INFO("sal.file", "fstat(" << fd << "): " << UnixErrnoString(e)); |
1224 | 0 | eRet = oslTranslateFileError(e); |
1225 | 0 | (void) close(fd); |
1226 | 0 | SAL_INFO("sal.file", "close(" << fd << ")"); |
1227 | 0 | return eRet; |
1228 | 0 | } |
1229 | 942k | else |
1230 | 942k | SAL_INFO("sal.file", "fstat(" << fd << "): OK"); |
1231 | | |
1232 | 942k | if (!S_ISREG(aFileStat.st_mode)) |
1233 | 0 | { |
1234 | | /* we only open regular files here */ |
1235 | 0 | SAL_INFO("sal.file", "osl_openFile(" << filePath << "): not a regular file"); |
1236 | 0 | (void) close(fd); |
1237 | 0 | SAL_INFO("sal.file", "close(" << fd << ")"); |
1238 | 0 | return osl_File_E_INVAL; |
1239 | 0 | } |
1240 | | |
1241 | 942k | if (osl_file_queryLocking(uFlags)) |
1242 | 0 | { |
1243 | | #ifdef MACOSX |
1244 | | if (flock(fd, LOCK_EX | LOCK_NB) == -1) |
1245 | | { |
1246 | | int e = errno; |
1247 | | SAL_INFO("sal.file", "flock(" << fd << ",LOCK_EX|LOCK_NB): " << UnixErrnoString(e)); |
1248 | | /* Mac OSX returns ENOTSUP for webdav drives. We should try read lock */ |
1249 | | |
1250 | | // Restore errno after possibly having been overwritten by the SAL_INFO above... |
1251 | | errno = e; |
1252 | | if ((errno != ENOTSUP) || ((flock(fd, LOCK_SH | LOCK_NB) == 1) && (errno != ENOTSUP))) |
1253 | | { |
1254 | | eRet = oslTranslateFileError(errno); |
1255 | | (void) close(fd); |
1256 | | SAL_INFO("sal.file", "close(" << fd << ")"); |
1257 | | return eRet; |
1258 | | } |
1259 | | } |
1260 | | else |
1261 | | SAL_INFO("sal.file", "flock(" << fd << ",LOCK_EX|LOCK_NB): OK"); |
1262 | | #else /* F_SETLK */ |
1263 | 0 | struct flock aflock; |
1264 | |
|
1265 | 0 | aflock.l_type = F_WRLCK; |
1266 | 0 | aflock.l_whence = SEEK_SET; |
1267 | 0 | aflock.l_start = 0; |
1268 | 0 | aflock.l_len = 0; |
1269 | |
|
1270 | 0 | if (fcntl(fd, F_SETLK, &aflock) == -1) |
1271 | 0 | { |
1272 | 0 | int e = errno; |
1273 | 0 | SAL_INFO("sal.file", "fcntl(" << fd << ",F_SETLK): " << UnixErrnoString(e)); |
1274 | 0 | eRet = oslTranslateFileError(e); |
1275 | 0 | (void) close(fd); |
1276 | 0 | SAL_INFO("sal.file", "close(" << fd << ")"); |
1277 | 0 | return eRet; |
1278 | 0 | } |
1279 | 0 | #endif /* F_SETLK */ |
1280 | 0 | } |
1281 | | |
1282 | | /* allocate memory for impl structure */ |
1283 | 942k | FileHandle_Impl *pImpl = new FileHandle_Impl(fd, FileHandle_Impl::KIND_FD, filePath); |
1284 | 942k | if (flags & O_RDWR) |
1285 | 933k | pImpl->m_state |= State::Writeable; |
1286 | | |
1287 | 942k | pImpl->m_size = sal::static_int_cast< sal_uInt64 >(aFileStat.st_size); |
1288 | | |
1289 | 942k | *pHandle = static_cast<oslFileHandle>(pImpl); |
1290 | | |
1291 | 942k | return osl_File_E_None; |
1292 | 942k | } |
1293 | | |
1294 | | oslFileError SAL_CALL osl_openFile(rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags) |
1295 | 952k | { |
1296 | 952k | return openFile(ustrFileURL, pHandle, uFlags, mode_t(-1)); |
1297 | 952k | } |
1298 | | |
1299 | | oslFileError openFile(rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uInt32 uFlags, mode_t mode) |
1300 | 952k | { |
1301 | 952k | oslFileError eRet; |
1302 | | |
1303 | 952k | if ((!ustrFileURL) || (ustrFileURL->length == 0) || (!pHandle)) |
1304 | 0 | return osl_File_E_INVAL; |
1305 | | |
1306 | | /* convert file URL to system path */ |
1307 | 952k | char buffer[PATH_MAX]; |
1308 | 952k | eRet = FileURLToPath(buffer, sizeof(buffer), ustrFileURL); |
1309 | 952k | if (eRet != osl_File_E_None) |
1310 | 615 | return eRet; |
1311 | | |
1312 | | #ifdef MACOSX |
1313 | | if (macxp_resolveAlias(buffer, sizeof(buffer)) != 0) |
1314 | | return oslTranslateFileError(errno); |
1315 | | #endif /* MACOSX */ |
1316 | | |
1317 | 951k | return openFilePath(buffer, pHandle, uFlags, mode); |
1318 | 952k | } |
1319 | | |
1320 | | oslFileError SAL_CALL osl_closeFile(oslFileHandle Handle) |
1321 | 942k | { |
1322 | 942k | FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle); |
1323 | | |
1324 | 942k | if (!pImpl) |
1325 | 0 | return osl_File_E_INVAL; |
1326 | | |
1327 | 942k | if (pImpl->m_kind == FileHandle_Impl::KIND_MEM) |
1328 | 0 | { |
1329 | | #ifdef ANDROID |
1330 | | rtl_string_release(pImpl->m_memstreambuf); |
1331 | | pImpl->m_memstreambuf = nullptr; |
1332 | | |
1333 | | pImpl->m_buffer = NULL; |
1334 | | #endif |
1335 | 0 | delete pImpl; |
1336 | 0 | return osl_File_E_None; |
1337 | 0 | } |
1338 | | |
1339 | 942k | if (pImpl->m_fd < 0) |
1340 | 0 | return osl_File_E_INVAL; |
1341 | | |
1342 | 942k | (void) pthread_mutex_lock(&(pImpl->m_mutex)); |
1343 | | |
1344 | | /* close(2) implicitly (and unconditionally) unlocks */ |
1345 | 942k | oslFileError result = pImpl->syncFile(); |
1346 | 942k | if (result != osl_File_E_None) |
1347 | 0 | { |
1348 | | /* close, ignoring double failure */ |
1349 | 0 | (void) close(pImpl->m_fd); |
1350 | 0 | SAL_INFO("sal.file", "close(" << pImpl->m_fd << ")"); |
1351 | 0 | } |
1352 | 942k | else if (close(pImpl->m_fd) == -1) |
1353 | 0 | { |
1354 | 0 | int e = errno; |
1355 | 0 | SAL_INFO("sal.file", "close(" << pImpl->m_fd << "): " << UnixErrnoString(e)); |
1356 | | /* translate error code */ |
1357 | 0 | result = oslTranslateFileError(e); |
1358 | 0 | } |
1359 | 942k | else |
1360 | 942k | SAL_INFO("sal.file", "close(" << pImpl->m_fd << "): OK"); |
1361 | | |
1362 | 942k | (void) pthread_mutex_unlock(&(pImpl->m_mutex)); |
1363 | 942k | delete pImpl; |
1364 | 942k | return result; |
1365 | 942k | } |
1366 | | |
1367 | | oslFileError SAL_CALL osl_syncFile(oslFileHandle Handle) |
1368 | 371k | { |
1369 | 371k | FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); |
1370 | | |
1371 | 371k | if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1))) |
1372 | 0 | return osl_File_E_INVAL; |
1373 | | |
1374 | 371k | if (pImpl->m_kind == FileHandle_Impl::KIND_MEM) |
1375 | 0 | return osl_File_E_None; |
1376 | | |
1377 | 371k | FileHandle_Impl::Guard lock(&(pImpl->m_mutex)); |
1378 | | |
1379 | 371k | oslFileError result = pImpl->syncFile(); |
1380 | | |
1381 | 371k | if (result != osl_File_E_None) |
1382 | 0 | return result; |
1383 | | |
1384 | 371k | static bool disabled = getenv("SAL_DISABLE_FSYNC") != nullptr; |
1385 | | |
1386 | 371k | if (disabled) |
1387 | 371k | SAL_INFO("sal.file", "fsync(" << pImpl->m_fd << "): Disabled"); |
1388 | 371k | else if (fsync(pImpl->m_fd) == -1) |
1389 | 0 | { |
1390 | 0 | int e = errno; |
1391 | 0 | SAL_INFO("sal.file", "fsync(" << pImpl->m_fd << "): " << UnixErrnoString(e)); |
1392 | 0 | return oslTranslateFileError(e); |
1393 | 0 | } |
1394 | 371k | else |
1395 | 371k | SAL_INFO("sal.file", "fsync(" << pImpl->m_fd << "): OK"); |
1396 | | |
1397 | 371k | return osl_File_E_None; |
1398 | 371k | } |
1399 | | |
1400 | | const off_t MAX_OFF_T = std::numeric_limits< off_t >::max(); |
1401 | | |
1402 | | namespace { |
1403 | | |
1404 | 55.2M | template<typename T> bool exceedsMaxOffT(T n) { return n > MAX_OFF_T; }file.cxx:bool (anonymous namespace)::exceedsMaxOffT<unsigned long>(unsigned long) Line | Count | Source | 1404 | 9.36k | template<typename T> bool exceedsMaxOffT(T n) { return n > MAX_OFF_T; } |
file.cxx:bool (anonymous namespace)::exceedsMaxOffT<long>(long) Line | Count | Source | 1404 | 55.2M | template<typename T> bool exceedsMaxOffT(T n) { return n > MAX_OFF_T; } |
|
1405 | | |
1406 | | template<typename T> bool exceedsMinOffT(T n) |
1407 | 55.2M | { return n < std::numeric_limits<off_t>::min(); } |
1408 | | |
1409 | | } |
1410 | | |
1411 | | oslFileError SAL_CALL osl_mapFile( |
1412 | | oslFileHandle Handle, |
1413 | | void** ppAddr, |
1414 | | sal_uInt64 uLength, |
1415 | | sal_uInt64 uOffset, |
1416 | | sal_uInt32 uFlags |
1417 | | ) |
1418 | 303 | { |
1419 | 303 | FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle); |
1420 | | |
1421 | 303 | if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!ppAddr)) |
1422 | 0 | return osl_File_E_INVAL; |
1423 | | |
1424 | 303 | *ppAddr = nullptr; |
1425 | | |
1426 | 303 | if (uLength > SAL_MAX_SIZE) |
1427 | 0 | { |
1428 | | // coverity[dead_error_line] 2024.6.1 - crossplatform requirement |
1429 | 0 | return osl_File_E_OVERFLOW; |
1430 | 0 | } |
1431 | | |
1432 | 303 | size_t const nLength = sal::static_int_cast< size_t >(uLength); |
1433 | | |
1434 | 303 | if (exceedsMaxOffT(uOffset)) |
1435 | 0 | return osl_File_E_OVERFLOW; |
1436 | | |
1437 | 303 | if (pImpl->m_kind == FileHandle_Impl::KIND_MEM) |
1438 | 0 | { |
1439 | 0 | *ppAddr = pImpl->m_buffer + uOffset; |
1440 | 0 | return osl_File_E_None; |
1441 | 0 | } |
1442 | | |
1443 | 303 | off_t const nOffset = sal::static_int_cast< off_t >(uOffset); |
1444 | | |
1445 | 303 | void* p = mmap(nullptr, nLength, PROT_READ, MAP_SHARED, pImpl->m_fd, nOffset); |
1446 | | |
1447 | 303 | if (p == MAP_FAILED) |
1448 | 0 | return oslTranslateFileError(errno); |
1449 | | |
1450 | 303 | *ppAddr = p; |
1451 | | |
1452 | 303 | if (uFlags & osl_File_MapFlag_RandomAccess) |
1453 | 202 | { |
1454 | | // Determine memory pagesize. |
1455 | 202 | size_t const nPageSize = FileHandle_Impl::getpagesize(); |
1456 | 202 | if (nPageSize != size_t(-1)) |
1457 | 202 | { |
1458 | | /* |
1459 | | * Pagein, touching first byte of every memory page. |
1460 | | * Note: volatile disables optimizing the loop away. |
1461 | | */ |
1462 | 202 | sal_uInt8 volatile *pData(static_cast<sal_uInt8*>(*ppAddr)); |
1463 | 202 | size_t nSize(nLength); |
1464 | | |
1465 | 18.3k | while (nSize > nPageSize) |
1466 | 18.1k | { |
1467 | 18.1k | pData[0]; |
1468 | 18.1k | pData += nPageSize; |
1469 | 18.1k | nSize -= nPageSize; |
1470 | 18.1k | } |
1471 | | |
1472 | 202 | if (nSize > 0) |
1473 | 202 | pData[0]; |
1474 | 202 | } |
1475 | 202 | } |
1476 | | |
1477 | 303 | if (uFlags & osl_File_MapFlag_WillNeed) |
1478 | 101 | { |
1479 | | // On Linux, madvise(..., MADV_WILLNEED) appears to have the undesirable |
1480 | | // effect of not returning until the data has actually been paged in, so |
1481 | | // that its net effect would typically be to slow down the process |
1482 | | // (which could start processing at the beginning of the data while the |
1483 | | // OS simultaneously pages in the rest); on other platforms, it remains |
1484 | | // to be evaluated whether madvise or equivalent is available and |
1485 | | // actually useful: |
1486 | | #if defined MACOSX || (defined(__sun) && (!defined(__XOPEN_OR_POSIX) || defined(_XPG6) || defined(__EXTENSIONS__))) |
1487 | | int e = posix_madvise(p, nLength, POSIX_MADV_WILLNEED); |
1488 | | if (e != 0) |
1489 | | SAL_INFO("sal.file", "posix_madvise(..., POSIX_MADV_WILLNEED) failed with " << e); |
1490 | | |
1491 | | #elif defined __sun |
1492 | | if (madvise(static_cast< caddr_t >(p), nLength, MADV_WILLNEED) != 0) |
1493 | | SAL_INFO("sal.file", "madvise(..., MADV_WILLNEED) failed with " << UnixErrnoString(errno)); |
1494 | | #endif |
1495 | 101 | } |
1496 | | |
1497 | 303 | return osl_File_E_None; |
1498 | 303 | } |
1499 | | |
1500 | | static oslFileError unmapFile(void* pAddr, sal_uInt64 uLength) |
1501 | 101 | { |
1502 | 101 | if (!pAddr) |
1503 | 0 | return osl_File_E_INVAL; |
1504 | | |
1505 | 101 | if (uLength > SAL_MAX_SIZE) |
1506 | 0 | { |
1507 | | // coverity[dead_error_line] 2024.6.1 - crossplatform requirement |
1508 | 0 | return osl_File_E_OVERFLOW; |
1509 | 0 | } |
1510 | | |
1511 | 101 | size_t const nLength = sal::static_int_cast< size_t >(uLength); |
1512 | | |
1513 | 101 | if (munmap(pAddr, nLength) == -1) |
1514 | 0 | return oslTranslateFileError(errno); |
1515 | | |
1516 | 101 | return osl_File_E_None; |
1517 | 101 | } |
1518 | | |
1519 | | #ifndef ANDROID |
1520 | | |
1521 | | // Note that osl_unmapFile() just won't work on Android in general |
1522 | | // where for (uncompressed) files inside the .apk, in the /assets |
1523 | | // folder osl_mapFile just returns a pointer to the file inside the |
1524 | | // already mmapped .apk archive. |
1525 | | |
1526 | | oslFileError SAL_CALL osl_unmapFile(void* pAddr, sal_uInt64 uLength) |
1527 | 0 | { |
1528 | 0 | return unmapFile(pAddr, uLength); |
1529 | 0 | } |
1530 | | |
1531 | | #endif |
1532 | | |
1533 | | oslFileError SAL_CALL osl_unmapMappedFile(oslFileHandle Handle, void* pAddr, sal_uInt64 uLength) |
1534 | 101 | { |
1535 | 101 | FileHandle_Impl *pImpl = static_cast<FileHandle_Impl*>(Handle); |
1536 | | |
1537 | 101 | if (!pImpl) |
1538 | 0 | return osl_File_E_INVAL; |
1539 | | |
1540 | 101 | if (pImpl->m_kind == FileHandle_Impl::KIND_FD) |
1541 | 101 | return unmapFile(pAddr, uLength); |
1542 | | |
1543 | | // For parts of already mmapped "parent" files, whose mapping we |
1544 | | // can't change, not much we can or should do... |
1545 | 0 | return osl_File_E_None; |
1546 | 101 | } |
1547 | | |
1548 | | oslFileError SAL_CALL osl_readLine( |
1549 | | oslFileHandle Handle, |
1550 | | sal_Sequence ** ppSequence) |
1551 | 505 | { |
1552 | 505 | FileHandle_Impl *pImpl = static_cast<FileHandle_Impl*>(Handle); |
1553 | | |
1554 | 505 | if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!ppSequence)) |
1555 | 0 | return osl_File_E_INVAL; |
1556 | | |
1557 | 505 | sal_uInt64 uBytesRead = 0; |
1558 | | |
1559 | | // read at current fileptr; fileptr += uBytesRead; |
1560 | 505 | FileHandle_Impl::Guard lock(&(pImpl->m_mutex)); |
1561 | 505 | oslFileError result = pImpl->readLineAt(pImpl->m_fileptr, ppSequence, &uBytesRead); |
1562 | | |
1563 | 505 | if (result == osl_File_E_None) |
1564 | 404 | pImpl->m_fileptr += uBytesRead; |
1565 | | |
1566 | 505 | return result; |
1567 | 505 | } |
1568 | | |
1569 | | oslFileError SAL_CALL osl_readFile( |
1570 | | oslFileHandle Handle, |
1571 | | void * pBuffer, |
1572 | | sal_uInt64 uBytesRequested, |
1573 | | sal_uInt64 * pBytesRead) |
1574 | 39.4M | { |
1575 | 39.4M | FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle); |
1576 | | |
1577 | 39.4M | if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pBuffer) || (!pBytesRead)) |
1578 | 0 | return osl_File_E_INVAL; |
1579 | | |
1580 | 39.4M | static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max(); |
1581 | 39.4M | if (g_limit_ssize_t < uBytesRequested) |
1582 | 0 | return osl_File_E_OVERFLOW; |
1583 | | |
1584 | 39.4M | size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested); |
1585 | | |
1586 | | // read at current fileptr; fileptr += *pBytesRead; |
1587 | 39.4M | FileHandle_Impl::Guard lock(&(pImpl->m_mutex)); |
1588 | 39.4M | oslFileError result = pImpl->readFileAt(pImpl->m_fileptr, pBuffer, nBytesRequested, pBytesRead); |
1589 | | |
1590 | 39.4M | if (result == osl_File_E_None) |
1591 | 39.4M | pImpl->m_fileptr += *pBytesRead; |
1592 | | |
1593 | 39.4M | return result; |
1594 | 39.4M | } |
1595 | | |
1596 | | oslFileError SAL_CALL osl_writeFile( |
1597 | | oslFileHandle Handle, |
1598 | | const void * pBuffer, |
1599 | | sal_uInt64 uBytesToWrite, |
1600 | | sal_uInt64 * pBytesWritten) |
1601 | 2.39M | { |
1602 | 2.39M | FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle); |
1603 | | |
1604 | 2.39M | if ((!pImpl) || (pImpl->m_fd == -1) || (!pBuffer) || (!pBytesWritten)) |
1605 | 0 | return osl_File_E_INVAL; |
1606 | | |
1607 | 2.39M | if (!(pImpl->m_state & State::Writeable)) |
1608 | 0 | return osl_File_E_BADF; |
1609 | | |
1610 | 2.39M | static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max(); |
1611 | 2.39M | if (g_limit_ssize_t < uBytesToWrite) |
1612 | 0 | return osl_File_E_OVERFLOW; |
1613 | | |
1614 | 2.39M | size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite); |
1615 | | |
1616 | | // write at current fileptr; fileptr += *pBytesWritten; |
1617 | 2.39M | FileHandle_Impl::Guard lock(&(pImpl->m_mutex)); |
1618 | 2.39M | oslFileError result = pImpl->writeFileAt(pImpl->m_fileptr, pBuffer, nBytesToWrite, pBytesWritten); |
1619 | 2.39M | if (result == osl_File_E_None) |
1620 | 2.39M | pImpl->m_fileptr += *pBytesWritten; |
1621 | | |
1622 | 2.39M | return result; |
1623 | 2.39M | } |
1624 | | |
1625 | | oslFileError SAL_CALL osl_readFileAt( |
1626 | | oslFileHandle Handle, |
1627 | | sal_uInt64 uOffset, |
1628 | | void* pBuffer, |
1629 | | sal_uInt64 uBytesRequested, |
1630 | | sal_uInt64* pBytesRead) |
1631 | 0 | { |
1632 | 0 | FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle); |
1633 | |
|
1634 | 0 | if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pBuffer) || (!pBytesRead)) |
1635 | 0 | return osl_File_E_INVAL; |
1636 | | |
1637 | 0 | if (!(pImpl->m_state & State::Seekable)) |
1638 | 0 | return osl_File_E_SPIPE; |
1639 | | |
1640 | 0 | if (exceedsMaxOffT(uOffset)) |
1641 | 0 | return osl_File_E_OVERFLOW; |
1642 | | |
1643 | 0 | off_t const nOffset = sal::static_int_cast< off_t >(uOffset); |
1644 | |
|
1645 | 0 | static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max(); |
1646 | 0 | if (g_limit_ssize_t < uBytesRequested) |
1647 | 0 | return osl_File_E_OVERFLOW; |
1648 | | |
1649 | 0 | size_t const nBytesRequested = sal::static_int_cast< size_t >(uBytesRequested); |
1650 | | |
1651 | | // read at specified fileptr |
1652 | 0 | FileHandle_Impl::Guard lock(&(pImpl->m_mutex)); |
1653 | |
|
1654 | 0 | return pImpl->readFileAt(nOffset, pBuffer, nBytesRequested, pBytesRead); |
1655 | 0 | } |
1656 | | |
1657 | | oslFileError SAL_CALL osl_writeFileAt( |
1658 | | oslFileHandle Handle, |
1659 | | sal_uInt64 uOffset, |
1660 | | const void* pBuffer, |
1661 | | sal_uInt64 uBytesToWrite, |
1662 | | sal_uInt64* pBytesWritten) |
1663 | 0 | { |
1664 | 0 | FileHandle_Impl* pImpl = static_cast<FileHandle_Impl*>(Handle); |
1665 | |
|
1666 | 0 | if ((!pImpl) || (pImpl->m_fd == -1) || (!pBuffer) || (!pBytesWritten)) |
1667 | 0 | return osl_File_E_INVAL; |
1668 | | |
1669 | 0 | if (!(pImpl->m_state & State::Seekable)) |
1670 | 0 | return osl_File_E_SPIPE; |
1671 | | |
1672 | 0 | if (!(pImpl->m_state & State::Writeable)) |
1673 | 0 | return osl_File_E_BADF; |
1674 | | |
1675 | 0 | if (exceedsMaxOffT(uOffset)) |
1676 | 0 | return osl_File_E_OVERFLOW; |
1677 | | |
1678 | 0 | off_t const nOffset = sal::static_int_cast< off_t >(uOffset); |
1679 | |
|
1680 | 0 | static sal_uInt64 const g_limit_ssize_t = std::numeric_limits< ssize_t >::max(); |
1681 | 0 | if (g_limit_ssize_t < uBytesToWrite) |
1682 | 0 | return osl_File_E_OVERFLOW; |
1683 | | |
1684 | 0 | size_t const nBytesToWrite = sal::static_int_cast< size_t >(uBytesToWrite); |
1685 | | |
1686 | | // write at specified fileptr |
1687 | 0 | FileHandle_Impl::Guard lock(&(pImpl->m_mutex)); |
1688 | |
|
1689 | 0 | return pImpl->writeFileAt(nOffset, pBuffer, nBytesToWrite, pBytesWritten); |
1690 | 0 | } |
1691 | | |
1692 | | oslFileError SAL_CALL osl_isEndOfFile(oslFileHandle Handle, sal_Bool *pIsEOF) |
1693 | 0 | { |
1694 | 0 | FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle); |
1695 | |
|
1696 | 0 | if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pIsEOF)) |
1697 | 0 | return osl_File_E_INVAL; |
1698 | | |
1699 | 0 | FileHandle_Impl::Guard lock(&(pImpl->m_mutex)); |
1700 | 0 | *pIsEOF = (pImpl->getPos() == pImpl->getSize()); |
1701 | |
|
1702 | 0 | return osl_File_E_None; |
1703 | 0 | } |
1704 | | |
1705 | | oslFileError SAL_CALL osl_getFilePos(oslFileHandle Handle, sal_uInt64* pPos) |
1706 | 8.08M | { |
1707 | 8.08M | FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle); |
1708 | | |
1709 | 8.08M | if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pPos)) |
1710 | 0 | return osl_File_E_INVAL; |
1711 | | |
1712 | | // no need to lock because pos is atomic |
1713 | 8.08M | *pPos = pImpl->getPos(); |
1714 | | |
1715 | 8.08M | return osl_File_E_None; |
1716 | 8.08M | } |
1717 | | |
1718 | | oslFileError SAL_CALL osl_setFilePos(oslFileHandle Handle, sal_uInt32 uHow, sal_Int64 uOffset) |
1719 | 55.2M | { |
1720 | 55.2M | FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle); |
1721 | | |
1722 | 55.2M | if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1))) |
1723 | 0 | return osl_File_E_INVAL; |
1724 | | |
1725 | 55.2M | if (exceedsMaxOffT(uOffset) || exceedsMinOffT(uOffset)) |
1726 | 0 | return osl_File_E_OVERFLOW; |
1727 | | |
1728 | 55.2M | off_t nPos = 0, nOffset = sal::static_int_cast< off_t >(uOffset); |
1729 | | |
1730 | 55.2M | FileHandle_Impl::Guard lock(&(pImpl->m_mutex)); |
1731 | 55.2M | switch (uHow) |
1732 | 55.2M | { |
1733 | 47.7M | case osl_Pos_Absolut: |
1734 | 47.7M | if (nOffset < 0) |
1735 | 0 | return osl_File_E_INVAL; |
1736 | 47.7M | break; |
1737 | | |
1738 | 47.7M | case osl_Pos_Current: |
1739 | 0 | nPos = sal::static_int_cast< off_t >(pImpl->getPos()); |
1740 | 0 | if ((nOffset < 0) && (nPos < -1*nOffset)) |
1741 | 0 | return osl_File_E_INVAL; |
1742 | | |
1743 | 0 | assert(nPos >= 0); |
1744 | 0 | if (nOffset > MAX_OFF_T - nPos) |
1745 | 0 | return osl_File_E_OVERFLOW; |
1746 | 0 | break; |
1747 | | |
1748 | 7.50M | case osl_Pos_End: |
1749 | 7.50M | nPos = sal::static_int_cast< off_t >(pImpl->getSize()); |
1750 | 7.50M | if ((nOffset < 0) && (nPos < -1*nOffset)) |
1751 | 0 | return osl_File_E_INVAL; |
1752 | | |
1753 | 7.50M | assert(nPos >= 0); |
1754 | 7.50M | if (nOffset > MAX_OFF_T - nPos) |
1755 | 0 | return osl_File_E_OVERFLOW; |
1756 | 7.50M | break; |
1757 | | |
1758 | 7.50M | default: |
1759 | 0 | return osl_File_E_INVAL; |
1760 | 55.2M | } |
1761 | | |
1762 | 55.2M | pImpl->setPos(nPos + nOffset); |
1763 | 55.2M | return osl_File_E_None; |
1764 | 55.2M | } |
1765 | | |
1766 | | oslFileError SAL_CALL osl_getFileSize(oslFileHandle Handle, sal_uInt64* pSize) |
1767 | 133k | { |
1768 | 133k | FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle); |
1769 | | |
1770 | 133k | if ((!pImpl) || ((pImpl->m_kind == FileHandle_Impl::KIND_FD) && (pImpl->m_fd == -1)) || (!pSize)) |
1771 | 0 | return osl_File_E_INVAL; |
1772 | | |
1773 | 133k | FileHandle_Impl::Guard lock(&(pImpl->m_mutex)); |
1774 | 133k | *pSize = pImpl->getSize(); |
1775 | | |
1776 | 133k | return osl_File_E_None; |
1777 | 133k | } |
1778 | | |
1779 | | oslFileError SAL_CALL osl_setFileSize(oslFileHandle Handle, sal_uInt64 uSize) |
1780 | 9.06k | { |
1781 | 9.06k | FileHandle_Impl* pImpl = static_cast< FileHandle_Impl* >(Handle); |
1782 | | |
1783 | 9.06k | if ((!pImpl) || (pImpl->m_fd == -1)) |
1784 | 0 | return osl_File_E_INVAL; |
1785 | | |
1786 | 9.06k | if (!(pImpl->m_state & State::Writeable)) |
1787 | 0 | return osl_File_E_BADF; |
1788 | | |
1789 | 9.06k | if (exceedsMaxOffT(uSize)) |
1790 | 0 | return osl_File_E_OVERFLOW; |
1791 | | |
1792 | 9.06k | oslFileError result = pImpl->syncFile(); |
1793 | 9.06k | if (result != osl_File_E_None) |
1794 | 0 | return result; |
1795 | | |
1796 | 9.06k | pImpl->m_bufptr = -1; |
1797 | 9.06k | pImpl->m_buflen = 0; |
1798 | | |
1799 | 9.06k | return pImpl->setSize(uSize); |
1800 | 9.06k | } |
1801 | | |
1802 | | |
1803 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |