• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************************************
2  * IOWOW library
3  *
4  * MIT License
5  *
6  * Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in all
16  * copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  *************************************************************************************************/
26 
27 #include "iwcfg.h"
28 #include "log/iwlog.h"
29 #include "platform/iwp.h"
30 #include "iwfile.h"
31 #include "iwutils.h"
32 
33 #include <fcntl.h>
34 #include <limits.h>
35 #include <unistd.h>
36 #ifdef _WIN32
37 #include <libiberty/libiberty.h>
38 #define strndup xstrndup
39 #endif
40 
41 typedef struct IWFS_FILE_IMPL {
42   HANDLE fh;               /**< File handle. */
43   iwfs_openstatus ostatus; /**< File open status. */
44   IWFS_FILE_OPTS opts;     /**< File open options. */
45 } IWF;
46 
_iwfs_write(struct IWFS_FILE * f,off_t off,const void * buf,size_t siz,size_t * sp)47 static iwrc _iwfs_write(struct IWFS_FILE *f, off_t off, const void *buf, size_t siz, size_t *sp) {
48   assert(f);
49   IWF *impl = f->impl;
50   if (!impl) {
51     return IW_ERROR_INVALID_STATE;
52   }
53   if (!(impl->opts.omode & IWFS_OWRITE)) {
54     return IW_ERROR_READONLY;
55   }
56   iwrc rc = iwp_pwrite(impl->fh, off, buf, siz, sp);
57   if (!rc && impl->opts.dlsnr) {
58     rc = impl->opts.dlsnr->onwrite(impl->opts.dlsnr, off, buf, siz, 0);
59   }
60   return rc;
61 }
62 
_iwfs_read(struct IWFS_FILE * f,off_t off,void * buf,size_t siz,size_t * sp)63 static iwrc _iwfs_read(struct IWFS_FILE *f, off_t off, void *buf, size_t siz, size_t *sp) {
64   assert(f);
65   IWF *impl = f->impl;
66   if (!impl) {
67     return IW_ERROR_INVALID_STATE;
68   }
69   return iwp_pread(impl->fh, off, buf, siz, sp);
70 }
71 
_iwfs_close(struct IWFS_FILE * f)72 static iwrc _iwfs_close(struct IWFS_FILE *f) {
73   if (!f || !f->impl) {
74     return 0;
75   }
76   iwrc rc = 0;
77   IWF *impl = f->impl;
78   IWFS_FILE_OPTS *opts = &impl->opts;
79 #ifndef _WIN32
80   if (opts->path && (opts->omode & IWFS_OUNLINK)) {
81     unlink(opts->path);
82   }
83 #endif
84   if (opts->lock_mode != IWP_NOLOCK) {
85     IWRC(iwp_unlock(impl->fh), rc);
86   }
87   IWRC(iwp_closefh(impl->fh), rc);
88   if (opts->path) {
89     free((char *) opts->path);
90     opts->path = 0;
91   }
92   free(f->impl);
93   f->impl = 0;
94   return rc;
95 }
96 
_iwfs_sync(struct IWFS_FILE * f,iwfs_sync_flags flags)97 static iwrc _iwfs_sync(struct IWFS_FILE *f, iwfs_sync_flags flags) {
98   assert(f);
99   iwrc rc = 0;
100   if (!f->impl) {
101     return IW_ERROR_INVALID_STATE;
102   }
103   IWF *impl = f->impl;
104   if (flags & IWFS_FDATASYNC) {
105 #ifdef __APPLE__
106     if (fcntl(impl->fh, F_FULLFSYNC) == -1) {
107       return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
108     }
109 #else
110     if (iwp_fdatasync(impl->fh) == -1) {
111       return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
112     }
113 #endif
114   } else if (iwp_fsync(impl->fh) == -1) {
115     return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
116   }
117   if (impl->opts.dlsnr) {
118     rc = impl->opts.dlsnr->onsynced(impl->opts.dlsnr, 0);
119   }
120   return rc;
121 }
122 
_iwfs_state(struct IWFS_FILE * f,IWFS_FILE_STATE * state)123 static iwrc _iwfs_state(struct IWFS_FILE *f, IWFS_FILE_STATE *state) {
124   assert(f);
125   assert(state);
126   memset(state, 0, sizeof(*state));
127   IWF *impl = f->impl;
128   state->is_open = (impl != 0);
129   if (!state->is_open) {
130     return 0;
131   }
132   state->ostatus = impl->ostatus;
133   state->opts = impl->opts;
134   state->fh = impl->fh;
135   return 0;
136 }
137 
_iwfs_copy(struct IWFS_FILE * f,off_t off,size_t siz,off_t noff)138 static iwrc _iwfs_copy(struct IWFS_FILE *f, off_t off, size_t siz, off_t noff) {
139   assert(f);
140   IWF *impl = f->impl;
141   if (!impl) {
142     return IW_ERROR_INVALID_STATE;
143   }
144   if (!(impl->opts.omode & IWFS_OWRITE)) {
145     return IW_ERROR_READONLY;
146   }
147   iwrc rc = iwp_copy_bytes(impl->fh, off, siz, noff);
148   if (!rc && impl->opts.dlsnr) {
149     rc = impl->opts.dlsnr->oncopy(impl->opts.dlsnr, off, siz, noff, 0);
150   }
151   return rc;
152 }
153 
iwfs_file_open(IWFS_FILE * f,const IWFS_FILE_OPTS * _opts)154 iwrc iwfs_file_open(IWFS_FILE *f, const IWFS_FILE_OPTS *_opts) {
155   if (!f || !_opts || !_opts->path) {
156     return IW_ERROR_INVALID_ARGS;
157   }
158 
159   IWFS_FILE_OPTS *opts;
160   IWF *impl;
161   IWP_FILE_STAT fstat;
162   iwfs_omode omode;
163   iwrc rc;
164   int mode;
165 
166   memset(f, 0, sizeof(*f));
167   rc = iwfs_file_init();
168   RCRET(rc);
169 
170   f->write = _iwfs_write;
171   f->read = _iwfs_read;
172   f->close = _iwfs_close;
173   f->sync = _iwfs_sync;
174   f->state = _iwfs_state;
175   f->copy = _iwfs_copy;
176 
177   impl = f->impl = calloc(sizeof(IWF), 1);
178   if (!impl) {
179     return iwrc_set_errno(IW_ERROR_ALLOC, errno);
180   }
181 
182   impl->opts = *_opts;
183   opts = &impl->opts;
184 
185   if (opts->dlsnr) {
186     IWDLSNR *l = opts->dlsnr;
187     if (!l->onopen || !l->onclosing || !l->oncopy || !l->onresize ||
188         !l->onset || !l->onsynced || !l->onwrite) {
189       iwlog_ecode_error2(IW_ERROR_INVALID_ARGS, "Invalid 'opts->dlsnr' specified");
190       return IW_ERROR_INVALID_ARGS;
191     }
192   }
193 
194   if (opts->omode & IWFS_OTMP) {
195     opts->path = iwp_allocate_tmpfile_path(opts->path);
196     if (!opts->path) {
197       rc = iwrc_set_errno(IW_ERROR_ERRNO, errno);
198       goto finish;
199     }
200   } else {
201     opts->path = strndup(_opts->path, MAXPATHLEN);
202     if (!opts->path) {
203       rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
204       goto finish;
205     }
206   }
207 
208   if (!opts->lock_mode) {
209     opts->lock_mode = IWFS_DEFAULT_LOCKMODE; // -V1048
210   }
211   if (!opts->omode) {
212     opts->omode = IWFS_DEFAULT_OMODE;
213   }
214   if (!opts->filemode) {
215     opts->filemode = IWFS_DEFAULT_FILEMODE;
216   }
217   opts->omode |= IWFS_OREAD;
218   if (opts->omode & IWFS_OTMP) {
219     opts->omode |= IWFS_OTRUNC;
220     opts->lock_mode |= IWP_WLOCK;
221   }
222   if (opts->omode & IWFS_OTRUNC) {
223     opts->omode |= IWFS_OWRITE;
224     opts->omode |= IWFS_OCREATE;
225   }
226   if (opts->omode & IWFS_OUNLINK) {
227     opts->omode |= IWFS_OWRITE;
228   }
229   if ((opts->omode & IWFS_OCREATE) || (opts->omode & IWFS_OTRUNC)) {
230     opts->omode |= IWFS_OWRITE;
231   }
232   omode = opts->omode;
233 
234   if (!(opts->omode & IWFS_OWRITE) && (opts->lock_mode & IWP_WLOCK)) {
235     opts->lock_mode &= ~IWP_WLOCK;
236   }
237   rc = iwp_fstat(opts->path, &fstat);
238   if (!rc && !(opts->omode & IWFS_OTRUNC)) {
239     impl->ostatus = IWFS_OPEN_EXISTING;
240   } else {
241     impl->ostatus = IWFS_OPEN_NEW;
242   }
243   rc = 0;
244   mode = O_RDONLY;
245   if (omode & IWFS_OWRITE) {
246     mode = O_RDWR;
247     if (omode & IWFS_OCREATE) {
248       mode |= O_CREAT;
249     }
250     if (omode & IWFS_OTRUNC) {
251       mode |= O_TRUNC;
252     }
253   }
254 #ifndef _WIN32
255   impl->fh = open(opts->path, mode, opts->filemode);
256   if (INVALIDHANDLE(impl->fh)) {
257     if (errno == ENOENT) {
258       rc = IW_ERROR_NOT_EXISTS;
259     } else {
260       rc = iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
261     }
262     goto finish;
263   }
264 #else
265   DWORD womode = GENERIC_READ;
266   DWORD wcmode = OPEN_EXISTING;
267   if (omode & IWFS_OWRITE) {
268     womode |= GENERIC_WRITE;
269     if (omode & IWFS_OTRUNC) {
270       wcmode = CREATE_ALWAYS;
271     } else if (omode & IWFS_OCREATE) {
272       wcmode = OPEN_ALWAYS;
273     }
274   }
275   DWORD smode = FILE_SHARE_READ | FILE_SHARE_WRITE;
276   DWORD flags = FILE_ATTRIBUTE_NORMAL;
277   if (opts->omode & IWFS_OUNLINK) {
278     smode |= FILE_SHARE_DELETE;
279     flags |= FILE_FLAG_DELETE_ON_CLOSE;
280   }
281   impl->fh = CreateFile(opts->path, womode, smode, NULL, wcmode, flags, NULL);
282   if (INVALIDHANDLE(impl->fh)) {
283     uint32_t err = GetLastError();
284     if (err == ERROR_FILE_NOT_FOUND) {
285       rc = IW_ERROR_NOT_EXISTS;
286     } else {
287       rc = iwrc_set_werror(IW_ERROR_IO_ERRNO, err);
288     }
289     goto finish;
290   }
291 #endif
292   if (opts->lock_mode != IWP_NOLOCK) {
293     rc = iwp_flock(impl->fh, opts->lock_mode);
294     RCGO(rc, finish);
295   }
296 finish:
297   if (rc) {
298     impl->ostatus = IWFS_OPEN_FAIL;
299     if (opts->path) {
300       free((char *) opts->path);
301     }
302     f->impl = 0;
303     free(impl);
304   }
305   return rc;
306 }
307 
iwfs_file_init(void)308 iwrc iwfs_file_init(void) {
309   return iw_init();
310 }
311