source: subversion/applications/utils/mod_tile/store.c @ 29338

Last change on this file since 29338 was 29086, checked in by apmon, 7 years ago

[mod_tile] fix memory leaks

Fixes coverity scan issue #746958 and #746957

File size: 10.6 KB
Line 
1/* Meta-tile optimised file storage
2 *
3 * Instead of storing each individual tile as a file,
4 * bundle the 8x8 meta tile into a special meta-file.
5 * This reduces the Inode usage and more efficient
6 * utilisation of disk space.
7 */
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include <limits.h>
13#include <string.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <utime.h>
17#include <fcntl.h>
18#include <assert.h>
19#include <errno.h>
20
21#include "store.h"
22#include "render_config.h"
23#include "dir_utils.h"
24#include "protocol.h"
25
26#ifdef METATILE
27int read_from_meta(const char *tilepath, const char *xmlconfig, int x, int y, int z, unsigned char *buf, size_t sz, int * compressed, unsigned char * log_msg)
28{
29    char path[PATH_MAX];
30    int meta_offset, fd;
31    unsigned int pos;
32    char header[4096];
33    struct meta_layout *m = (struct meta_layout *)header;
34    size_t file_offset, tile_size;
35
36    meta_offset = xyz_to_meta(path, sizeof(path), tilepath, xmlconfig, x, y, z);
37
38    fd = open(path, O_RDONLY);
39    if (fd < 0) {
40        snprintf(log_msg,1024, "Could not open metatile %s. Reason: %s\n", path, strerror(errno));
41        return -1;
42    }
43
44    pos = 0;
45    while (pos < sizeof(header)) {
46        size_t len = sizeof(header) - pos;
47        int got = read(fd, header + pos, len);
48        if (got < 0) {
49            snprintf(log_msg,1024, "Failed to read complete header for metatile %s Reason: %s\n", path, strerror(errno));
50            close(fd);           
51            return -2;
52        } else if (got > 0) {
53            pos += got;
54        } else {
55            break;
56        }
57    }
58    if (pos < sizeof(struct meta_layout)) {
59        snprintf(log_msg,1024, "Meta file %s too small to contain header\n", path);
60        close(fd);
61        return -3;
62    }
63    if (memcmp(m->magic, META_MAGIC, strlen(META_MAGIC))) {
64        if (memcmp(m->magic, META_MAGIC_COMPRESSED, strlen(META_MAGIC_COMPRESSED))) {
65            snprintf(log_msg,1024, "Meta file %s header magic mismatch\n", path);
66            close(fd);
67            return -4;
68        } else {
69            *compressed = 1;
70        }
71    } else *compressed = 0;
72#if 1
73    // Currently this code only works with fixed metatile sizes (due to xyz_to_meta above)
74    if (m->count != (METATILE * METATILE)) {
75        snprintf(log_msg, 1024, "Meta file %s header bad count %d != %d\n", path, m->count, METATILE * METATILE);
76        close(fd);
77        return -5;
78    }
79#else
80    if (m->count < 0 || m->count > 256) {
81        fprintf(stderr, "Meta file %s header bad count %d\n", path, m->count);
82        close(fd);
83        return -5;
84    }
85#endif
86    file_offset = m->index[meta_offset].offset;
87    tile_size   = m->index[meta_offset].size;
88
89    if (lseek(fd, file_offset, SEEK_SET) < 0) {
90        snprintf(log_msg, 1024, "Meta file %s seek error %d\n", path, m->count);
91        close(fd);
92        return -6;
93    }
94    if (tile_size > sz) {
95        snprintf(log_msg, 1024, "Truncating tile %zd to fit buffer of %zd\n", tile_size, sz);
96        tile_size = sz;
97    }
98    pos = 0;
99    while (pos < tile_size) {
100        size_t len = tile_size - pos;
101        int got = read(fd, buf + pos, len);
102        if (got < 0) {
103            snprintf(log_msg, 1024, "Failed to read data from file %s. Reason: %s\n", path, strerror(errno));
104            close(fd);
105            return -7;
106        } else if (got > 0) {
107            pos += got;
108        } else {
109            break;
110        }
111    }
112    close(fd);
113    return pos;
114}
115#endif
116
117int read_from_file(const char *tilepath, const char *xmlconfig, int x, int y, int z, unsigned char *buf, size_t sz)
118{
119    char path[PATH_MAX];
120    int fd;
121    size_t pos;
122
123    xyz_to_path(path, sizeof(path), tilepath, xmlconfig, x, y, z);
124
125    fd = open(path, O_RDONLY);
126    if (fd < 0)
127        return -1;
128
129    pos = 0;
130    while (pos < sz) {
131        size_t len = sz - pos;
132        int got = read(fd, buf + pos, len);
133        if (got < 0) {
134            close(fd);
135            return -2;
136        } else if (got > 0) {
137            pos += got;
138        } else {
139            break;
140        }
141    }
142    if (pos == sz) {
143        fprintf(stderr, "file %s truncated at %zd bytes\n", path, sz);
144    }
145    close(fd);
146    return pos;
147}
148
149int tile_read(const char *tilepath, const char *xmlconfig, int x, int y, int z, unsigned char *buf, int sz, int * compressed, unsigned char *err_msg)
150{
151#ifdef METATILE
152    int r;
153
154    r = read_from_meta(tilepath, xmlconfig, x, y, z, buf, sz, compressed, err_msg);
155    if (r >= 0)
156        return r;
157#endif
158    return read_from_file(tilepath, xmlconfig, x, y, z, buf, sz);
159}
160
161#ifdef METATILE
162void process_meta(const char *tilepath, const char *xmlconfig, int x, int y, int z)
163{
164    int fd;
165    int ox, oy, limit;
166    size_t offset, pos;
167    const int buf_len = 10 * MAX_SIZE; // To store all tiles in this .meta
168    unsigned char *buf;
169    struct meta_layout *m;
170    char meta_path[PATH_MAX];
171    char tmp[PATH_MAX];
172    struct stat s;
173
174    buf = (unsigned char *)malloc(buf_len);
175    if (!buf)
176        return;
177
178    m = (struct meta_layout *)buf;
179    offset = sizeof(struct meta_layout) + (sizeof(struct entry) * (METATILE * METATILE));
180    memset(buf, 0, offset);
181
182    limit = (1 << z);
183    limit = MIN(limit, METATILE);
184
185    for (ox=0; ox < limit; ox++) {
186        for (oy=0; oy < limit; oy++) {
187            //fprintf(stderr, "Process %d/%d/%d\n", num, ox, oy);
188            int len = read_from_file(tilepath, xmlconfig, x + ox, y + oy, z, buf + offset, buf_len - offset);
189            int mt = xyz_to_meta(meta_path, sizeof(meta_path), tilepath, xmlconfig, x + ox, y + oy, z);
190            if (len <= 0) {
191#if 1
192                fprintf(stderr, "Problem reading sub tiles for metatile xml(%s) x(%d) y(%d) z(%d), got %d\n", xmlconfig, x, y, z, len);
193                free(buf);
194                return;
195#else
196                 m->index[mt].offset = 0;
197                 m->index[mt].size = 0;
198#endif
199            } else {
200                 m->index[mt].offset = offset;
201                 m->index[mt].size = len;
202                 offset += len;
203            }
204        }
205    }
206    m->count = METATILE * METATILE;
207    memcpy(m->magic, META_MAGIC, strlen(META_MAGIC));
208    m->x = x;
209    m->y = y;
210    m->z = z;
211
212    xyz_to_meta(meta_path, sizeof(meta_path), tilepath, xmlconfig, x, y, z);
213    if (mkdirp(meta_path)) {
214        fprintf(stderr, "Error creating directories for: %s\n", meta_path);
215        free(buf);
216        return;
217    }
218    snprintf(tmp, sizeof(tmp), "%s.tmp.%d", meta_path, getpid());
219
220    fd = open(tmp, O_WRONLY | O_TRUNC | O_CREAT, 0666);
221    if (fd < 0) {
222        fprintf(stderr, "Error creating file: %s\n", meta_path);
223        free(buf);
224        return;
225    }
226
227    pos = 0;
228    while (pos < offset) {
229        int len = write(fd, buf + pos, offset - pos);
230        if (len < 0) {
231            perror("Writing file");
232            free(buf);
233            close(fd);
234            return;
235        } else if (len > 0) {
236            pos += len;
237        } else {
238            break;
239        }
240    }
241    close(fd);
242    free(buf);
243
244    // Reset meta timestamp to match one of the original tiles
245    xyz_to_path(meta_path, sizeof(meta_path), tilepath, xmlconfig, x, y, z);
246    if (stat(meta_path, &s) == 0) {
247        struct utimbuf b;
248        b.actime = s.st_atime;
249        b.modtime = s.st_mtime;
250        xyz_to_meta(meta_path, sizeof(meta_path), tilepath, xmlconfig, x, y, z);
251        utime(tmp, &b);
252    }
253    rename(tmp, meta_path);
254    printf("Produced .meta: %s\n", meta_path);
255
256    // Remove raw .png's
257    for (ox=0; ox < limit; ox++) {
258        for (oy=0; oy < limit; oy++) {
259            xyz_to_path(meta_path, sizeof(meta_path), tilepath, xmlconfig, x + ox, y + oy, z);
260            if (unlink(meta_path)<0)
261                perror(meta_path);
262        }
263    }
264}
265
266void process_pack(const char *tilepath, const char *name)
267{
268    char meta_path[PATH_MAX];
269    char xmlconfig[XMLCONFIG_MAX];
270    int x, y, z;
271    int meta_offset;
272
273    if (path_to_xyz(tilepath, name, xmlconfig, &x, &y, &z))
274        return;
275 
276    // Launch the .meta creation for only 1 tile of the whole block
277    meta_offset = xyz_to_meta(meta_path, sizeof(meta_path), tilepath, xmlconfig, x, y, z);
278    //fprintf(stderr,"Requesting x(%d) y(%d) z(%d) - mo(%d)\n", x, y, z, meta_offset);
279
280    if (meta_offset == 0)
281        process_meta(tilepath, xmlconfig, x, y, z);
282}
283
284static void write_tile(const char *tilepath, const char *xmlconfig, int x, int y, int z, const unsigned char *buf, size_t sz)
285{
286    int fd;
287    char path[PATH_MAX];
288    size_t pos;
289
290    xyz_to_path(path, sizeof(path), tilepath, xmlconfig, x, y, z);
291    if (mkdirp(path)) {
292        fprintf(stderr, "Error creating directories for: %s\n", path);
293        return;
294    }
295    fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0666);
296    if (fd < 0) {
297        fprintf(stderr, "Error creating file: %s\n", path);
298        return;
299    }
300
301    pos = 0;
302    while (pos < sz) {
303        int len = write(fd, buf + pos, sz - pos);
304        if (len < 0) {
305            perror("Writing file");
306            close(fd);
307            return;
308        } else if (len > 0) {
309            pos += len;
310        } else {
311            break;
312        }
313    }
314    close(fd);
315    printf("Produced tile: %s\n", path);
316}
317
318void process_unpack(const char *tilepath, const char *name)
319{
320    char meta_path[PATH_MAX];
321    char xmlconfig[XMLCONFIG_MAX];
322    char err_msg[4096];
323    int x, y, z;
324    int ox, oy, limit;
325    const int buf_len = 1024 * 1024;
326    unsigned char *buf;
327    struct stat s;
328    int compressed;
329
330    // path_to_xyz is valid for meta tile names as well
331    if (path_to_xyz(tilepath, name, xmlconfig, &x, &y, &z))
332        return;
333
334    buf = (unsigned char *)malloc(buf_len);
335    if (!buf)
336        return;
337
338
339    limit = (1 << z);
340    limit = MIN(limit, METATILE);
341
342    for (ox=0; ox < limit; ox++) {
343        for (oy=0; oy < limit; oy++) {
344            err_msg[0] = 0;
345            int len = read_from_meta(tilepath, xmlconfig, x + ox, y + oy, z, buf, buf_len, &compressed, err_msg);
346
347            if (len <= 0)
348                fprintf(stderr, "Failed to get tile x(%d) y(%d) z(%d)\n    %s", x + ox, y + oy, z, err_msg);
349            else
350                write_tile(tilepath, xmlconfig, x + ox, y + oy, z, buf, len);
351        }
352    }
353    free(buf);
354
355    // Grab timestamp of the meta file and update tile timestamps
356    if (stat(name, &s) == 0) {
357        struct utimbuf b;
358        b.actime = s.st_atime;
359        b.modtime = s.st_mtime;
360        for (ox=0; ox < limit; ox++) {
361            for (oy=0; oy < limit; oy++) {
362                xyz_to_path(meta_path, sizeof(meta_path), tilepath, xmlconfig, x+ox, y+oy, z);
363                utime(meta_path, &b);
364            }
365        }
366    }
367
368    // Remove the .meta file
369    xyz_to_meta(meta_path, sizeof(meta_path), tilepath, xmlconfig, x, y, z);
370    if (unlink(meta_path)<0)
371        perror(meta_path);
372}
373#endif
Note: See TracBrowser for help on using the repository browser.