Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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 &it;
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: */