Subversion Repositories HelenOS

Rev

Rev 4491 | Rev 4508 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4491 Rev 4492
1
/*
1
/*
2
 * Copyright (c) 2005 Martin Decky
2
 * Copyright (c) 2005 Martin Decky
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup libc
29
/** @addtogroup libc
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <stdio.h>
35
#include <stdio.h>
36
#include <unistd.h>
36
#include <unistd.h>
37
#include <fcntl.h>
37
#include <fcntl.h>
38
#include <string.h>
38
#include <string.h>
39
#include <errno.h>
39
#include <errno.h>
40
#include <bool.h>
40
#include <bool.h>
41
#include <malloc.h>
41
#include <malloc.h>
42
#include <io/klog.h>
42
#include <io/klog.h>
43
#include <vfs/vfs.h>
43
#include <vfs/vfs.h>
44
#include <ipc/devmap.h>
44
#include <ipc/devmap.h>
45
 
45
 
46
FILE stdin_null = {
46
FILE stdin_null = {
47
    .fd = -1,
47
    .fd = -1,
48
    .error = true,
48
    .error = true,
49
    .eof = true,
49
    .eof = true,
50
    .klog = false,
50
    .klog = false,
51
    .phone = -1
51
    .phone = -1
52
};
52
};
53
 
53
 
54
FILE stdout_klog = {
54
FILE stdout_klog = {
55
    .fd = -1,
55
    .fd = -1,
56
    .error = false,
56
    .error = false,
57
    .eof = false,
57
    .eof = false,
58
    .klog = true,
58
    .klog = true,
59
    .phone = -1
59
    .phone = -1
60
};
60
};
61
 
61
 
62
FILE *stdin = &stdin_null;
62
FILE *stdin = &stdin_null;
63
FILE *stdout = &stdout_klog;
63
FILE *stdout = &stdout_klog;
64
FILE *stderr = &stdout_klog;
64
FILE *stderr = &stdout_klog;
65
 
65
 
66
static bool parse_mode(const char *mode, int *flags)
66
static bool parse_mode(const char *mode, int *flags)
67
{
67
{
68
    /* Parse mode except first character. */
68
    /* Parse mode except first character. */
69
    const char *mp = mode;
69
    const char *mp = mode;
70
    if (*mp++ == 0) {
70
    if (*mp++ == 0) {
71
        errno = EINVAL;
71
        errno = EINVAL;
72
        return false;
72
        return false;
73
    }
73
    }
74
   
74
   
75
    if ((*mp == 'b') || (*mp == 't'))
75
    if ((*mp == 'b') || (*mp == 't'))
76
        mp++;
76
        mp++;
77
   
77
   
78
    bool plus;
78
    bool plus;
79
    if (*mp == '+') {
79
    if (*mp == '+') {
80
        mp++;
80
        mp++;
81
        plus = true;
81
        plus = true;
82
    } else
82
    } else
83
        plus = false;
83
        plus = false;
84
   
84
   
85
    if (*mp != 0) {
85
    if (*mp != 0) {
86
        errno = EINVAL;
86
        errno = EINVAL;
87
        return false;
87
        return false;
88
    }
88
    }
89
   
89
   
90
    /* Parse first character of mode and determine flags for open(). */
90
    /* Parse first character of mode and determine flags for open(). */
91
    switch (mode[0]) {
91
    switch (mode[0]) {
92
    case 'r':
92
    case 'r':
93
        *flags = plus ? O_RDWR : O_RDONLY;
93
        *flags = plus ? O_RDWR : O_RDONLY;
94
        break;
94
        break;
95
    case 'w':
95
    case 'w':
96
        *flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
96
        *flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
97
        break;
97
        break;
98
    case 'a':
98
    case 'a':
99
        /* TODO: a+ must read from beginning, append to the end. */
99
        /* TODO: a+ must read from beginning, append to the end. */
100
        if (plus) {
100
        if (plus) {
101
            errno = ENOTSUP;
101
            errno = ENOTSUP;
102
            return false;
102
            return false;
103
        }
103
        }
104
        *flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
104
        *flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
105
    default:
105
    default:
106
        errno = EINVAL;
106
        errno = EINVAL;
107
        return false;
107
        return false;
108
    }
108
    }
