source: sources/src/ioFileFifo.cc @ 1464:3f6711617be1

Revision 1464:3f6711617be1, 17.1 KB checked in by niam, 22 months ago (diff)

{issue #58[resolved]} support for non-c++ exceptions

Line 
1/***************************************************************************
2 *            ioFileFifo.cc
3 *
4 *  Wed Oct 8 2005
5 *  Copyright  2005  Dmytro Milinevskyy
6 *  milinevskyy@gmail.com
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License version 2.1 as published by
12 *  the Free Software Foundation;
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU Library General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/**
25 * vim indentation settings
26 * set tabstop=4
27 * set shiftwidth=4
28 */
29
30#include <libdodo/directives.h>
31
32#include <unistd.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <errno.h>
36#include <string.h>
37#include <fcntl.h>
38
39#include "ioFile.inline"
40
41#include <libdodo/ioFileFifo.h>
42#include <libdodo/toolsFilesystem.h>
43#include <libdodo/ioFileFifoEx.h>
44#include <libdodo/types.h>
45#include <libdodo/ioChannel.h>
46#include <libdodo/pcSyncStack.h>
47
48using namespace dodo::io::file;
49
50fifo::fifo(short protection) : stream::channel(protection),
51                               handle(new io::__file__),
52                               blocked(true)
53{
54#ifndef IO_WO_XEXEC
55    collectedData.setExecObject(xexec::OBJECT_IOFILEFIFO);
56#endif
57}
58
59//-------------------------------------------------------------------
60
61fifo::fifo(const dodo::string &path,
62           short            mode,
63           short            protection) : stream::channel(protection),
64                                          path(path),
65                                          mode(mode),
66                                          handle(new io::__file__),
67                                          blocked(true)
68{
69#ifndef IO_WO_XEXEC
70    collectedData.setExecObject(xexec::OBJECT_IOFILEFIFO);
71#endif
72
73    if (path.size() != 0) {
74        bool exists(false);
75        struct stat st;
76
77        if (::lstat(path.data(), &st) == -1) {
78            if (errno != ENOENT) {
79                delete handle;
80
81                dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_FIFO, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__, path);
82            }
83        } else
84            exists = true;
85
86        if (exists && !S_ISFIFO(st.st_mode)) {
87            delete handle;
88
89            dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_FIFO, exception::ERRNO_LIBDODO, FIFOEX_WRONGFILENAME, IOFILEFIFOEX_WRONGFILENAME_STR, __LINE__, __FILE__, path);
90        }
91
92        if (!exists) {
93            dodo_try {
94                tools::filesystem::mkfifo(path, DEFAULT_FILE_PERM);
95            } dodo_catch (exception::basic *e UNUSED) {
96                delete handle;
97
98                dodo_rethrow;
99            }
100        }
101
102        switch (mode) {
103            case OPEN_MODE_WRITE:
104
105                handle->file = fopen(path.data(), "w");
106
107                break;
108
109            case OPEN_MODE_READ_OPENNONBLOCK:
110            {
111#ifdef O_LARGEFILE
112                int fd = ::open(path.data(), O_NONBLOCK | O_RDONLY | O_LARGEFILE);
113#else
114                int fd = ::open(path.data(), O_NONBLOCK | O_RDONLY);
115#endif
116
117                int blockFlag = fcntl(fd, F_GETFL);
118                if (blockFlag == -1) {
119                    delete handle;
120
121                    dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_FIFO, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
122                }
123
124                blockFlag &= ~O_NONBLOCK;
125
126                if (fcntl(fd, F_SETFL, blockFlag) == -1) {
127                    delete handle;
128
129                    dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_FIFO, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
130                }
131
132                handle->file = fdopen(fd, "r");
133
134                break;
135            }
136
137            case OPEN_MODE_READ:
138            default:
139
140                handle->file = fopen(path.data(), "r");
141        }
142    }
143
144    if (handle->file == NULL) {
145        delete handle;
146
147        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_FIFO, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__, path);
148    }
149}
150
151//-------------------------------------------------------------------
152
153fifo::fifo(const fifo &fd) : stream::channel(fd.protection),
154                             path(fd.path),
155                             mode(fd.mode),
156                             handle(new __file__),
157                             blocked(fd.blocked)
158{
159#ifndef IO_WO_XEXEC
160    collectedData.setExecObject(xexec::OBJECT_IOFILEFIFO);
161#endif
162
163    bs = fd.bs;
164
165    if (fd.handle->file != NULL) {
166        int oldDesc, newDesc;
167
168        oldDesc = fileno(fd.handle->file);
169        if (oldDesc == -1) {
170            delete handle;
171
172            dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_FIFO, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
173        }
174
175        newDesc = dup(oldDesc);
176        if (newDesc == -1) {
177            delete handle;
178
179            dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_FIFO, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
180        }
181
182        switch (mode) {
183            case OPEN_MODE_WRITE:
184
185                handle->file = fdopen(newDesc, "w");
186
187                break;
188
189            case OPEN_MODE_READ:
190            default:
191
192                handle->file = fdopen(newDesc, "r");
193        }
194
195        if (handle->file == NULL) {
196            delete handle;
197
198            dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_FIFO, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
199        }
200    }
201}
202
203//-------------------------------------------------------------------
204
205fifo::~fifo()
206{
207    if (handle->file != NULL)
208        fclose(handle->file);
209
210    delete handle;
211}
212
213//-------------------------------------------------------------------
214
215int
216fifo::inDescriptor() const
217{
218    pc::sync::stack pg(keeper);
219
220    if (handle->file == NULL)
221        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_INDESCRIPTOR, exception::ERRNO_LIBDODO, FIFOEX_NOTOPENED, IOFILEFIFOEX_NOTOPENED_STR, __LINE__, __FILE__, path);
222
223    return fileno(handle->file);
224}
225
226//-------------------------------------------------------------------
227
228int
229fifo::outDescriptor() const
230{
231    pc::sync::stack pg(keeper);
232
233    if (handle->file == NULL)
234        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_OUTDESCRIPTOR, exception::ERRNO_LIBDODO, FIFOEX_NOTOPENED, IOFILEFIFOEX_NOTOPENED_STR, __LINE__, __FILE__, path);
235
236    return fileno(handle->file);
237}
238
239//-------------------------------------------------------------------
240
241void
242fifo::clone(const fifo &fd)
243{
244    pc::sync::stack pg(keeper);
245
246    if (handle->file != NULL) {
247        if (fclose(handle->file) != 0)
248            dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
249
250        handle->file = NULL;
251    }
252
253    blocked = fd.blocked;
254    path = fd.path;
255    mode = fd.mode;
256    bs = fd.bs;
257
258    if (fd.handle->file != NULL) {
259        int oldDesc, newDesc;
260
261        oldDesc = fileno(fd.handle->file);
262        if (oldDesc == -1)
263            dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
264
265        newDesc = dup(oldDesc);
266        if (newDesc == -1)
267            dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
268
269        switch (mode) {
270            case OPEN_MODE_WRITE:
271
272                handle->file = fdopen(newDesc, "w");
273
274                break;
275
276            case OPEN_MODE_READ:
277            default:
278
279                handle->file = fdopen(newDesc, "r");
280        }
281
282        if (handle->file == NULL)
283            dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_CLONE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
284    }
285}
286
287//-------------------------------------------------------------------
288
289void
290fifo::close()
291{
292    pc::sync::stack pg(keeper);
293
294#ifndef IO_WO_XEXEC
295    performPreExec(OPERATION_CLOSE);
296#endif
297
298    if (handle->file != NULL) {
299        if (fclose(handle->file) != 0)
300            dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_CLOSE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__, path);
301
302        handle->file = NULL;
303    }
304
305#ifndef IO_WO_XEXEC
306    performPostExec(OPERATION_CLOSE);
307#endif
308}
309
310//-------------------------------------------------------------------
311
312void
313fifo::open(const dodo::string &a_path,
314           short            a_mode)
315{
316    pc::sync::stack pg(keeper);
317
318#ifndef IO_WO_XEXEC
319    performPreExec(OPERATION_OPEN);
320#endif
321
322    path = a_path;
323    mode = a_mode;
324
325    if (handle->file != NULL) {
326        if (fclose(handle->file) != 0)
327            dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_OPEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__, path);
328
329        handle->file = NULL;
330    }
331
332    if (path.size() == 0)
333        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_OPEN, exception::ERRNO_LIBDODO, FIFOEX_WRONGFILENAME, IOFILEFIFOEX_WRONGFILENAME_STR, __LINE__, __FILE__, path);
334    else {
335        bool exists(false);
336        struct stat st;
337
338        if (::lstat(path.data(), &st) == -1) {
339            if (errno != ENOENT)
340                dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_OPEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__, path);
341        } else
342            exists = true;
343
344        if (exists && !S_ISFIFO(st.st_mode))
345            dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_OPEN, exception::ERRNO_LIBDODO, FIFOEX_WRONGFILENAME, IOFILEFIFOEX_WRONGFILENAME_STR, __LINE__, __FILE__, path);
346
347        if (!exists)
348            tools::filesystem::mkfifo(path, DEFAULT_FILE_PERM);
349
350        switch (mode) {
351            case OPEN_MODE_WRITE:
352
353                handle->file = fopen(path.data(), "w");
354
355                break;
356
357            case OPEN_MODE_READ_OPENNONBLOCK:
358            {
359#ifdef O_LARGEFILE
360                int fd = ::open(path.data(), O_NONBLOCK | O_RDONLY | O_LARGEFILE);
361#else
362                int fd = ::open(path.data(), O_NONBLOCK | O_RDONLY);
363#endif
364
365                int blockFlag = fcntl(fd, F_GETFL);
366                if (blockFlag == -1)
367                    dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_OPEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
368
369                blockFlag &= ~O_NONBLOCK;
370
371                if (fcntl(fd, F_SETFL, blockFlag) == -1)
372                    dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_OPEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
373
374                handle->file = fdopen(fd, "r");
375
376                break;
377            }
378
379            case OPEN_MODE_READ:
380            default:
381
382                handle->file = fopen(path.data(), "r");
383        }
384    }
385
386    if (handle->file == NULL)
387        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_OPEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__, path);
388
389#ifndef IO_WO_XEXEC
390    performPostExec(OPERATION_OPEN);
391#endif
392}
393
394//-------------------------------------------------------------------
395
396bool
397fifo::isBlocked()
398{
399    pc::sync::stack pg(keeper);
400
401    return blocked;
402}
403
404//-------------------------------------------------------------------
405
406void
407fifo::block(bool flag)
408{
409    pc::sync::stack pg(keeper);
410
411    if (handle->file == NULL)
412        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_BLOCK, exception::ERRNO_LIBDODO, FIFOEX_NOTOPENED, IOFILEFIFOEX_NOTOPENED_STR, __LINE__, __FILE__);
413
414    if (blocked == flag)
415        return;
416
417    int blockFlag;
418
419    int desc = fileno(handle->file);
420    if (desc == -1)
421        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_BLOCK, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
422
423    blockFlag = fcntl(desc, F_GETFL);
424    if (blockFlag == -1)
425        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_BLOCK, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
426
427    if (flag)
428        blockFlag &= ~O_NONBLOCK;
429    else
430        blockFlag |= O_NONBLOCK;
431
432    if (fcntl(desc, F_SETFL, blockFlag) == -1)
433        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_BLOCK, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
434
435    blocked = flag;
436}
437
438//-------------------------------------------------------------------
439
440unsigned long
441fifo::_read(char * const data) const
442{
443    if (handle->file == NULL)
444        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX__READ, exception::ERRNO_LIBDODO, FIFOEX_NOTOPENED, IOFILEFIFOEX_NOTOPENED_STR, __LINE__, __FILE__, path);
445
446    char *s = data;
447
448    unsigned long batch = bs, n;
449
450    while (batch != 0) {
451        while (true) {
452            if ((n = fread(s, 1, batch, handle->file)) == 0) {
453                if (feof(handle->file) != 0 || errno == EAGAIN)
454                    return bs - batch;
455
456                if (errno == EINTR)
457                    continue;
458
459                if (ferror(handle->file) != 0)
460                    dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX__READ, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
461            }
462
463            break;
464        }
465
466        batch -= n;
467        s += n;
468    }
469
470    return bs - batch;
471}
472
473//-------------------------------------------------------------------
474
475unsigned long
476fifo::_write(const char *const data) const
477{
478    if (handle->file == NULL)
479        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX__WRITE, exception::ERRNO_LIBDODO, FIFOEX_NOTOPENED, IOFILEFIFOEX_NOTOPENED_STR, __LINE__, __FILE__, path);
480
481    const char *s = data;
482
483    unsigned long batch = bs, n;
484
485    while (batch != 0) {
486        while (true) {
487            if ((n = fwrite(s, 1, batch, handle->file)) == 0) {
488                if (errno == EINTR)
489                    continue;
490
491                if (errno == EAGAIN)
492                    return bs - batch;
493
494                if (ferror(handle->file) != 0)
495                    dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX__WRITE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
496            }
497
498            break;
499        }
500
501        batch -= n;
502        s += n;
503    }
504
505    return bs;
506}
507
508//-------------------------------------------------------------------
509
510void
511fifo::flush() const
512{
513    pc::sync::stack pg(keeper);
514
515    if (handle->file == NULL)
516        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_FLUSH, exception::ERRNO_LIBDODO, FIFOEX_NOTOPENED, IOFILEFIFOEX_NOTOPENED_STR, __LINE__, __FILE__, path);
517
518    if (fflush(handle->file) != 0)
519        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX_FLUSH, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__, path);
520}
521
522//-------------------------------------------------------------------
523
524unsigned long
525fifo::_readString(char * const data) const
526{
527    if (handle->file == NULL)
528        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX__READSTRING, exception::ERRNO_LIBDODO, FIFOEX_NOTOPENED, IOFILEFIFOEX_NOTOPENED_STR, __LINE__, __FILE__, path);
529
530    unsigned long readSize = bs + 1;
531
532    while (true) {
533        if (fgets(data, readSize, handle->file) == NULL) {
534            if (errno == EINTR)
535                continue;
536
537            if (errno == EAGAIN)
538                return 0;
539
540            if (ferror(handle->file) != 0)
541                dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX__READSTRING, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
542        }
543
544        break;
545    }
546
547    return strlen(data);
548}
549
550//-------------------------------------------------------------------
551
552unsigned long
553fifo::_writeString(const char *const data) const
554{
555    unsigned long _bs = bs;
556    unsigned long written;
557
558    dodo_try {
559        bs = strnlen(data, bs);
560
561        written = _write(data);
562
563        if (data[bs - 1] != '\n') {
564            while (true) {
565                if (fputc('\n', handle->file) == EOF) {
566                    if (errno == EINTR)
567                        continue;
568
569                    if (errno == EAGAIN)
570                        break;
571
572                    if (ferror(handle->file) != 0)
573                        dodo_throw exception::basic(exception::MODULE_IOFILEFIFO, FIFOEX__WRITESTRING, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
574                }
575
576                break;
577            }
578        }
579
580        bs = _bs;
581    } dodo_catch (exception::basic *e UNUSED) {
582        bs = _bs;
583
584        dodo_rethrow;
585    }
586
587    return written;
588}
589
590//-------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.