1 #include "cache.h" |
1 #include "cache.h" |
2 |
2 |
3 static int pt_cache_new (struct pt_cache **cache_ptr) |
3 #include <stdlib.h> |
|
4 #include <unistd.h> |
|
5 #include <sys/types.h> |
|
6 #include <sys/stat.h> |
|
7 #include <fcntl.h> |
|
8 #include <sys/mman.h> |
|
9 |
|
10 |
|
11 |
|
12 static int pt_cache_new (struct pt_cache **cache_ptr, const char *path) |
4 { |
13 { |
5 struct pt_cache *cache; |
14 struct pt_cache *cache; |
6 |
15 |
|
16 // alloc |
7 if ((cache = calloc(1, sizeof(*cache))) == NULL) |
17 if ((cache = calloc(1, sizeof(*cache))) == NULL) |
8 return -1; |
18 return -1; |
9 |
19 |
|
20 if ((cache->path = strdup(path)) == NULL) |
|
21 goto error; |
|
22 |
|
23 // init |
|
24 cache->fd = -1; |
|
25 |
10 // ok |
26 // ok |
11 *cache_ptr = cache; |
27 *cache_ptr = cache; |
12 |
28 |
13 return 0; |
29 return 0; |
14 } |
30 |
15 |
31 error: |
16 int pt_cache_open (struct pt_cache **cache_ptr, struct pt_image *img, int mode) |
32 // cleanup |
|
33 if (cache) |
|
34 pt_cache_destroy(cache); |
|
35 |
|
36 return -1; |
|
37 } |
|
38 |
|
39 int pt_cache_open (struct pt_cache **cache_ptr, const char *path, int mode) |
17 { |
40 { |
18 struct pt_cache *cache; |
41 struct pt_cache *cache; |
19 |
42 |
20 // alloc |
43 // alloc |
21 if (pt_cache_new(&cache)) |
44 if (pt_cache_new(&cache, path)) |
22 return -1; |
45 return -1; |
23 |
|
24 |
46 |
25 } |
47 // ok |
26 |
48 *cache_ptr = cache; |
27 bool pt_cache_fresh (struct pt_cache *cache) |
49 |
|
50 return 0; |
|
51 } |
|
52 |
|
53 int pt_cache_stale (struct pt_cache *cache, const char *orig_path) |
28 { |
54 { |
29 // TODO: stat + mtime |
55 // TODO: stat + mtime |
30 return false; |
56 return false; |
31 } |
57 } |
32 |
58 |
33 /** |
59 /** |
|
60 * Abort any incomplete open operation, cleaning up |
|
61 */ |
|
62 static void pt_cache_abort (struct pt_cache *cache) |
|
63 { |
|
64 if (cache->mmap != NULL) { |
|
65 munmap(cache->mmap, cache->size); |
|
66 |
|
67 cache->mmap = NULL; |
|
68 } |
|
69 |
|
70 if (cache->fd >= 0) { |
|
71 close(cache->fd); |
|
72 |
|
73 cache->fd = -1; |
|
74 } |
|
75 } |
|
76 |
|
77 /** |
|
78 * Open the cache file as an fd. |
|
79 * |
|
80 * XXX: needs locking |
|
81 */ |
|
82 static int pt_cache_open_fd (struct pt_cache *cache, int *fd_ptr) |
|
83 { |
|
84 int fd; |
|
85 int flags = 0; |
|
86 |
|
87 // determine open flags |
|
88 // XXX: O_RDONLY | O_WRONLY == O_RDWR? |
|
89 if (cache->mode & PT_IMG_READ) |
|
90 flags |= O_RDONLY; |
|
91 |
|
92 if (cache->mode & PT_IMG_WRITE) |
|
93 flags |= (O_WRONLY | O_CREAT); |
|
94 |
|
95 // actual open() |
|
96 if ((fd = open(cache->path, flags)) < 0) |
|
97 return -1; |
|
98 |
|
99 // ok |
|
100 *fd_ptr = fd; |
|
101 |
|
102 return 0; |
|
103 } |
|
104 |
|
105 /** |
|
106 * Mmap the opened cache file from offset PT_CACHE_PAGE, using the calculated size stored in cache->size |
|
107 */ |
|
108 static int pt_cache_open_mmap (struct pt_cache *cache, void **addr_ptr) |
|
109 { |
|
110 int prot = 0; |
|
111 void *addr; |
|
112 |
|
113 // determine prot |
|
114 if (cache->mode & PT_IMG_READ) |
|
115 prot |= PROT_READ; |
|
116 |
|
117 if (cache->mode & PT_IMG_WRITE) |
|
118 prot |= PROT_WRITE; |
|
119 |
|
120 // perform mmap() from second page on |
|
121 if ((addr = mmap(NULL, cache->size, prot, MAP_SHARED, cache->fd, PT_CACHE_PAGE)) == MAP_FAILED) |
|
122 return -1; |
|
123 |
|
124 // ok |
|
125 *addr_ptr = addr; |
|
126 |
|
127 return 0; |
|
128 } |
|
129 |
|
130 /** |
|
131 * Write out the cache header into the opened file |
|
132 */ |
|
133 static int pt_cache_write_header (struct pt_cache *cache, const struct pt_cache_header *header) |
|
134 { |
|
135 size_t len = sizeof(*header); |
|
136 const char *buf = (const char *) header; |
|
137 |
|
138 // seek to start |
|
139 if (lseek(cache->fd, 0, SEEK_SET) != 0) |
|
140 return -1; |
|
141 |
|
142 // write out full header |
|
143 while (len) { |
|
144 ssize_t ret; |
|
145 |
|
146 // try and write out the header |
|
147 if ((ret = write(cache->fd, buf, len)) < 0) |
|
148 return -1; |
|
149 |
|
150 // update offset |
|
151 buf += ret; |
|
152 len -= ret; |
|
153 } |
|
154 |
|
155 // done |
|
156 return 0; |
|
157 } |
|
158 |
|
159 /** |
34 * Create a new cache file, open it, and write out the header. |
160 * Create a new cache file, open it, and write out the header. |
35 */ |
161 */ |
36 static int pt_cache_create (struct pt_cache *cache, struct pt_cache_header *header) |
162 static int pt_cache_open_create (struct pt_cache *cache, struct pt_cache_header *header) |
37 { |
163 { |
|
164 // open |
|
165 if (pt_cache_open_fd(cache, &cache->fd)) |
|
166 return -1; |
|
167 |
|
168 // calculate data size |
|
169 cache->size = sizeof(*header) + header->height * header->row_bytes; |
|
170 |
|
171 // grow file |
|
172 if (ftruncate(cache->fd, PT_CACHE_PAGE + cache->size) < 0) |
|
173 goto error; |
|
174 |
|
175 // open mmap |
|
176 if (pt_cache_open_mmap(cache, (void **) &cache->mmap)) |
|
177 goto error; |
|
178 |
|
179 // write header |
|
180 if (pt_cache_write_header(cache, header)) |
|
181 goto error; |
|
182 |
|
183 // done |
|
184 return 0; |
|
185 |
|
186 error: |
|
187 // cleanup |
|
188 pt_cache_abort(cache); |
|
189 |
|
190 return -1; |
|
191 } |
|
192 |
|
193 int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info) |
|
194 { |
|
195 struct pt_cache_header header; |
38 |
196 |
39 } |
197 // XXX: check cache_mode |
40 |
198 // XXX: check image doesn't use any options we don't handle |
41 int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info) |
|
42 { |
|
43 struct pt_cache_header header; |
|
44 |
199 |
45 memset(&header, 0, sizeof(header)); |
200 memset(&header, 0, sizeof(header)); |
46 |
201 |
47 // fill in basic info |
202 // fill in basic info |
48 header->width = png_get_image_width(png, info); |
203 header.width = png_get_image_width(png, info); |
49 header->height = png_get_image_height(png, info); |
204 header.height = png_get_image_height(png, info); |
50 header->bit_depth = png_get_bit_depth(png, info); |
205 header.bit_depth = png_get_bit_depth(png, info); |
51 header->color_type = png_get_color_type(png, info); |
206 header.color_type = png_get_color_type(png, info); |
52 |
207 |
53 // fill in other info |
208 // fill in other info |
54 header->row_bytes = png_get_rowbytes(png, info); |
209 header.row_bytes = png_get_rowbytes(png, info); |
55 } |
210 |
|
211 // create and write out header |
|
212 if (pt_cache_open_create(cache, &header)) |
|
213 return -1; |
|
214 |
|
215 // XXX: pallette etc. |
|
216 |
|
217 // write out raw image data a row at a time |
|
218 for (size_t row = 0; row < header.height; row++) { |
|
219 // read row data, non-interlaced |
|
220 png_read_row(png, cache->mmap + row * header.row_bytes, NULL); |
|
221 } |
|
222 |
|
223 // done! |
|
224 return 0; |
|
225 } |
|
226 |
|
227 void pt_cache_destroy (struct pt_cache *cache) |
|
228 { |
|
229 free(cache->path); |
|
230 |
|
231 pt_cache_abort(cache); |
|
232 |
|
233 free(cache); |
|
234 } |