]> git.tdb.fi Git - libs/core.git/blob - source/file.cpp
Drop copyright and license notices from files
[libs/core.git] / source / file.cpp
1 #ifndef WIN32
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #endif
6 #include <msp/strings/formatter.h>
7 #include "except.h"
8 #include "file.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace IO {
14
15 /**
16 Creates a new file object and opens it.  If the
17 create flag is true and write access is requested and the file does exist, it
18 is created.  Otherwise a missing file is an error.
19
20 @param   fn  Name of the file to open
21 @param   m   Open mode
22 @param   cm  Flags controlling creation of a new file
23 */
24 File::File(const string &fn, Mode m, CreateMode cm)
25 {
26         if(!(m&M_RDWR))
27                 throw InvalidParameterValue("Invalid read/write mode");
28         if(cm&~(C_CREATE|C_TRUNCATE))
29                 throw InvalidParameterValue("Invalid create mode");
30
31         mode = m;
32
33 #ifdef WIN32
34         int flags = 0;
35         int create_flags = OPEN_EXISTING;
36
37         if(mode&M_READ)
38                 flags |= GENERIC_READ;
39         else if(mode&M_WRITE)
40         {
41                 flags |= GENERIC_WRITE;
42
43                 switch(static_cast<int>(cm))
44                 {
45                 case C_NONE:     create_flags = OPEN_EXISTING; break;
46                 case C_CREATE:   create_flags = OPEN_ALWAYS; break;
47                 case C_TRUNCATE: create_flags = TRUNCATE_EXISTING; break;
48                 case C_CREATE+C_TRUNCATE: create_flags = CREATE_ALWAYS; break;
49                 }
50         }
51
52         handle = CreateFile(fn.c_str(), flags, 0, 0, create_flags, FILE_ATTRIBUTE_NORMAL, 0);
53         if(handle==INVALID_HANDLE_VALUE)
54         {
55                 int err = GetLastError();
56                 if(err==ERROR_FILE_NOT_FOUND)
57                         throw FileNotFound("Can't find file "+fn, fn);
58                 else
59                         throw SystemError(format("Can't open file '%s'", fn), GetLastError());
60         }
61 #else
62         int flags = 0;
63         switch(mode&M_RDWR)
64         {
65         case M_READ:  flags |= O_RDONLY; break;
66         case M_WRITE: flags |= O_WRONLY; break;
67         case M_RDWR:  flags |= O_RDWR; break;
68         default:;
69         }
70
71         if(mode&M_WRITE)
72         {
73                 if(cm&C_CREATE)
74                         flags |= O_CREAT;
75                 if(cm&C_TRUNCATE)
76                         flags |= O_TRUNC;
77         }
78         if(mode&M_APPEND)
79                 flags |= O_APPEND;
80         if(mode&M_NONBLOCK)
81                 flags |= O_NONBLOCK;
82
83         handle = ::open(fn.c_str(), flags, 0666);
84         if(handle==-1)
85         {
86                 int err = errno;
87                 if(err==ENOENT)
88                         throw FileNotFound("Can't find file "+fn, fn);
89                 else
90                         throw SystemError(format("Can't open file '%s'", fn), err);
91         }
92 #endif
93
94         set_events(P_INPUT);
95 }
96
97 /**
98 Closes the file.  Any attempt to access the file after this will cause an
99 exception to be thrown.
100 */
101 void File::close()
102 {
103         if(handle==MSP_IO_INVALID_HANDLE)
104                 return;
105
106         set_events(P_NONE);
107
108         signal_flush_required.emit();
109
110 #ifdef WIN32
111         CloseHandle(handle);
112 #else
113         ::close(handle);
114 #endif
115
116         handle = MSP_IO_INVALID_HANDLE;
117         signal_closed.emit();
118 }
119
120 /**
121 Sets the blocking state of the file.  If blocking is disabled, all operations
122 will return immediately, even if they can't be fully completed.
123 */
124 void File::set_block(bool b)
125 {
126         check_access(M_NONE);
127
128         mode = (mode&~M_NONBLOCK);
129         if(b)
130                 mode = (mode|M_NONBLOCK);
131 #ifndef WIN32
132         int flags = fcntl(handle, F_GETFD);
133         fcntl(handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK));
134 #endif
135 }
136
137 void File::sync()
138 {
139 #ifndef WIN32
140         signal_flush_required.emit();
141
142         fsync(handle);
143 #endif
144 }
145
146 /**
147 Seeks the file to the given byte offset.
148
149 @param   off  Offset in bytes
150 @param   st   Seek type
151
152 @return  The resulting offset
153 */
154 int File::seek(int off, SeekType st)
155 {
156         check_access(M_NONE);
157
158         signal_flush_required.emit();
159
160         int type = sys_seek_type(st);
161 #ifdef WIN32
162         DWORD ret = SetFilePointer(handle, off, 0, type);
163         if(ret==INVALID_SET_FILE_POINTER)
164                 throw SystemError("Seek failed", GetLastError());
165 #else
166         int ret = lseek(handle, off, type);
167         if(ret==-1)
168                 throw SystemError("Seek failed", errno);
169 #endif
170
171         eof_flag = false;
172
173         return ret;
174 }
175
176 /**
177 Returns the current read/write offset of the file.
178 */
179 int File::tell() const
180 {
181         check_access(M_NONE);
182
183 #ifdef WIN32
184         DWORD ret = SetFilePointer(handle, 0, 0, FILE_CURRENT);
185         if(ret==INVALID_SET_FILE_POINTER)
186                 throw SystemError("Tell failed", GetLastError());
187 #else
188         int ret = lseek(handle, 0, SEEK_CUR);
189         if(ret==-1)
190                 throw SystemError("Tell failed", errno);
191 #endif
192
193         return ret;
194 }
195
196 File::~File()
197 {
198         close();
199 }
200
201 void File::check_access(Mode m) const
202 {
203         if(handle==MSP_IO_INVALID_HANDLE)
204                 throw InvalidState("File is not open");
205         if(m==M_READ && !(mode&M_READ))
206                 throw InvalidState("File is not readable");
207         if(m==M_WRITE && !(mode&M_WRITE))
208                 throw InvalidState("File is not writable");
209 }
210
211 /**
212 Writes data from a buffer to the file.
213
214 @param   buf   Buffer to write from.
215 @param   size  Length of data to write.
216
217 @return  The number of bytes written
218 */
219 unsigned File::do_write(const char *buf, unsigned size)
220 {
221         check_access(M_WRITE);
222
223         if(size==0)
224                 return 0;
225
226 #ifdef WIN32
227         if(mode&M_APPEND)
228                 seek(0, S_END);
229         DWORD ret;
230         if(WriteFile(handle, buf, size, &ret, 0)==0)
231                 throw SystemError("Writing to file failed", GetLastError());
232 #else
233         int ret = ::write(handle, buf, size);
234         if(ret==-1)
235         {
236                 if(errno==EAGAIN)
237                         return 0;
238                 else
239                         throw SystemError("Writing to file failed", errno);
240         }
241 #endif
242
243         return ret;
244 }
245
246 /**
247 Reads data from the file.
248
249 @param   buf   Buffer to read data into.
250 @param   size  Maximum size of data to read.
251
252 @return  The number of bytes read, possibly zero
253 */
254 unsigned File::do_read(char *buf, unsigned size)
255 {
256         check_access(M_READ);
257
258         if(size==0)
259                 return 0;
260
261 #ifdef WIN32
262         DWORD ret;
263         if(ReadFile(handle, buf, size, &ret, 0)==0)
264                 throw SystemError("Reading from file failed", GetLastError());
265 #else
266         int ret = ::read(handle, buf, size);
267         if(ret==-1)
268         {
269                 if(errno==EAGAIN)
270                         return 0;
271                 else
272                         throw SystemError("Reading from file failed", errno);
273         }
274 #endif
275
276         if(ret==0)
277         {
278                 eof_flag = true;
279                 signal_end_of_file.emit();
280         }
281
282         return ret;
283 }
284
285 } // namespace IO
286 } // namespace Msp