Initial import.
[profile/ivi/apr.git] / file_io / os2 / readwrite.c
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
27 APR_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
125 APR_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
198 APR_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
222 APR_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
242 APR_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
249 APR_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
275 APR_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
284 APR_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
307 APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile)
308 {
309     return APR_ENOTIMPL;
310 }
311
312 APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile)
313 {
314     return APR_ENOTIMPL;
315 }
316
317 APR_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
353 APR_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
375 apr_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 }