1 /***************************************************************************
2 begin : Tue Apr 27 2010
3 copyright : (C) 2010 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * *
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 * *
23 ***************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28
29
30
31 #include "syncio_file_p.h"
32
33 #include <gwenhywfar/misc.h>
34 #include <gwenhywfar/debug.h>
35
36 #include <assert.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <string.h>
43 #include <stdio.h>
44
45
46
47
GWEN_INHERIT(GWEN_SYNCIO,GWEN_SYNCIO_FILE)48 GWEN_INHERIT(GWEN_SYNCIO, GWEN_SYNCIO_FILE)
49
50
51
52 GWEN_SYNCIO *GWEN_SyncIo_File_new(const char *path, GWEN_SYNCIO_FILE_CREATIONMODE cm)
53 {
54 GWEN_SYNCIO *sio;
55 GWEN_SYNCIO_FILE *xio;
56
57 assert(path);
58 sio=GWEN_SyncIo_new(GWEN_SYNCIO_FILE_TYPE, NULL);
59 GWEN_NEW_OBJECT(GWEN_SYNCIO_FILE, xio);
60 GWEN_INHERIT_SETDATA(GWEN_SYNCIO, GWEN_SYNCIO_FILE, sio, xio, GWEN_SyncIo_File_FreeData);
61
62 xio->creationMode=cm;
63 xio->path=strdup(path);
64
65 GWEN_SyncIo_SetConnectFn(sio, GWEN_SyncIo_File_Connect);
66 GWEN_SyncIo_SetDisconnectFn(sio, GWEN_SyncIo_File_Disconnect);
67 GWEN_SyncIo_SetReadFn(sio, GWEN_SyncIo_File_Read);
68 GWEN_SyncIo_SetWriteFn(sio, GWEN_SyncIo_File_Write);
69
70 return sio;
71 }
72
73
74
GWEN_SyncIo_File_fromFd(int fd)75 GWEN_SYNCIO *GWEN_SyncIo_File_fromFd(int fd)
76 {
77 GWEN_SYNCIO *sio;
78 GWEN_SYNCIO_FILE *xio;
79
80 sio=GWEN_SyncIo_new(GWEN_SYNCIO_FILE_TYPE, NULL);
81 GWEN_NEW_OBJECT(GWEN_SYNCIO_FILE, xio);
82 GWEN_INHERIT_SETDATA(GWEN_SYNCIO, GWEN_SYNCIO_FILE, sio, xio, GWEN_SyncIo_File_FreeData);
83
84 xio->fd=fd;
85 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Connected);
86
87 GWEN_SyncIo_SetConnectFn(sio, GWEN_SyncIo_File_Connect);
88 GWEN_SyncIo_SetDisconnectFn(sio, GWEN_SyncIo_File_Disconnect);
89 GWEN_SyncIo_SetReadFn(sio, GWEN_SyncIo_File_Read);
90 GWEN_SyncIo_SetWriteFn(sio, GWEN_SyncIo_File_Write);
91
92 return sio;
93 }
94
95
96
GWEN_SyncIo_File_fromStdHandle(int fd,const char * hname)97 GWEN_SYNCIO *GWEN_SyncIo_File_fromStdHandle(int fd, const char *hname)
98 {
99 GWEN_SYNCIO *sio;
100 GWEN_SYNCIO_FILE *xio;
101
102 sio=GWEN_SyncIo_new(GWEN_SYNCIO_FILE_TYPE, NULL);
103 GWEN_NEW_OBJECT(GWEN_SYNCIO_FILE, xio);
104 GWEN_INHERIT_SETDATA(GWEN_SYNCIO, GWEN_SYNCIO_FILE, sio, xio, GWEN_SyncIo_File_FreeData);
105
106 xio->path=strdup(hname);
107 xio->fd=fd;
108 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Connected);
109
110 GWEN_SyncIo_SetConnectFn(sio, GWEN_SyncIo_File_Connect);
111 GWEN_SyncIo_SetDisconnectFn(sio, GWEN_SyncIo_File_Disconnect);
112 GWEN_SyncIo_SetReadFn(sio, GWEN_SyncIo_File_Read);
113 GWEN_SyncIo_SetWriteFn(sio, GWEN_SyncIo_File_Write);
114
115 return sio;
116 }
117
118
119
GWEN_SyncIo_File_fromStdin(void)120 GWEN_SYNCIO *GWEN_SyncIo_File_fromStdin(void)
121 {
122 return GWEN_SyncIo_File_fromStdHandle(fileno(stdin), "stdin");
123 }
124
125
126
GWEN_SyncIo_File_fromStdout(void)127 GWEN_SYNCIO *GWEN_SyncIo_File_fromStdout(void)
128 {
129 return GWEN_SyncIo_File_fromStdHandle(fileno(stdout), "stdout");
130 }
131
132
133
GWEN_SyncIo_File_fromStderr(void)134 GWEN_SYNCIO *GWEN_SyncIo_File_fromStderr(void)
135 {
136 return GWEN_SyncIo_File_fromStdHandle(fileno(stderr), "stderr");
137 }
138
139
140
141
142
143
144
GWEN_SyncIo_File_GetPath(const GWEN_SYNCIO * sio)145 const char *GWEN_SyncIo_File_GetPath(const GWEN_SYNCIO *sio)
146 {
147 GWEN_SYNCIO_FILE *xio;
148
149 assert(sio);
150 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_FILE, sio);
151 assert(xio);
152
153 return xio->path;
154 }
155
156
157
GWEN_SyncIo_File_FreeData(GWEN_UNUSED void * bp,void * p)158 void GWENHYWFAR_CB GWEN_SyncIo_File_FreeData(GWEN_UNUSED void *bp, void *p)
159 {
160 GWEN_SYNCIO_FILE *xio;
161
162 xio=(GWEN_SYNCIO_FILE *) p;
163 free(xio->path);
164 GWEN_FREE_OBJECT(xio);
165 }
166
167
168
GWEN_SyncIo_File_Connect(GWEN_SYNCIO * sio)169 int GWENHYWFAR_CB GWEN_SyncIo_File_Connect(GWEN_SYNCIO *sio)
170 {
171 GWEN_SYNCIO_FILE *xio;
172 int fd;
173 uint32_t flags;
174 uint32_t accflags;
175 mode_t mode=0;
176 int acc=0;
177
178 assert(sio);
179 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_FILE, sio);
180 assert(xio);
181
182 flags=GWEN_SyncIo_GetFlags(sio);
183 accflags=flags & (GWEN_SYNCIO_FILE_FLAGS_READ | GWEN_SYNCIO_FILE_FLAGS_WRITE);
184 if (accflags==(GWEN_SYNCIO_FILE_FLAGS_READ | GWEN_SYNCIO_FILE_FLAGS_WRITE))
185 acc=O_RDWR;
186 else if (accflags==GWEN_SYNCIO_FILE_FLAGS_READ)
187 acc=O_RDONLY;
188 else if (accflags==GWEN_SYNCIO_FILE_FLAGS_WRITE)
189 acc=O_WRONLY;
190
191 if (flags & GWEN_SYNCIO_FILE_FLAGS_APPEND)
192 acc|=O_APPEND;
193
194 #ifdef O_BINARY
195 /* always assume binary mode */
196 acc|=O_BINARY;
197 #endif
198
199 if (flags & GWEN_SYNCIO_FILE_FLAGS_UREAD)
200 mode|=S_IRUSR;
201 if (flags & GWEN_SYNCIO_FILE_FLAGS_UWRITE)
202 mode|=S_IWUSR;
203 if (flags & GWEN_SYNCIO_FILE_FLAGS_UEXEC)
204 mode|=S_IXUSR;
205
206 #ifdef S_IRGRP
207 if (flags & GWEN_SYNCIO_FILE_FLAGS_GREAD)
208 mode|=S_IRGRP;
209 #endif
210 #ifdef S_IWGRP
211 if (flags & GWEN_SYNCIO_FILE_FLAGS_GWRITE)
212 mode|=S_IWGRP;
213 #endif
214 #ifdef S_IXGRP
215 if (flags & GWEN_SYNCIO_FILE_FLAGS_GEXEC)
216 mode|=S_IXGRP;
217 #endif
218
219 #ifdef S_IROTH
220 if (flags & GWEN_SYNCIO_FILE_FLAGS_OREAD)
221 mode|=S_IROTH;
222 #endif
223 #ifdef S_IWOTH
224 if (flags & GWEN_SYNCIO_FILE_FLAGS_OWRITE)
225 mode|=S_IWOTH;
226 #endif
227 #ifdef S_IXOTH
228 if (flags & GWEN_SYNCIO_FILE_FLAGS_OEXEC)
229 mode|=S_IXOTH;
230 #endif
231
232 switch (xio->creationMode) {
233 case GWEN_SyncIo_File_CreationMode_OpenExisting:
234 fd=open(xio->path, acc);
235 break;
236 case GWEN_SyncIo_File_CreationMode_CreateNew:
237 fd=open(xio->path, acc | O_CREAT | O_EXCL, mode);
238 break;
239 case GWEN_SyncIo_File_CreationMode_OpenAlways:
240 fd=open(xio->path, acc | O_CREAT, mode);
241 break;
242 case GWEN_SyncIo_File_CreationMode_CreateAlways:
243 fd=open(xio->path, acc | O_CREAT | O_TRUNC, mode);
244 break;
245 case GWEN_SyncIo_File_CreationMode_TruncateExisting:
246 fd=open(xio->path, acc | O_TRUNC, mode);
247 break;
248 default:
249 DBG_ERROR(GWEN_LOGDOMAIN, "Invalid creation mode %d", xio->creationMode);
250 fd=-1;
251 break;
252 }
253
254 if (fd==-1) {
255 DBG_ERROR(GWEN_LOGDOMAIN, "open(%s, %d): %s", xio->path, xio->creationMode, strerror(errno));
256 switch (errno) {
257 case EEXIST:
258 return GWEN_ERROR_FOUND;
259 case EACCES:
260 return GWEN_ERROR_PERMISSIONS;
261 case ENOENT:
262 return GWEN_ERROR_NOT_FOUND;
263 default:
264 return GWEN_ERROR_IO;
265 }
266 }
267
268 xio->fd=fd;
269 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Connected);
270
271 return 0;
272 }
273
274
275
GWEN_SyncIo_File_Disconnect(GWEN_SYNCIO * sio)276 int GWENHYWFAR_CB GWEN_SyncIo_File_Disconnect(GWEN_SYNCIO *sio)
277 {
278 GWEN_SYNCIO_FILE *xio;
279 int rv=0;
280
281 assert(sio);
282 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_FILE, sio);
283 assert(xio);
284
285 if (xio->fd==-1) {
286 DBG_ERROR(GWEN_LOGDOMAIN, "File (%s) not open", xio->path);
287 return GWEN_ERROR_NOT_OPEN;
288 }
289
290 if (!(GWEN_SyncIo_GetFlags(sio) & GWEN_SYNCIO_FLAGS_DONTCLOSE)) {
291 do {
292 rv=close(xio->fd);
293 }
294 while (rv==-1 && errno==EINTR);
295
296 if (rv==-1) {
297 DBG_ERROR(GWEN_LOGDOMAIN, "close(%s): %s", xio->path, strerror(errno));
298 switch (errno) {
299 case ENOSPC:
300 return GWEN_ERROR_MEMORY_FULL;
301 default:
302 return GWEN_ERROR_IO;
303 }
304 }
305 }
306
307 xio->fd=-1;
308 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Disconnected);
309
310 return (int)rv;
311 }
312
313
314
GWEN_SyncIo_File_Read(GWEN_SYNCIO * sio,uint8_t * buffer,uint32_t size)315 int GWENHYWFAR_CB GWEN_SyncIo_File_Read(GWEN_SYNCIO *sio,
316 uint8_t *buffer,
317 uint32_t size)
318 {
319 GWEN_SYNCIO_FILE *xio;
320 ssize_t rv;
321
322 assert(sio);
323 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_FILE, sio);
324 assert(xio);
325
326 if (xio->fd==-1) {
327 DBG_ERROR(GWEN_LOGDOMAIN, "File (%s) not open", xio->path);
328 return GWEN_ERROR_NOT_OPEN;
329 }
330
331 if (GWEN_SyncIo_GetStatus(sio) != GWEN_SyncIo_Status_Connected) {
332 DBG_ERROR(GWEN_LOGDOMAIN, "GWEN_SYNCIO of file (%s) not connected; did you forget to call GWEN_SyncIo_Connect()?",
333 xio->path);
334 return GWEN_ERROR_NOT_OPEN;
335 }
336
337 do {
338 rv=read(xio->fd, buffer, size);
339 }
340 while (rv==-1 && errno==EINTR);
341
342 if (rv==-1) {
343 DBG_ERROR(GWEN_LOGDOMAIN, "read(%s, %lu): %s", xio->path, (long unsigned int) size, strerror(errno));
344 return GWEN_ERROR_IO;
345 }
346
347 return (int)rv;
348 }
349
350
351
GWEN_SyncIo_File_Write(GWEN_SYNCIO * sio,const uint8_t * buffer,uint32_t size)352 int GWENHYWFAR_CB GWEN_SyncIo_File_Write(GWEN_SYNCIO *sio,
353 const uint8_t *buffer,
354 uint32_t size)
355 {
356 GWEN_SYNCIO_FILE *xio;
357 ssize_t rv;
358
359 assert(sio);
360 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_FILE, sio);
361 assert(xio);
362
363 if (xio->fd==-1) {
364 DBG_ERROR(GWEN_LOGDOMAIN, "File (%s) not open", xio->path);
365 return GWEN_ERROR_NOT_OPEN;
366 }
367
368 do {
369 rv=write(xio->fd, buffer, size);
370 }
371 while (rv==-1 && errno==EINTR);
372
373 if (rv==-1) {
374 DBG_ERROR(GWEN_LOGDOMAIN, "write(%d, %s, %lu): %s", xio->fd, xio->path, (long unsigned int) size, strerror(errno));
375 switch (errno) {
376 case ENOSPC:
377 return GWEN_ERROR_MEMORY_FULL;
378 default:
379 return GWEN_ERROR_IO;
380 }
381 }
382
383 return (int)rv;
384 }
385
386
387
GWEN_SyncIo_File_Seek(GWEN_SYNCIO * sio,int64_t pos,GWEN_SYNCIO_FILE_WHENCE whence)388 int64_t GWEN_SyncIo_File_Seek(GWEN_SYNCIO *sio, int64_t pos, GWEN_SYNCIO_FILE_WHENCE whence)
389 {
390 GWEN_SYNCIO_FILE *xio;
391 off_t rv;
392 int w;
393
394 assert(sio);
395 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_FILE, sio);
396 assert(xio);
397
398 switch (whence) {
399 case GWEN_SyncIo_File_Whence_Set:
400 w=SEEK_SET;
401 break;
402 case GWEN_SyncIo_File_Whence_Current:
403 w=SEEK_CUR;
404 break;
405 case GWEN_SyncIo_File_Whence_End:
406 w=SEEK_END;
407 break;
408 default:
409 DBG_ERROR(GWEN_LOGDOMAIN, "Invalid seek mode (%d)", whence);
410 return GWEN_ERROR_INVALID;
411 }
412
413 rv=lseek(xio->fd, pos, w);
414 if (rv==-1) {
415 DBG_ERROR(GWEN_LOGDOMAIN, "lseek(%s, %" PRIi64 "): %s",
416 xio->path, (int64_t) pos, strerror(errno));
417 return GWEN_ERROR_IO;
418 }
419 return rv;
420 }
421
422
423
424
425
426
427