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#define INCL_DOS
18#define INCL_DOSERRORS
19
20#include "apr_arch_file_io.h"
21#include "apr_file_io.h"
22#include "apr_lib.h"
23#include "apr_strings.h"
24
25#include <malloc.h>
26
27APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes)
28{
29    ULONG rc = 0;
30    ULONG bytesread;
31
32    if (!thefile->isopen) {
33        *nbytes = 0;
34        return APR_EBADF;
35    }
36
37    if (thefile->buffered) {
38        char *pos = (char *)buf;
39        ULONG blocksize;
40        ULONG size = *nbytes;
41
42        apr_thread_mutex_lock(thefile->mutex);
43
44        if (thefile->direction == 1) {
45            int rv = apr_file_flush(thefile);
46
47            if (rv != APR_SUCCESS) {
48                apr_thread_mutex_unlock(thefile->mutex);
49                return rv;
50            }
51
52            thefile->bufpos = 0;
53            thefile->direction = 0;
54            thefile->dataRead = 0;
55        }
56
57        while (rc == 0 && size > 0) {
58            if (thefile->bufpos >= thefile->dataRead) {
59                ULONG bytesread;
60                rc = DosRead(thefile->filedes, thefile->buffer,
61                             thefile->bufsize, &bytesread);
62
63                if (bytesread == 0) {
64                    if (rc == 0)
65                        thefile->eof_hit = TRUE;
66                    break;
67                }
68
69                thefile->dataRead = bytesread;
70                thefile->filePtr += thefile->dataRead;
71                thefile->bufpos = 0;
72            }
73
74            blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size;
75            memcpy(pos, thefile->buffer + thefile->bufpos, blocksize);
76            thefile->bufpos += blocksize;
77            pos += blocksize;
78            size -= blocksize;
79        }
80
81        *nbytes = rc == 0 ? pos - (char *)buf : 0;
82        apr_thread_mutex_unlock(thefile->mutex);
83
84        if (*nbytes == 0 && rc == 0 && thefile->eof_hit) {
85            return APR_EOF;
86        }
87
88        return APR_FROM_OS_ERROR(rc);
89    } else {
90        if (thefile->pipe)
91            DosResetEventSem(thefile->pipeSem, &rc);
92
93        rc = DosRead(thefile->filedes, buf, *nbytes, &bytesread);
94
95        if (rc == ERROR_NO_DATA && thefile->timeout != 0) {
96            int rcwait = DosWaitEventSem(thefile->pipeSem, thefile->timeout >= 0 ? thefile->timeout / 1000 : SEM_INDEFINITE_WAIT);
97
98            if (rcwait == 0) {
99                rc = DosRead(thefile->filedes, buf, *nbytes, &bytesread);
100            }
101            else if (rcwait == ERROR_TIMEOUT) {
102                *nbytes = 0;
103                return APR_TIMEUP;
104            }
105        }
106
107        if (rc) {
108            *nbytes = 0;
109            return APR_FROM_OS_ERROR(rc);
110        }
111
112        *nbytes = bytesread;
113
114        if (bytesread == 0) {
115            thefile->eof_hit = TRUE;
116            return APR_EOF;
117        }
118
119        return APR_SUCCESS;
120    }
121}
122
123
124
125APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes)
126{
127    ULONG rc = 0;
128    ULONG byteswritten;
129
130    if (!thefile->isopen) {
131        *nbytes = 0;
132        return APR_EBADF;
133    }
134
135    if (thefile->buffered) {
136        char *pos = (char *)buf;
137        int blocksize;
138        int size = *nbytes;
139
140        apr_thread_mutex_lock(thefile->mutex);
141
142        if ( thefile->direction == 0 ) {
143            /* Position file pointer for writing at the offset we are logically reading from */
144            ULONG offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
145            if (offset != thefile->filePtr)
146                DosSetFilePtr(thefile->filedes, offset, FILE_BEGIN, &thefile->filePtr );
147            thefile->bufpos = thefile->dataRead = 0;
148            thefile->direction = 1;
149        }
150
151        while (rc == 0 && size > 0) {
152            if (thefile->bufpos == thefile->bufsize) /* write buffer is full */
153                /* XXX bug; - rc is double-transformed os->apr below */
154                rc = apr_file_flush(thefile);
155
156            blocksize = size > thefile->bufsize - thefile->bufpos ? thefile->bufsize - thefile->bufpos : size;
157            memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);
158            thefile->bufpos += blocksize;
159            pos += blocksize;
160            size -= blocksize;
161        }
162
163        apr_thread_mutex_unlock(thefile->mutex);
164        return APR_FROM_OS_ERROR(rc);
165    } else {
166        if (thefile->flags & APR_FOPEN_APPEND) {
167            FILELOCK all = { 0, 0x7fffffff };
168            ULONG newpos;
169            rc = DosSetFileLocks(thefile->filedes, NULL, &all, -1, 0);
170
171            if (rc == 0) {
172                rc = DosSetFilePtr(thefile->filedes, 0, FILE_END, &newpos);
173
174                if (rc == 0) {
175                    rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten);
176                }
177
178                DosSetFileLocks(thefile->filedes, &all, NULL, -1, 0);
179            }
180        } else {
181            rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten);
182        }
183
184        if (rc) {
185            *nbytes = 0;
186            return APR_FROM_OS_ERROR(rc);
187        }
188
189        *nbytes = byteswritten;
190        return APR_SUCCESS;
191    }
192}
193
194
195
196#ifdef HAVE_WRITEV
197
198APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec, apr_size_t nvec, apr_size_t *nbytes)
199{
200    int bytes;
201
202    if (thefile->buffered) {
203        apr_status_t rv = apr_file_flush(thefile);
204        if (rv != APR_SUCCESS) {
205            return rv;
206        }
207    }
208
209    if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) {
210        *nbytes = 0;
211        return errno;
212    }
213    else {
214        *nbytes = bytes;
215        return APR_SUCCESS;
216    }
217}
218#endif
219
220
221
222APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile)
223{
224    ULONG rc;
225    ULONG byteswritten;
226
227    if (!thefile->isopen) {
228        return APR_EBADF;
229    }
230
231    rc = DosWrite(thefile->filedes, &ch, 1, &byteswritten);
232
233    if (rc) {
234        return APR_FROM_OS_ERROR(rc);
235    }
236
237    return APR_SUCCESS;
238}
239
240
241
242APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile)
243{
244    apr_off_t offset = -1;
245    return apr_file_seek(thefile, APR_CUR, &offset);
246}
247
248
249APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile)
250{
251    ULONG rc;
252    apr_size_t bytesread;
253
254    if (!thefile->isopen) {
255        return APR_EBADF;
256    }
257
258    bytesread = 1;
259    rc = apr_file_read(thefile, ch, &bytesread);
260
261    if (rc) {
262        return rc;
263    }
264
265    if (bytesread == 0) {
266        thefile->eof_hit = TRUE;
267        return APR_EOF;
268    }
269
270    return APR_SUCCESS;
271}
272
273
274
275APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
276{
277    apr_size_t len;
278
279    len = strlen(str);
280    return apr_file_write(thefile, str, &len);
281}
282
283
284APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile)
285{
286    if (thefile->buffered) {
287        ULONG written = 0;
288        int rc = 0;
289
290        if (thefile->direction == 1 && thefile->bufpos) {
291            rc = DosWrite(thefile->filedes, thefile->buffer, thefile->bufpos, &written);
292            thefile->filePtr += written;
293
294            if (rc == 0)
295                thefile->bufpos = 0;
296        }
297
298        return APR_FROM_OS_ERROR(rc);
299    } else {
300        /* There isn't anything to do if we aren't buffering the output
301         * so just return success.
302         */
303        return APR_SUCCESS;
304    }
305}
306
307APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile)
308{
309    return APR_ENOTIMPL;
310}
311
312APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile)
313{
314    return APR_ENOTIMPL;
315}
316
317APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile)
318{
319    apr_size_t readlen;
320    apr_status_t rv = APR_SUCCESS;
321    int i;
322
323    for (i = 0; i < len-1; i++) {
324        readlen = 1;
325        rv = apr_file_read(thefile, str+i, &readlen);
326
327        if (rv != APR_SUCCESS) {
328            break;
329        }
330
331        if (readlen != 1) {
332            rv = APR_EOF;
333            break;
334        }
335
336        if (str[i] == '\n') {
337            i++;
338            break;
339        }
340    }
341    str[i] = 0;
342    if (i > 0) {
343        /* we stored chars; don't report EOF or any other errors;
344         * the app will find out about that on the next call
345         */
346        return APR_SUCCESS;
347    }
348    return rv;
349}
350
351
352
353APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr,
354                                        const char *format, ...)
355{
356    int cc;
357    va_list ap;
358    char *buf;
359    int len;
360
361    buf = malloc(HUGE_STRING_LEN);
362    if (buf == NULL) {
363        return 0;
364    }
365    va_start(ap, format);
366    len = apr_vsnprintf(buf, HUGE_STRING_LEN, format, ap);
367    cc = apr_file_puts(buf, fptr);
368    va_end(ap);
369    free(buf);
370    return (cc == APR_SUCCESS) ? len : -1;
371}
372
373
374
375apr_status_t apr_file_check_read(apr_file_t *fd)
376{
377    int rc;
378
379    if (!fd->pipe)
380        return APR_SUCCESS; /* Not a pipe, assume no waiting */
381
382    rc = DosWaitEventSem(fd->pipeSem, SEM_IMMEDIATE_RETURN);
383
384    if (rc == ERROR_TIMEOUT)
385        return APR_TIMEUP;
386
387    return APR_FROM_OS_ERROR(rc);
388}
389