109
   
109
   
110
    return true;
110
    return true;
111
}
111
}
112
 
112
 
113
/** Open a stream.
113
/** Open a stream.
114
 *
114
 *
115
 * @param path Path of the file to open.
115
 * @param path Path of the file to open.
116
 * @param mode Mode string, (r|w|a)[b|t][+].
116
 * @param mode Mode string, (r|w|a)[b|t][+].
117
 *
117
 *
118
 */
118
 */
119
FILE *fopen(const char *path, const char *mode)
119
FILE *fopen(const char *path, const char *mode)
120
{
120
{
121
    int flags;
121
    int flags;
122
    if (!parse_mode(mode, &flags))
122
    if (!parse_mode(mode, &flags))
123
        return NULL;
123
        return NULL;
124
   
124
   
125
    /* Open file. */
125
    /* Open file. */
126
    FILE *stream = malloc(sizeof(FILE));
126
    FILE *stream = malloc(sizeof(FILE));
127
    if (stream == NULL) {
127
    if (stream == NULL) {
128
        errno = ENOMEM;
128
        errno = ENOMEM;
129
        return NULL;
129
        return NULL;
130
    }
130
    }
131
   
131
   
132
    stream->fd = open(path, flags, 0666);
132
    stream->fd = open(path, flags, 0666);
133
    if (stream->fd < 0) {
133
    if (stream->fd < 0) {
134
        /* errno was set by open() */
134
        /* errno was set by open() */
135
        free(stream);
135
        free(stream);
136
        return NULL;
136
        return NULL;
137
    }
137
    }
138
   
138
   
139
    stream->error = false;
139
    stream->error = false;
140
    stream->eof = false;
140
    stream->eof = false;
141
    stream->klog = false;
141
    stream->klog = false;
142
    stream->phone = -1;
142
    stream->phone = -1;
143
   
143
   
144
    return stream;
144
    return stream;
145
}
145
}
146
 
146
 
147
FILE *fopen_node(inode_t *node, const char *mode)
147
FILE *fopen_node(fdi_node_t *node, const char *mode)
148
{
148
{
149
    int flags;
149
    int flags;
150
    if (!parse_mode(mode, &flags))
150
    if (!parse_mode(mode, &flags))
151
        return NULL;
151
        return NULL;
152
   
152
   
153
    /* Open file. */
153
    /* Open file. */
154
    FILE *stream = malloc(sizeof(FILE));
154
    FILE *stream = malloc(sizeof(FILE));
155
    if (stream == NULL) {
155
    if (stream == NULL) {
156
        errno = ENOMEM;
156
        errno = ENOMEM;
157
        return NULL;
157
        return NULL;
158
    }
158
    }
159
   
159
   
160
    stream->fd = open_node(node, flags);
160
    stream->fd = open_node(node, flags);
161
    if (stream->fd < 0) {
161
    if (stream->fd < 0) {
162
        /* errno was set by open_node() */
162
        /* errno was set by open_node() */
163
        free(stream);
163
        free(stream);
164
        return NULL;
164
        return NULL;
165
    }
165
    }
166
   
166
   
167
    stream->error = false;
167
    stream->error = false;
168
    stream->eof = false;
168
    stream->eof = false;
169
    stream->klog = false;
169
    stream->klog = false;
170
    stream->phone = -1;
170
    stream->phone = -1;
171
   
171
   
172
    return stream;
172
    return stream;
173
}
173
}
174
 
174
 
175
int fclose(FILE *stream)
175
int fclose(FILE *stream)
176
{
176
{
177
    int rc = 0;
177
    int rc = 0;
178
   
178
   
179
    fflush(stream);
179
    fflush(stream);
180
   
180
   
181
    if (stream->phone >= 0)
181
    if (stream->phone >= 0)
182
        ipc_hangup(stream->phone);
182
        ipc_hangup(stream->phone);
183
   
183
   
184
    if (stream->fd >= 0)
184
    if (stream->fd >= 0)
185
        rc = close(stream->fd);
185
        rc = close(stream->fd);
186
   
186
   
187
    if ((stream != &stdin_null) && (stream != &stdout_klog))
187
    if ((stream != &stdin_null) && (stream != &stdout_klog))
188
        free(stream);
188
        free(stream);
189
   
189
   
190
    stream = NULL;
190
    stream = NULL;
191
   
191
   
192
    if (rc != 0) {
192
    if (rc != 0) {
193
        /* errno was set by close() */
193
        /* errno was set by close() */
194
        return EOF;
194
        return EOF;
195
    }
195
    }
196
   
196
   
197
    return 0;
197
    return 0;
198
}
198
}
199
 
