diff options
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 342 |
1 files changed, 237 insertions, 105 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 7d26659b806..b01a9537977 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -2,11 +2,15 @@ | |||
2 | #include <unistd.h> | 2 | #include <unistd.h> |
3 | #include <stdio.h> | 3 | #include <stdio.h> |
4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
5 | #include <linux/list.h> | ||
5 | 6 | ||
6 | #include "util.h" | 7 | #include "util.h" |
7 | #include "header.h" | 8 | #include "header.h" |
8 | #include "../perf.h" | 9 | #include "../perf.h" |
9 | #include "trace-event.h" | 10 | #include "trace-event.h" |
11 | #include "symbol.h" | ||
12 | #include "data_map.h" | ||
13 | #include "debug.h" | ||
10 | 14 | ||
11 | /* | 15 | /* |
12 | * Create new perf.data header attribute: | 16 | * Create new perf.data header attribute: |
@@ -15,32 +19,43 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr) | |||
15 | { | 19 | { |
16 | struct perf_header_attr *self = malloc(sizeof(*self)); | 20 | struct perf_header_attr *self = malloc(sizeof(*self)); |
17 | 21 | ||
18 | if (!self) | 22 | if (self != NULL) { |
19 | die("nomem"); | 23 | self->attr = *attr; |
20 | 24 | self->ids = 0; | |
21 | self->attr = *attr; | 25 | self->size = 1; |
22 | self->ids = 0; | 26 | self->id = malloc(sizeof(u64)); |
23 | self->size = 1; | 27 | if (self->id == NULL) { |
24 | self->id = malloc(sizeof(u64)); | 28 | free(self); |
25 | 29 | self = NULL; | |
26 | if (!self->id) | 30 | } |
27 | die("nomem"); | 31 | } |
28 | 32 | ||
29 | return self; | 33 | return self; |
30 | } | 34 | } |
31 | 35 | ||
32 | void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | 36 | void perf_header_attr__delete(struct perf_header_attr *self) |
37 | { | ||
38 | free(self->id); | ||
39 | free(self); | ||
40 | } | ||
41 | |||
42 | int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | ||
33 | { | 43 | { |
34 | int pos = self->ids; | 44 | int pos = self->ids; |
35 | 45 | ||
36 | self->ids++; | 46 | self->ids++; |
37 | if (self->ids > self->size) { | 47 | if (self->ids > self->size) { |
38 | self->size *= 2; | 48 | int nsize = self->size * 2; |
39 | self->id = realloc(self->id, self->size * sizeof(u64)); | 49 | u64 *nid = realloc(self->id, nsize * sizeof(u64)); |
40 | if (!self->id) | 50 | |
41 | die("nomem"); | 51 | if (nid == NULL) |
52 | return -1; | ||
53 | |||
54 | self->size = nsize; | ||
55 | self->id = nid; | ||
42 | } | 56 | } |
43 | self->id[pos] = id; | 57 | self->id[pos] = id; |
58 | return 0; | ||
44 | } | 59 | } |
45 | 60 | ||
46 | /* | 61 | /* |
@@ -50,34 +65,41 @@ struct perf_header *perf_header__new(void) | |||
50 | { | 65 | { |
51 | struct perf_header *self = calloc(sizeof(*self), 1); | 66 | struct perf_header *self = calloc(sizeof(*self), 1); |
52 | 67 | ||
53 | if (!self) | 68 | if (self != NULL) { |
54 | die("nomem"); | 69 | self->size = 1; |
55 | 70 | self->attr = malloc(sizeof(void *)); | |
56 | self->size = 1; | ||
57 | self->attr = malloc(sizeof(void *)); | ||
58 | 71 | ||
59 | if (!self->attr) | 72 | if (self->attr == NULL) { |
60 | die("nomem"); | 73 | free(self); |
74 | self = NULL; | ||
75 | } | ||
76 | } | ||
61 | 77 | ||
62 | return self; | 78 | return self; |
63 | } | 79 | } |
64 | 80 | ||
65 | void perf_header__add_attr(struct perf_header *self, | 81 | int perf_header__add_attr(struct perf_header *self, |
66 | struct perf_header_attr *attr) | 82 | struct perf_header_attr *attr) |
67 | { | 83 | { |
68 | int pos = self->attrs; | 84 | int pos = self->attrs; |
69 | 85 | ||
70 | if (self->frozen) | 86 | if (self->frozen) |
71 | die("frozen"); | 87 | return -1; |
72 | 88 | ||
73 | self->attrs++; | 89 | self->attrs++; |
74 | if (self->attrs > self->size) { | 90 | if (self->attrs > self->size) { |
75 | self->size *= 2; | 91 | int nsize = self->size * 2; |
76 | self->attr = realloc(self->attr, self->size * sizeof(void *)); | 92 | struct perf_header_attr **nattr; |
77 | if (!self->attr) | 93 | |
78 | die("nomem"); | 94 | nattr = realloc(self->attr, nsize * sizeof(void *)); |
95 | if (nattr == NULL) | ||
96 | return -1; | ||
97 | |||
98 | self->size = nsize; | ||
99 | self->attr = nattr; | ||
79 | } | 100 | } |
80 | self->attr[pos] = attr; | 101 | self->attr[pos] = attr; |
102 | return 0; | ||
81 | } | 103 | } |
82 | 104 | ||
83 | #define MAX_EVENT_NAME 64 | 105 | #define MAX_EVENT_NAME 64 |
@@ -124,71 +146,110 @@ static const char *__perf_magic = "PERFFILE"; | |||
124 | 146 | ||
125 | #define PERF_MAGIC (*(u64 *)__perf_magic) | 147 | #define PERF_MAGIC (*(u64 *)__perf_magic) |
126 | 148 | ||
127 | struct perf_file_section { | ||
128 | u64 offset; | ||
129 | u64 size; | ||
130 | }; | ||
131 | |||
132 | struct perf_file_attr { | 149 | struct perf_file_attr { |
133 | struct perf_event_attr attr; | 150 | struct perf_event_attr attr; |
134 | struct perf_file_section ids; | 151 | struct perf_file_section ids; |
135 | }; | 152 | }; |
136 | 153 | ||
137 | struct perf_file_header { | 154 | void perf_header__set_feat(struct perf_header *self, int feat) |
138 | u64 magic; | 155 | { |
139 | u64 size; | 156 | set_bit(feat, self->adds_features); |
140 | u64 attr_size; | 157 | } |
141 | struct perf_file_section attrs; | ||
142 | struct perf_file_section data; | ||
143 | struct perf_file_section event_types; | ||
144 | DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); | ||
145 | }; | ||
146 | 158 | ||
147 | void perf_header__feat_trace_info(struct perf_header *header) | 159 | bool perf_header__has_feat(const struct perf_header *self, int feat) |
148 | { | 160 | { |
149 | set_bit(HEADER_TRACE_INFO, header->adds_features); | 161 | return test_bit(feat, self->adds_features); |
150 | } | 162 | } |
151 | 163 | ||
152 | static void do_write(int fd, void *buf, size_t size) | 164 | static int do_write(int fd, const void *buf, size_t size) |
153 | { | 165 | { |
154 | while (size) { | 166 | while (size) { |
155 | int ret = write(fd, buf, size); | 167 | int ret = write(fd, buf, size); |
156 | 168 | ||
157 | if (ret < 0) | 169 | if (ret < 0) |
158 | die("failed to write"); | 170 | return -1; |
159 | 171 | ||
160 | size -= ret; | 172 | size -= ret; |
161 | buf += ret; | 173 | buf += ret; |
162 | } | 174 | } |
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int write_buildid_table(int fd, struct list_head *id_head) | ||
180 | { | ||
181 | struct build_id_list *iter, *next; | ||
182 | |||
183 | list_for_each_entry_safe(iter, next, id_head, list) { | ||
184 | struct build_id_event *b = &iter->event; | ||
185 | |||
186 | if (do_write(fd, b, sizeof(*b)) < 0 || | ||
187 | do_write(fd, iter->dso_name, iter->len) < 0) | ||
188 | return -1; | ||
189 | list_del(&iter->list); | ||
190 | free(iter); | ||
191 | } | ||
192 | |||
193 | return 0; | ||
163 | } | 194 | } |
164 | 195 | ||
165 | static void perf_header__adds_write(struct perf_header *self, int fd) | 196 | static void |
197 | perf_header__adds_write(struct perf_header *self, int fd) | ||
166 | { | 198 | { |
167 | struct perf_file_section trace_sec; | 199 | LIST_HEAD(id_list); |
168 | u64 cur_offset = lseek(fd, 0, SEEK_CUR); | 200 | int nr_sections; |
169 | unsigned long *feat_mask = self->adds_features; | 201 | struct perf_file_section *feat_sec; |
202 | int sec_size; | ||
203 | u64 sec_start; | ||
204 | int idx = 0; | ||
205 | |||
206 | if (fetch_build_id_table(&id_list)) | ||
207 | perf_header__set_feat(self, HEADER_BUILD_ID); | ||
208 | |||
209 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | ||
210 | if (!nr_sections) | ||
211 | return; | ||
212 | |||
213 | feat_sec = calloc(sizeof(*feat_sec), nr_sections); | ||
214 | if (!feat_sec) | ||
215 | die("No memory"); | ||
216 | |||
217 | sec_size = sizeof(*feat_sec) * nr_sections; | ||
218 | |||
219 | sec_start = self->data_offset + self->data_size; | ||
220 | lseek(fd, sec_start + sec_size, SEEK_SET); | ||
221 | |||
222 | if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { | ||
223 | struct perf_file_section *trace_sec; | ||
224 | |||
225 | trace_sec = &feat_sec[idx++]; | ||
170 | 226 | ||
171 | if (test_bit(HEADER_TRACE_INFO, feat_mask)) { | ||
172 | /* Write trace info */ | 227 | /* Write trace info */ |
173 | trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR); | 228 | trace_sec->offset = lseek(fd, 0, SEEK_CUR); |
174 | read_tracing_data(fd, attrs, nr_counters); | 229 | read_tracing_data(fd, attrs, nr_counters); |
175 | trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset; | 230 | trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; |
176 | |||
177 | /* Write trace info headers */ | ||
178 | lseek(fd, cur_offset, SEEK_SET); | ||
179 | do_write(fd, &trace_sec, sizeof(trace_sec)); | ||
180 | |||
181 | /* | ||
182 | * Update cur_offset. So that other (future) | ||
183 | * features can set their own infos in this place. But if we are | ||
184 | * the only feature, at least that seeks to the place the data | ||
185 | * should begin. | ||
186 | */ | ||
187 | cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); | ||
188 | } | 231 | } |
189 | }; | ||
190 | 232 | ||
191 | void perf_header__write(struct perf_header *self, int fd) | 233 | |
234 | if (perf_header__has_feat(self, HEADER_BUILD_ID)) { | ||
235 | struct perf_file_section *buildid_sec; | ||
236 | |||
237 | buildid_sec = &feat_sec[idx++]; | ||
238 | |||
239 | /* Write build-ids */ | ||
240 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); | ||
241 | if (write_buildid_table(fd, &id_list) < 0) | ||
242 | die("failed to write buildid table"); | ||
243 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; | ||
244 | } | ||
245 | |||
246 | lseek(fd, sec_start, SEEK_SET); | ||
247 | if (do_write(fd, feat_sec, sec_size) < 0) | ||
248 | die("failed to write feature section"); | ||
249 | free(feat_sec); | ||
250 | } | ||
251 | |||
252 | void perf_header__write(struct perf_header *self, int fd, bool at_exit) | ||
192 | { | 253 | { |
193 | struct perf_file_header f_header; | 254 | struct perf_file_header f_header; |
194 | struct perf_file_attr f_attr; | 255 | struct perf_file_attr f_attr; |
@@ -202,7 +263,8 @@ void perf_header__write(struct perf_header *self, int fd) | |||
202 | attr = self->attr[i]; | 263 | attr = self->attr[i]; |
203 | 264 | ||
204 | attr->id_offset = lseek(fd, 0, SEEK_CUR); | 265 | attr->id_offset = lseek(fd, 0, SEEK_CUR); |
205 | do_write(fd, attr->id, attr->ids * sizeof(u64)); | 266 | if (do_write(fd, attr->id, attr->ids * sizeof(u64)) < 0) |
267 | die("failed to write perf header"); | ||
206 | } | 268 | } |
207 | 269 | ||
208 | 270 | ||
@@ -218,18 +280,21 @@ void perf_header__write(struct perf_header *self, int fd) | |||
218 | .size = attr->ids * sizeof(u64), | 280 | .size = attr->ids * sizeof(u64), |
219 | } | 281 | } |
220 | }; | 282 | }; |
221 | do_write(fd, &f_attr, sizeof(f_attr)); | 283 | if (do_write(fd, &f_attr, sizeof(f_attr)) < 0) |
284 | die("failed to write perf header attribute"); | ||
222 | } | 285 | } |
223 | 286 | ||
224 | self->event_offset = lseek(fd, 0, SEEK_CUR); | 287 | self->event_offset = lseek(fd, 0, SEEK_CUR); |
225 | self->event_size = event_count * sizeof(struct perf_trace_event_type); | 288 | self->event_size = event_count * sizeof(struct perf_trace_event_type); |
226 | if (events) | 289 | if (events) |
227 | do_write(fd, events, self->event_size); | 290 | if (do_write(fd, events, self->event_size) < 0) |
228 | 291 | die("failed to write perf header events"); | |
229 | perf_header__adds_write(self, fd); | ||
230 | 292 | ||
231 | self->data_offset = lseek(fd, 0, SEEK_CUR); | 293 | self->data_offset = lseek(fd, 0, SEEK_CUR); |
232 | 294 | ||
295 | if (at_exit) | ||
296 | perf_header__adds_write(self, fd); | ||
297 | |||
233 | f_header = (struct perf_file_header){ | 298 | f_header = (struct perf_file_header){ |
234 | .magic = PERF_MAGIC, | 299 | .magic = PERF_MAGIC, |
235 | .size = sizeof(f_header), | 300 | .size = sizeof(f_header), |
@@ -251,7 +316,8 @@ void perf_header__write(struct perf_header *self, int fd) | |||
251 | memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); | 316 | memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); |
252 | 317 | ||
253 | lseek(fd, 0, SEEK_SET); | 318 | lseek(fd, 0, SEEK_SET); |
254 | do_write(fd, &f_header, sizeof(f_header)); | 319 | if (do_write(fd, &f_header, sizeof(f_header)) < 0) |
320 | die("failed to write perf header"); | ||
255 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | 321 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); |
256 | 322 | ||
257 | self->frozen = 1; | 323 | self->frozen = 1; |
@@ -272,43 +338,112 @@ static void do_read(int fd, void *buf, size_t size) | |||
272 | } | 338 | } |
273 | } | 339 | } |
274 | 340 | ||
275 | static void perf_header__adds_read(struct perf_header *self, int fd) | 341 | int perf_header__process_sections(struct perf_header *self, int fd, |
342 | int (*process)(struct perf_file_section *self, | ||
343 | int feat, int fd)) | ||
276 | { | 344 | { |
277 | const unsigned long *feat_mask = self->adds_features; | 345 | struct perf_file_section *feat_sec; |
346 | int nr_sections; | ||
347 | int sec_size; | ||
348 | int idx = 0; | ||
349 | int err = 0, feat = 1; | ||
278 | 350 | ||
279 | if (test_bit(HEADER_TRACE_INFO, feat_mask)) { | 351 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); |
280 | struct perf_file_section trace_sec; | 352 | if (!nr_sections) |
353 | return 0; | ||
281 | 354 | ||
282 | do_read(fd, &trace_sec, sizeof(trace_sec)); | 355 | feat_sec = calloc(sizeof(*feat_sec), nr_sections); |
283 | lseek(fd, trace_sec.offset, SEEK_SET); | 356 | if (!feat_sec) |
284 | trace_report(fd); | 357 | return -1; |
285 | lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); | 358 | |
359 | sec_size = sizeof(*feat_sec) * nr_sections; | ||
360 | |||
361 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | ||
362 | |||
363 | do_read(fd, feat_sec, sec_size); | ||
364 | |||
365 | while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { | ||
366 | if (perf_header__has_feat(self, feat)) { | ||
367 | struct perf_file_section *sec = &feat_sec[idx++]; | ||
368 | |||
369 | err = process(sec, feat, fd); | ||
370 | if (err < 0) | ||
371 | break; | ||
372 | } | ||
373 | ++feat; | ||
286 | } | 374 | } |
375 | |||
376 | free(feat_sec); | ||
377 | return err; | ||
287 | }; | 378 | }; |
288 | 379 | ||
380 | int perf_file_header__read(struct perf_file_header *self, | ||
381 | struct perf_header *ph, int fd) | ||
382 | { | ||
383 | lseek(fd, 0, SEEK_SET); | ||
384 | do_read(fd, self, sizeof(*self)); | ||
385 | |||
386 | if (self->magic != PERF_MAGIC || | ||
387 | self->attr_size != sizeof(struct perf_file_attr)) | ||
388 | return -1; | ||
389 | |||
390 | if (self->size != sizeof(*self)) { | ||
391 | /* Support the previous format */ | ||
392 | if (self->size == offsetof(typeof(*self), adds_features)) | ||
393 | bitmap_zero(self->adds_features, HEADER_FEAT_BITS); | ||
394 | else | ||
395 | return -1; | ||
396 | } | ||
397 | |||
398 | memcpy(&ph->adds_features, &self->adds_features, | ||
399 | sizeof(self->adds_features)); | ||
400 | |||
401 | ph->event_offset = self->event_types.offset; | ||
402 | ph->event_size = self->event_types.size; | ||
403 | ph->data_offset = self->data.offset; | ||
404 | ph->data_size = self->data.size; | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int perf_file_section__process(struct perf_file_section *self, | ||
409 | int feat, int fd) | ||
410 | { | ||
411 | if (lseek(fd, self->offset, SEEK_SET) < 0) { | ||
412 | pr_debug("Failed to lseek to %Ld offset for feature %d, " | ||
413 | "continuing...\n", self->offset, feat); | ||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | switch (feat) { | ||
418 | case HEADER_TRACE_INFO: | ||
419 | trace_report(fd); | ||
420 | break; | ||
421 | |||
422 | case HEADER_BUILD_ID: | ||
423 | if (perf_header__read_build_ids(fd, self->offset, self->size)) | ||
424 | pr_debug("Failed to read buildids, continuing...\n"); | ||
425 | break; | ||
426 | default: | ||
427 | pr_debug("unknown feature %d, continuing...\n", feat); | ||
428 | } | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
289 | struct perf_header *perf_header__read(int fd) | 433 | struct perf_header *perf_header__read(int fd) |
290 | { | 434 | { |
291 | struct perf_header *self = perf_header__new(); | 435 | struct perf_header *self = perf_header__new(); |
292 | struct perf_file_header f_header; | 436 | struct perf_file_header f_header; |
293 | struct perf_file_attr f_attr; | 437 | struct perf_file_attr f_attr; |
294 | u64 f_id; | 438 | u64 f_id; |
295 | |||
296 | int nr_attrs, nr_ids, i, j; | 439 | int nr_attrs, nr_ids, i, j; |
297 | 440 | ||
298 | lseek(fd, 0, SEEK_SET); | 441 | if (self == NULL) |
299 | do_read(fd, &f_header, sizeof(f_header)); | 442 | die("nomem"); |
300 | 443 | ||
301 | if (f_header.magic != PERF_MAGIC || | 444 | if (perf_file_header__read(&f_header, self, fd) < 0) |
302 | f_header.attr_size != sizeof(f_attr)) | ||
303 | die("incompatible file format"); | 445 | die("incompatible file format"); |
304 | 446 | ||
305 | if (f_header.size != sizeof(f_header)) { | ||
306 | /* Support the previous format */ | ||
307 | if (f_header.size == offsetof(typeof(f_header), adds_features)) | ||
308 | bitmap_zero(f_header.adds_features, HEADER_FEAT_BITS); | ||
309 | else | ||
310 | die("incompatible file format"); | ||
311 | } | ||
312 | nr_attrs = f_header.attrs.size / sizeof(f_attr); | 447 | nr_attrs = f_header.attrs.size / sizeof(f_attr); |
313 | lseek(fd, f_header.attrs.offset, SEEK_SET); | 448 | lseek(fd, f_header.attrs.offset, SEEK_SET); |
314 | 449 | ||
@@ -320,6 +455,8 @@ struct perf_header *perf_header__read(int fd) | |||
320 | tmp = lseek(fd, 0, SEEK_CUR); | 455 | tmp = lseek(fd, 0, SEEK_CUR); |
321 | 456 | ||
322 | attr = perf_header_attr__new(&f_attr.attr); | 457 | attr = perf_header_attr__new(&f_attr.attr); |
458 | if (attr == NULL) | ||
459 | die("nomem"); | ||
323 | 460 | ||
324 | nr_ids = f_attr.ids.size / sizeof(u64); | 461 | nr_ids = f_attr.ids.size / sizeof(u64); |
325 | lseek(fd, f_attr.ids.offset, SEEK_SET); | 462 | lseek(fd, f_attr.ids.offset, SEEK_SET); |
@@ -327,9 +464,12 @@ struct perf_header *perf_header__read(int fd) | |||
327 | for (j = 0; j < nr_ids; j++) { | 464 | for (j = 0; j < nr_ids; j++) { |
328 | do_read(fd, &f_id, sizeof(f_id)); | 465 | do_read(fd, &f_id, sizeof(f_id)); |
329 | 466 | ||
330 | perf_header_attr__add_id(attr, f_id); | 467 | if (perf_header_attr__add_id(attr, f_id) < 0) |
468 | die("nomem"); | ||
331 | } | 469 | } |
332 | perf_header__add_attr(self, attr); | 470 | if (perf_header__add_attr(self, attr) < 0) |
471 | die("nomem"); | ||
472 | |||
333 | lseek(fd, tmp, SEEK_SET); | 473 | lseek(fd, tmp, SEEK_SET); |
334 | } | 474 | } |
335 | 475 | ||
@@ -342,15 +482,7 @@ struct perf_header *perf_header__read(int fd) | |||
342 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); | 482 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); |
343 | } | 483 | } |
344 | 484 | ||
345 | memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features)); | 485 | perf_header__process_sections(self, fd, perf_file_section__process); |
346 | |||
347 | perf_header__adds_read(self, fd); | ||
348 | |||
349 | self->event_offset = f_header.event_types.offset; | ||
350 | self->event_size = f_header.event_types.size; | ||
351 | |||
352 | self->data_offset = f_header.data.offset; | ||
353 | self->data_size = f_header.data.size; | ||
354 | 486 | ||
355 | lseek(fd, self->data_offset, SEEK_SET); | 487 | lseek(fd, self->data_offset, SEEK_SET); |
356 | 488 | ||