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