1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr_arch_file_io.h"
18
19static apr_status_t setptr(apr_file_t *thefile, apr_off_t pos )
20{
21    apr_off_t newbufpos;
22    apr_status_t rv;
23
24    if (thefile->direction == 1) {
25        rv = apr_file_flush_locked(thefile);
26        if (rv) {
27            return rv;
28        }
29        thefile->bufpos = thefile->direction = thefile->dataRead = 0;
30    }
31
32    newbufpos = pos - (thefile->filePtr - thefile->dataRead);
33    if (newbufpos >= 0 && newbufpos <= thefile->dataRead) {
34        thefile->bufpos = newbufpos;
35        rv = APR_SUCCESS;
36    }
37    else {
38        if (lseek(thefile->filedes, pos, SEEK_SET) != -1) {
39            thefile->bufpos = thefile->dataRead = 0;
40            thefile->filePtr = pos;
41            rv = APR_SUCCESS;
42        }
43        else {
44            rv = errno;
45        }
46    }
47
48    return rv;
49}
50
51
52APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, apr_seek_where_t where, apr_off_t *offset)
53{
54    apr_off_t rv;
55
56    thefile->eof_hit = 0;
57
58    if (thefile->buffered) {
59        int rc = EINVAL;
60        apr_finfo_t finfo;
61
62        file_lock(thefile);
63
64        switch (where) {
65        case APR_SET:
66            rc = setptr(thefile, *offset);
67            break;
68
69        case APR_CUR:
70            rc = setptr(thefile, thefile->filePtr - thefile->dataRead + thefile->bufpos + *offset);
71            break;
72
73        case APR_END:
74            rc = apr_file_info_get_locked(&finfo, APR_FINFO_SIZE, thefile);
75            if (rc == APR_SUCCESS)
76                rc = setptr(thefile, finfo.size + *offset);
77            break;
78        }
79
80        *offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
81
82        file_unlock(thefile);
83
84        return rc;
85    }
86    else {
87        rv = lseek(thefile->filedes, *offset, where);
88        if (rv == -1) {
89            *offset = -1;
90            return errno;
91        }
92        else {
93            *offset = rv;
94            return APR_SUCCESS;
95        }
96    }
97}
98
99apr_status_t apr_file_trunc(apr_file_t *fp, apr_off_t offset)
100{
101    if (fp->buffered) {
102        int rc = 0;
103        file_lock(fp);
104        if (fp->direction == 1 && fp->bufpos != 0) {
105            apr_off_t len = fp->filePtr + fp->bufpos;
106            if (offset < len) {
107                /* New file end fall below our write buffer limit.
108                 * Figure out if and what needs to be flushed.
109                 */
110                apr_off_t off = len - offset;
111                if (off >= 0 && off <= fp->bufpos)
112                    fp->bufpos = fp->bufpos - (size_t)off;
113                else
114                    fp->bufpos = 0;
115            }
116            rc = apr_file_flush_locked(fp);
117            /* Reset buffer positions for write mode */
118            fp->bufpos = fp->direction = fp->dataRead = 0;
119        }
120        else if (fp->direction == 0) {
121            /* Discard the read buffer, as we are about to reposition
122             * ourselves to the end of file.
123             */
124            fp->bufpos = 0;
125            fp->dataRead = 0;
126        }
127        file_unlock(fp);
128        if (rc) {
129            return rc;
130        }
131    }
132    if (ftruncate(fp->filedes, offset) == -1) {
133        return errno;
134    }
135    return apr_file_seek(fp, APR_SET, &offset);
136}
137