]> git.tdb.fi Git - libs/core.git/blob - source/io/file.cpp
25e3b4af115855a6b332e99ebcf947599590cbc8
[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))
21                 throw invalid_argument("File::File create");
22
23         mode = m;
24
25 #ifdef WIN32
26         int flags = 0;
27         int create_flags = OPEN_EXISTING;
28
29         if(mode&M_READ)
30                 flags |= GENERIC_READ;
31         else if(mode&M_WRITE)
32         {
33                 flags |= GENERIC_WRITE;
34
35                 switch(static_cast<int>(cm))
36                 {
37                 case C_NONE:     create_flags = OPEN_EXISTING; break;
38                 case C_CREATE:   create_flags = OPEN_ALWAYS; break;
39                 case C_TRUNCATE: create_flags = TRUNCATE_EXISTING; break;
40                 case C_CREATE+C_TRUNCATE: create_flags = CREATE_ALWAYS; break;
41                 }
42         }
43
44         *handle = CreateFile(fn.c_str(), flags, 0, 0, create_flags, FILE_ATTRIBUTE_NORMAL, 0);
45         if(!handle)
46         {
47                 int err = GetLastError();
48                 if(err==ERROR_FILE_NOT_FOUND)
49                         throw file_not_found(fn);
50                 else
51                         throw system_error(format("CreateFile(%s)", fn), err);
52         }
53 #else
54         int flags = 0;
55         switch(mode&M_RDWR)
56         {
57         case M_READ:  flags |= O_RDONLY; break;
58         case M_WRITE: flags |= O_WRONLY; break;
59         case M_RDWR:  flags |= O_RDWR; break;
60         default:;
61         }
62
63         if(mode&M_WRITE)
64         {
65                 if(cm&C_CREATE)
66                         flags |= O_CREAT;
67                 if(cm&C_TRUNCATE)
68                         flags |= O_TRUNC;
69         }
70         if(mode&M_APPEND)
71                 flags |= O_APPEND;
72         if(mode&M_NONBLOCK)
73                 flags |= O_NONBLOCK;
74
75         *handle = ::open(fn.c_str(), flags, 0666);
76         if(!handle)
77         {
78                 int err = errno;
79                 if(err==ENOENT)
80                         throw file_not_found(fn);
81                 else
82                         throw system_error(format("open(%s)", fn), err);
83         }
84 #endif
85
86         set_events(P_INPUT);
87 }
88
89 File::~File()
90 {
91         close();
92 }
93
94 void File::close()
95 {
96         if(!handle)
97                 return;
98
99         set_events(P_NONE);
100
101         signal_flush_required.emit();
102
103 #ifdef WIN32
104         CloseHandle(*handle);
105 #else
106         ::close(*handle);
107 #endif
108
109         handle = Handle();
110         signal_closed.emit();
111 }
112
113 void File::set_block(bool b)
114 {
115         check_access(M_NONE);
116
117         mode = (mode&~M_NONBLOCK);
118         if(b)
119                 mode = (mode|M_NONBLOCK);
120 #ifndef WIN32
121         int flags = fcntl(*handle, F_GETFD);
122         fcntl(*handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK));
123 #endif
124 }
125
126 unsigned File::do_write(const char *buf, unsigned size)
127 {
128         check_access(M_WRITE);
129
130         if(size==0)
131                 return 0;
132
133 #ifdef WIN32
134         if(mode&M_APPEND)
135                 seek(0, S_END);
136         DWORD ret;
137         if(WriteFile(*handle, buf, size, &ret, 0)==0)
138                 throw system_error("WriteFile");
139 #else
140         int ret = ::write(*handle, buf, size);
141         if(ret==-1)
142         {
143                 if(errno==EAGAIN)
144                         return 0;
145                 else
146                         throw system_error("write");
147         }
148 #endif
149
150         return ret;
151 }
152
153 unsigned File::do_read(char *buf, unsigned size)
154 {
155         check_access(M_READ);
156
157         if(size==0)
158                 return 0;
159
160 #ifdef WIN32
161         DWORD ret;
162         if(ReadFile(*handle, buf, size, &ret, 0)==0)
163                 throw system_error("ReadFile");
164 #else
165         int ret = ::read(*handle, buf, size);
166         if(ret==-1)
167         {
168                 if(errno==EAGAIN)
169                         return 0;
170                 else
171                         throw system_error("read");
172         }
173 #endif
174
175         if(ret==0)
176         {
177                 eof_flag = true;
178                 signal_end_of_file.emit();
179         }
180
181         return ret;
182 }
183
184 void File::sync()
185 {
186 #ifndef WIN32
187         signal_flush_required.emit();
188
189         fsync(*handle);
190 #endif
191 }
192
193 unsigned File::seek(int off, SeekType st)
194 {
195         check_access(M_NONE);
196
197         signal_flush_required.emit();
198
199         int type = sys_seek_type(st);
200 #ifdef WIN32
201         DWORD ret = SetFilePointer(*handle, off, 0, type);
202         if(ret==INVALID_SET_FILE_POINTER)
203                 throw system_error("SetFilePointer");
204 #else
205         off_t ret = lseek(*handle, off, type);
206         if(ret==(off_t)-1)
207                 throw system_error("lseek");
208 #endif
209
210         eof_flag = false;
211
212         return ret;
213 }
214
215 unsigned File::tell() const
216 {
217         check_access(M_NONE);
218
219 #ifdef WIN32
220         DWORD ret = SetFilePointer(*handle, 0, 0, FILE_CURRENT);
221         if(ret==INVALID_SET_FILE_POINTER)
222                 throw system_error("SetFilePointer");
223 #else
224         off_t ret = lseek(*handle, 0, SEEK_CUR);
225         if(ret==(off_t)-1)
226                 throw system_error("lseek");
227 #endif
228
229         return ret;
230 }
231
232 void File::check_access(Mode m) const
233 {
234         if(!handle || (m && !(mode&m)))
235                 throw invalid_access(m);
236 }
237
238 } // namespace IO
239 } // namespace Msp