208371df8bff5b33bedb5ddbd72847dfc6fcf7d2
[libs/core.git] / source / io / file.cpp
1 #ifndef WIN32
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #endif
6 #include <msp/strings/format.h>
7 #include <msp/core/systemerror.h>
8 #include "file.h"
9 #include "handle_private.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace IO {
15
16 File::File(const string &fn, Mode m, CreateMode cm)
17 {
18         if(!(m&M_RDWR))
19                 throw invalid_argument("File::File mode");
20         if(cm&~(C_CREATE|C_TRUNCATE|C_EXCLUSIVE))
21                 throw invalid_argument("File::File create");
22         if((cm&C_EXCLUSIVE) && (!(cm&C_CREATE) || (cm&C_TRUNCATE)))
23                 throw invalid_argument("File::File create");
24
25         mode = m;
26
27 #ifdef WIN32
28         int flags = 0;
29         int create_flags = OPEN_EXISTING;
30
31         if(mode&M_READ)
32                 flags |= GENERIC_READ;
33         else if(mode&M_WRITE)
34         {
35                 flags |= GENERIC_WRITE;
36
37                 switch(static_cast<int>(cm))
38                 {
39                 case C_NONE:     create_flags = OPEN_EXISTING; break;
40                 case C_CREATE:   create_flags = OPEN_ALWAYS; break;
41                 case C_TRUNCATE: create_flags = TRUNCATE_EXISTING; break;
42                 case C_CREATE+C_TRUNCATE: create_flags = CREATE_ALWAYS; break;
43                 case C_CREATE+C_EXCLUSIVE: create_flags = CREATE_NEW; break;
44                 }
45         }
46
47         *handle = CreateFile(fn.c_str(), flags, 0, 0, create_flags, FILE_ATTRIBUTE_NORMAL, 0);
48         if(!handle)
49         {
50                 int err = GetLastError();
51                 if(err==ERROR_FILE_NOT_FOUND)
52                         throw file_not_found(fn);
53                 else if(err==ERROR_FILE_EXISTS)
54                         throw file_already_exists(fn);
55                 else
56                         throw system_error(format("CreateFile(%s)", fn), err);
57         }
58 #else
59         int flags = 0;
60         switch(mode&M_RDWR)
61         {
62         case M_READ:  flags |= O_RDONLY; break;
63         case M_WRITE: flags |= O_WRONLY; break;
64         case M_RDWR:  flags |= O_RDWR; break;
65         default:;
66         }
67
68         if(mode&M_WRITE)
69         {
70                 if(cm&C_CREATE)
71                         flags |= O_CREAT;
72                 if(cm&C_TRUNCATE)
73                         flags |= O_TRUNC;
74                 if(cm&C_EXCLUSIVE)
75                         flags |= O_EXCL;
76         }
77         if(mode&M_APPEND)
78                 flags |= O_APPEND;
79         if(mode&M_NONBLOCK)
80                 flags |= O_NONBLOCK;
81
82         *handle = ::open(fn.c_str(), flags, 0666);
83         if(!handle)
84         {
85                 int err = errno;
86                 if(err==ENOENT)
87                         throw file_not_found(fn);
88                 else if(err==EEXIST)
89                         throw file_already_exists(fn);
90                 else
91                         throw system_error(format("open(%s)", fn), err);
92         }
93 #endif
94 }
95
96 File::~File()
97 {
98         signal_flush_required.emit();
99         sys_close(handle);
100 }
101
102 void File::set_block(bool b)
103 {
104         mode = (mode&~M_NONBLOCK);
105         if(b)
106                 mode = (mode|M_NONBLOCK);
107 #ifndef WIN32
108         int flags = fcntl(*handle, F_GETFD);
109         fcntl(*handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK));
110 #endif
111 }
112
113 unsigned File::do_write(const char *buf, unsigned size)
114 {
115         check_access(M_WRITE);
116
117         if(size==0)
118                 return 0;
119
120 #ifdef WIN32
121         if(mode&M_APPEND)
122                 seek(0, S_END);
123 #endif
124
125         return sys_write(handle, buf, size);
126 }
127
128 unsigned File::do_read(char *buf, unsigned size)
129 {
130         check_access(M_READ);
131
132         if(size==0)
133                 return 0;
134
135         unsigned ret = sys_read(handle, buf, size);
136         if(ret==0)
137                 set_eof();
138
139         return ret;
140 }
141
142 void File::sync()
143 {
144 #ifndef WIN32
145         signal_flush_required.emit();
146
147         fsync(*handle);
148 #endif
149 }
150
151 SeekOffset File::seek(SeekOffset off, SeekType type)
152 {
153         signal_flush_required.emit();
154         off = sys_seek(handle, off, type);
155         eof_flag = false;
156
157         return off;
158 }
159
160 SeekOffset File::tell() const
161 {
162         return sys_seek(const_cast<Handle &>(handle), 0, S_CUR);
163 }
164
165 const Handle &File::get_handle(Mode m)
166 {
167         check_access(m);
168         return handle;
169 }
170
171 } // namespace IO
172 } // namespace Msp