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