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