199
 
200
/** Read from a stream.
200
/** Read from a stream.
201
 *
201
 *
202
 * @param buf    Destination buffer.
202
 * @param buf    Destination buffer.
203
 * @param size   Size of each record.
203
 * @param size   Size of each record.
204
 * @param nmemb  Number of records to read.
204
 * @param nmemb  Number of records to read.
205
 * @param stream Pointer to the stream.
205
 * @param stream Pointer to the stream.
206
 *
206
 *
207
 */
207
 */
208
size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream)
208
size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream)
209
{
209
{
210
    size_t left = size * nmemb;
210
    size_t left = size * nmemb;
211
    size_t done = 0;
211
    size_t done = 0;
212
   
212
   
213
    while ((left > 0) && (!stream->error) && (!stream->eof)) {
213
    while ((left > 0) && (!stream->error) && (!stream->eof)) {
214
        ssize_t rd = read(stream->fd, buf + done, left);
214
        ssize_t rd = read(stream->fd, buf + done, left);
215
       
215
       
216
        if (rd < 0)
216
        if (rd < 0)
217
            stream->error = true;
217
            stream->error = true;
218
        else if (rd == 0)
218
        else if (rd == 0)
219
            stream->eof = true;
219
            stream->eof = true;
220
        else {
220
        else {
221
            left -= rd;
221
            left -= rd;
222
            done += rd;
222
            done += rd;
223
        }
223
        }
224
    }
224
    }
225
   
225
   
226
    return (done / size);
226
    return (done / size);
227
}
227
}
228
 
228
 
229
/** Write to a stream.
229
/** Write to a stream.
230
 *
230
 *
231
 * @param buf    Source buffer.
231
 * @param buf    Source buffer.
232
 * @param size   Size of each record.
232
 * @param size   Size of each record.
233
 * @param nmemb  Number of records to write.
233
 * @param nmemb  Number of records to write.
234
 * @param stream Pointer to the stream.
234
 * @param stream Pointer to the stream.
235
 *
235
 *
236
 */
236
 */
237
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
237
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
238
{
238
{
239
    size_t left = size * nmemb;
239
    size_t left = size * nmemb;
240
    size_t done = 0;
240
    size_t done = 0;
241
   
241
   
242
    while ((left > 0) && (!stream->error)) {
242
    while ((left > 0) && (!stream->error)) {
243
        ssize_t wr;
243
        ssize_t wr;
244
       
244
       
245
        if (stream->klog)
245
        if (stream->klog)
246
            wr = klog_write(buf + done, left);
246
            wr = klog_write(buf + done, left);
247
        else
247
        else
248
            wr = write(stream->fd, buf + done, left);
248
            wr = write(stream->fd, buf + done, left);
249
       
249
       
250
        if (wr <= 0)
250
        if (wr <= 0)
251
            stream->error = true;
251
            stream->error = true;
252
        else {
252
        else {
253
            left -= wr;
253
            left -= wr;
254
            done += wr;
254
            done += wr;
255
        }
255
        }
256
    }
256
    }
257
   
257
   
258
    return (done / size);
258
    return (done / size);
259
}
259
}
260
 
260
 
261
int fputc(wchar_t c, FILE *stream)
261
int fputc(wchar_t c, FILE *stream)
262
{
262
{
263
    char buf[STR_BOUNDS(1)];
263
    char buf[STR_BOUNDS(1)];
264
    size_t sz = 0;
264
    size_t sz = 0;
265
   
265
   
266
    if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
266
    if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
267
        size_t wr = fwrite(buf, sz, 1, stream);
267
        size_t wr = fwrite(buf, sz, 1, stream);
268
       
268
       
269
        if (wr < sz)
269
        if (wr < sz)
270
            return EOF;
270
            return EOF;
271
       
271
       
272
        return (int) c;
272
        return (int) c;
273
    }
273
    }
