Initial sketch of file access wrappers.
[blender.git] / source / blender / blenlib / intern / BLI_bfile.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2009 by Stichting Blender Foundation.
21  * All rights reserved.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  * BFILE* based abstraction for file access.
25  */
26
27 #include <string.h>
28
29 #include <unistd.h>
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_bfile.h"
38
39 // This would provide config paths and their oldest viable version
40 // so if there is an uncompatible change, user's old versions are not loaded
41 //#include "bfile_tables.h"
42
43 /* Internal bfile type flags */
44 #define BTF_OPEN     (0)
45 #define BTF_FOPEN    (1<<0)
46 #define BTF_READ     (1<<1)
47 #define BTF_WRITE    (1<<2)
48 #define BTF_AT_END   (1<<3)
49 #define BTF_DISCARD  (1<<4)
50
51
52 void fill_paths(BFILE *bfile, const char *path) {
53         char* source_path = NULL;
54         int bflags = bfile->uflags;
55
56         if(bflags & BFILE_NORMAL || bflags & BFILE_RAW) {
57 //              bfile->fpath is path with // replaced
58         }
59         if(bflags & BFILE_TEMP) {
60 //              bfile->fpath is tempdir+path
61         }
62         if(bflags & BFILE_CONFIG) {
63 //              bfile->fpath is userdir+version+path
64 //              source_path is first hit in (if using fallback to older versions)
65 //                  userdir+curversion+path (... userdir+limitversion+path) sysdir+path
66 //              (limitversion is based in path, using some kind of regex or "tables")
67         }
68
69         if(bfile->type & BTF_WRITE && !(bflags & BFILE_RAW)) {
70                 /* Generate temp path */
71                 // bfile->tpath is fpath+randstring
72                 if(!(bfile->type & BTF_DISCARD)) {
73                         /* Copy data to tpath */
74                         if(source_path) {
75                                 // copy it from older version or sys version
76                         }
77                 }
78         } else {
79                 bfile->tpath = bfile->fpath;
80         }
81 }
82
83 BFILE *BLI_bfile_fopen(const char *path, const char *mode, int bflags) {
84         BFILE *bfile;
85
86         bfile = MEM_mallocN(sizeof(BFILE), "bfile-fopen");
87         bfile->type = BTF_FOPEN;
88         bfile->uflags = bflags;
89
90         /* From fopen() doc, we can guess some logic:
91         r  BTF_READ
92         r+ BTF_READ | BTF_WRITE
93         w  BTF_DISCARD | BTF_WRITE
94         w+ BTF_DISCARD | BTF_WRITE | BTF_READ
95         a  BTF_AT_END | BTF_WRITE
96         a+ BTF_AT_END | BTF_WRITE | BTF_READ
97         */
98         if(strchr(mode, 'r'))
99                 bfile->type |= BTF_READ;
100         if(strchr(mode, 'w'))
101                 bfile->type |= (BTF_DISCARD | BTF_WRITE);
102         if(strchr(mode, 'a'))
103                 bfile->type |= (BTF_AT_END | BTF_WRITE);
104         if(strchr(mode, '+'))
105                 bfile->type |= (BTF_READ | BTF_WRITE);
106
107         fill_paths(bfile, path);
108
109         bfile->stream = fopen(bfile->tpath, mode);
110         // detect failed fopen
111         bfile->fd = fileno(bfile->stream);
112         return bfile;
113 }
114
115
116 BFILE *BLI_bfile_open(const char *pathname, int flags, int bflags) {
117         BFILE *bfile;
118
119         bfile = MEM_mallocN(sizeof(BFILE), "bfile-open");
120         bfile->type = BTF_OPEN;
121         bfile->uflags = bflags;
122
123         /* Easy mapping for open() */
124         if(flags & O_RDONLY)
125                 bfile->type |= BTF_READ;
126         if(flags & O_WRONLY)
127                 bfile->type |= BTF_WRITE;
128         if(flags & O_RDWR)
129                 bfile->type |= (BTF_READ | BTF_WRITE);
130         if(flags & O_APPEND)
131                 bfile->type |= BTF_AT_END;
132         if(flags & O_TRUNC)
133                 bfile->type |= BTF_DISCARD;
134
135         fill_paths(bfile, pathname);
136
137         bfile->fd = open(bfile->tpath, flags);
138         // detect failed open
139 //      bfile->stream = fdopen(bfile->fd, XXX); /* MSWindows _fdopen? */
140         return bfile;
141 }
142
143
144 FILE *BLI_bfile_file_from_bfile(BFILE *bfile) {
145         return bfile->stream;
146 }
147
148
149 int BLI_bfile_fd_from_bfile(BFILE *bfile) {
150         return bfile->fd;
151 }
152
153
154 ssize_t BLI_bfile_write(BFILE *f, const void *buf, size_t count) {
155         ssize_t ret;
156
157         ret = write((f->fd), buf, count);
158         if (ret == -1) {
159                 f->error = 1;
160         }
161
162         return ret;
163 }
164
165
166 ssize_t BLI_bfile_read(BFILE *f, void *buf, size_t count) {
167         ssize_t ret;
168
169         ret = read((f->fd), buf, count);
170         if (ret == -1) {
171                 f->error = 1;
172         }
173
174         return ret;
175 }
176
177
178 size_t BLI_bfile_fwrite(const void *ptr, size_t size, size_t nmemb, BFILE *f) {
179         size_t ret;
180
181         ret = fwrite(ptr, size, nmemb, f->stream);
182         if (ret < 0) {
183                 f->error = 1;
184         }
185
186         return ret;
187 }
188
189
190 size_t BLI_bfile_fread(void *ptr, size_t size, size_t nmemb, BFILE *f) {
191         size_t ret;
192
193         ret = fread(ptr, size, nmemb, f->stream);
194         if ((ret < 0) && ferror(f->stream)) {
195                 f->error = 1;
196         }
197
198         return ret;
199 }
200
201
202 void BLI_bfile_close(BFILE *bfile) {
203         if((bfile->type | BTF_WRITE) &&
204            !(bfile->uflags | BFILE_RAW)) {
205                 /* Make sure data is on disk */
206                 /* Move to final name if no errors */
207         }
208
209         /* Normal close */
210
211         /* Cleanup */
212         if(bfile->fpath) {
213                 MEM_freeN(bfile->fpath);
214         }
215         if(bfile->tpath) {
216                 MEM_freeN(bfile->tpath);
217         }
218 }
219
220
221 void BLI_bfile_clear_error(BFILE *bfile) {
222         bfile->error = 0;
223 }
224
225
226 void BLI_bfile_set_error(BFILE *bfile, int error) {
227         /* No cheating, use clear_error() for 0 */
228         if (error) {
229                 bfile->error = error;
230         }
231 }