274
   
274
   
275
    return EOF;
275
    return EOF;
276
}
276
}
277
 
277
 
278
int putchar(wchar_t c)
278
int putchar(wchar_t c)
279
{
279
{
280
    return fputc(c, stdout);
280
    return fputc(c, stdout);
281
}
281
}
282
 
282
 
283
int fputs(const char *str, FILE *stream)
283
int fputs(const char *str, FILE *stream)
284
{
284
{
285
    return fwrite(str, str_size(str), 1, stream);
285
    return fwrite(str, str_size(str), 1, stream);
286
}
286
}
287
 
287
 
288
int puts(const char *str)
288
int puts(const char *str)
289
{
289
{
290
    return fputs(str, stdout);
290
    return fputs(str, stdout);
291
}
291
}
292
 
292
 
293
int fgetc(FILE *stream)
293
int fgetc(FILE *stream)
294
{
294
{
295
    char c;
295
    char c;
296
   
296
   
297
    if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
297
    if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
298
        return EOF;
298
        return EOF;
299
   
299
   
300
    return (int) c;
300
    return (int) c;
301
}
301
}
302
 
302
 
303
int getchar(void)
303
int getchar(void)
304
{
304
{
305
    return fgetc(stdin);
305
    return fgetc(stdin);
306
}
306
}
307
 
307
 
308
int fseek(FILE *stream, long offset, int origin)
308
int fseek(FILE *stream, long offset, int origin)
309
{
309
{
310
    off_t rc = lseek(stream->fd, offset, origin);
310
    off_t rc = lseek(stream->fd, offset, origin);
311
    if (rc == (off_t) (-1)) {
311
    if (rc == (off_t) (-1)) {
312
        /* errno has been set by lseek. */
312
        /* errno has been set by lseek. */
313
        return -1;
313
        return -1;
314
    }
314
    }
315
   
315
   
316
    stream->eof = false;
316
    stream->eof = false;
317
   
317
   
318
    return 0;
318
    return 0;
319
}
319
}
320
 
320
 
321
int fflush(FILE *stream)
321
int fflush(FILE *stream)
322
{
322
{
323
    if (stream->klog) {
323
    if (stream->klog) {
324
        klog_update();
324
        klog_update();
325
        return EOK;
325
        return EOK;
326
    }
326
    }
327
   
327
   
328
    if (stream->fd >= 0)
328
    if (stream->fd >= 0)
329
        return fsync(stream->fd);
329
        return fsync(stream->fd);
330
   
330
   
331
    return ENOENT;
331
    return ENOENT;
332
}
332
}
333
 
333
 
334
int feof(FILE *stream)
334
int feof(FILE *stream)
335
{
335
{
336
    return stream->eof;
336
    return stream->eof;
337
}
337
}
338
 
338
 
339
int ferror(FILE *stream)
339
int ferror(FILE *stream)
340
{
340
{
341
    return stream->error;
341
    return stream->error;
342
}
342
}
343
 
343
 
344
int fphone(FILE *stream)
344
int fphone(FILE *stream)
345
{
345
{
346
    if (stream->fd >= 0) {
346
    if (stream->fd >= 0) {
347
        if (stream->phone < 0)
347
        if (stream->phone < 0)
348
            stream->phone = fd_phone(stream->fd);
348
            stream->phone = fd_phone(stream->fd);
349
       
349
       
350
        return stream->phone;
350
        return stream->phone;
351
    }
351
    }
352
   
352
   
353
    return -1;
353
    return -1;
354
}
354
}
355
 
355
 
356
void fnode(FILE *stream, inode_t *node)
356
void fnode(FILE *stream, fdi_node_t *node)
357
{
357
{
358
    if (stream->fd >= 0) {
358
    if (stream->fd >= 0) {
359
        fd_node(stream->fd, node);
359
        fd_node(stream->fd, node);
360
    } else {
360
    } else {
361
        node->fs_handle = 0;
361
        node->fs_handle = 0;
362
        node->dev_handle = 0;
362
        node->dev_handle = 0;
363
        node->index = 0;
363
        node->index = 0;
364
    }
364
    }
365
}
365
}
366
 
366
 
367
/** @}
367
/** @}
368
 */
368
 */
369
 
369