udftools

- Main Page
- Classes
- Files

- File List
- File Members

All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
extent.c
Go to the documentation of this file.
1 /*
2 * extent.c
3 *
4 * Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu>
5 * All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
28 #include "config.h"
29
30 #include <malloc.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <time.h>
38 #include <sys/time.h>
39 #include <errno.h>
40
41 #include "libudffs.h"
42
112 struct udf_extent *next_extent(struct udf_extent *start_ext, enum udf_space_type type)
113 {
114 while (start_ext != NULL && !(start_ext->space_type & type))
115 start_ext = start_ext->next;
116
117 return start_ext;
118 }
119
129 uint32_t next_extent_size(struct udf_extent *start_ext, enum udf_space_type type, uint32_t blocks, uint32_t offset)
130 {
131 uint32_t inc;
132
133 start_ext = next_extent(start_ext, type);
134 cont:
135 while (start_ext != NULL && start_ext->blocks < blocks)
136 start_ext = next_extent(start_ext->next, type);
137
138 if (start_ext != NULL && start_ext->start % offset)
139 {
140 inc = offset - (start_ext->start % offset);
141 if (start_ext->blocks - inc < blocks)
142 {
143 start_ext = next_extent(start_ext->next, type);
144 goto cont;
145 }
146 }
147 else
148 inc = 0;
149
150 return start_ext ? start_ext->start + inc : 0;
151 }
152
159 struct udf_extent *prev_extent(struct udf_extent *start_ext, enum udf_space_type type)
160 {
161 while (start_ext != NULL && !(start_ext->space_type & type))
162 start_ext = start_ext->prev;
163
164 return start_ext;
165 }
166
176 uint32_t prev_extent_size(struct udf_extent *start_ext, enum udf_space_type type, uint32_t blocks, uint32_t offset)
177 {
178 uint32_t dec;
179
180 start_ext = prev_extent(start_ext, type);
181 cont:
182 while (start_ext != NULL && start_ext->blocks < blocks)
183 start_ext = prev_extent(start_ext->prev, type);
184
185 if (start_ext != NULL && (start_ext->start + start_ext->blocks) % offset)
186 {
187 dec = (start_ext->start + start_ext->blocks) % offset;
188 if (start_ext->blocks - dec < blocks)
189 {
190 start_ext = prev_extent(start_ext->prev, type);
191 goto cont;
192 }
193 }
194 else
195 dec = 0;
196
197 return start_ext ? start_ext->start + start_ext->blocks - dec - blocks : 0; // could this cause fragmentation?
198 }
199
207 struct udf_extent *find_extent(struct udf_disc *disc, uint32_t start)
208 {
209 struct udf_extent *start_ext = disc->head;
210
211 while (start_ext->next != NULL)
212 {
213 if (start_ext->start + start_ext->blocks > start)
214 break;
215 start_ext = start_ext->next;
216 }
217 return start_ext;
218 }
219
230 struct udf_extent *set_extent(struct udf_disc *disc, enum udf_space_type type, uint32_t start, uint32_t blocks)
231 {
232 struct udf_extent *new_ext, *start_ext = find_extent(disc, start);
233
234 if (start == start_ext->start)
235 {
236 if (blocks == start_ext->blocks)
237 {
238 start_ext->space_type = type;
239
240 return start_ext;
241 }
242 else if (blocks < start_ext->blocks)
243 {
244 new_ext = malloc(sizeof(struct udf_extent));
245 new_ext->space_type = type;
246 new_ext->start = start;
247 new_ext->blocks = blocks;
248 new_ext->head = new_ext->tail = NULL;
249 new_ext->prev = start_ext->prev;
250 if (new_ext->prev)
251 new_ext->prev->next = new_ext;
252 new_ext->next = start_ext;
253 if (disc->head == start_ext)
254 disc->head = new_ext;
255
256 start_ext->start += blocks;
257 start_ext->blocks -= blocks;
258 start_ext->prev = new_ext;
259
260 return new_ext;
261 }
262 else /* blocks > start_ext->blocks */
263 {
264 printf("trying to change type of multiple extents\n");
265 exit(1);
266 start_ext->space_type = type;
267
268 return start_ext;
269 }
270 }
271 else /* start > start_ext->start */
272 {
273 if (start + blocks == start_ext->start + start_ext->blocks)
274 {
275 new_ext = malloc(sizeof(struct udf_extent));
276 new_ext->space_type = type;
277 new_ext->start = start;
278 new_ext->blocks = blocks;
279 new_ext->head = new_ext->tail = NULL;
280 new_ext->prev = start_ext;
281 new_ext->next = start_ext->next;
282 if (new_ext->next)
283 new_ext->next->prev = new_ext;
284 if (disc->tail == start_ext)
285 disc->tail = new_ext;
286
287 start_ext->blocks -= blocks;
288 start_ext->next = new_ext;
289
290 return new_ext;
291 }
292 else if (start + blocks < start_ext->start + start_ext->blocks)
293 {
294 new_ext = malloc(sizeof(struct udf_extent));
295 new_ext->space_type = type;
296 new_ext->start = start;
297 new_ext->blocks = blocks;
298 new_ext->head = new_ext->tail = NULL;
299 new_ext->prev = start_ext;
300
301 new_ext->next = malloc(sizeof(struct udf_extent));
302 new_ext->next->prev = new_ext;
303 new_ext->next->space_type = start_ext->space_type;
304 new_ext->next->start = start + blocks;
305 new_ext->next->blocks = start_ext->blocks - blocks - start + start_ext->start;
306 new_ext->next->head = new_ext->next->tail = NULL;
307 new_ext->next->next = start_ext->next;
308 if (new_ext->next->next)
309 new_ext->next->next->prev = new_ext->next;
310 if (disc->tail == start_ext)
311 disc->tail = new_ext->next;
312
313 start_ext->blocks = start - start_ext->start;
314 start_ext->next = new_ext;
315
316 return new_ext;
317 }
318 else /* start + blocks > start_ext->start + start_ext->blocks */
319 {
320 if (start_ext->blocks < blocks)
321 {
322 printf("trying to change type of multiple extents\n");
323 exit(1);
324 }
325 new_ext = malloc(sizeof(struct udf_extent));
326 new_ext->space_type = type;
327 new_ext->start = start;
328 new_ext->blocks = blocks;
329 new_ext->head = new_ext->tail = NULL;
330 new_ext->prev = start_ext;
331 new_ext->next = start_ext->next;
332 if (new_ext->next)
333 new_ext->next->prev = new_ext;
334 if (disc->tail == start_ext)
335 disc->tail = new_ext;
336
337 start_ext->blocks -= blocks;
338 start_ext->next = new_ext;
339
340 return new_ext;
341 }
342 }
343 }
344
351 struct udf_desc *next_desc(struct udf_desc *start_desc, uint16_t ident)
352 {
353 while (start_desc != NULL && start_desc->ident != ident)
354 start_desc = start_desc->next;
355
356 return start_desc;
357 }
358
366 struct udf_desc *find_desc(struct udf_extent *ext, uint32_t offset)
367 {
368 struct udf_desc *start_desc = ext->head;
369
370 while (start_desc->next != NULL)
371 {
372 if (start_desc->offset == offset)
373 return start_desc;
374 else if (start_desc->offset > offset)
375 return start_desc->prev;
376 else
377 start_desc = start_desc->next;
378 }
379 return start_desc;
380 }
381
393 struct udf_desc *set_desc(struct udf_disc *disc, struct udf_extent *ext, uint16_t ident, uint32_t offset, uint32_t length, struct udf_data *data)
394 {
395 struct udf_desc *start_desc, *new_desc = calloc(1, sizeof(struct udf_desc));
396
397 new_desc->ident = ident;
398 new_desc->offset = offset;
399 new_desc->length = length;
400 if (data == NULL)
401 new_desc->data = alloc_data(NULL, length);
402 else
403 new_desc->data = data;
404
405 if (ext->head == NULL)
406 {
407 ext->head = ext->tail = new_desc;
408 new_desc->next = new_desc->prev = NULL;
409 }
410 else
411 {
412 start_desc = find_desc(ext, offset);
413 if (start_desc == NULL)
414 {
415 new_desc->next = ext->head;
416 new_desc->prev = NULL;
417 new_desc->next->prev = new_desc;
418 ext->head = new_desc;
419 }
420 else
421 {
422 new_desc->next = start_desc->next;
423 new_desc->prev = start_desc;
424 if (start_desc->next)
425 start_desc->next->prev = new_desc;
426 else
427 ext->tail = new_desc;
428 start_desc->next = new_desc;
429 }
430 }
431
432 return new_desc;
433 }
434
442 void append_data(struct udf_desc *desc, struct udf_data *data)
443 {
444 struct udf_data *ndata = desc->data;
445
446 desc->length += data->length;
447
448 while (ndata->next != NULL)
449 ndata = ndata->next;
450
451 ndata->next = data;
452 data->prev = ndata;
453 }
454
462 struct udf_data *alloc_data(void *buffer, int length)
463 {
464 struct udf_data *data = calloc(1, sizeof(struct udf_data));
465
466 if (buffer)
467 data->buffer = buffer;
468 else if (length)
469 data->buffer = calloc(1, length+sizeof(unsigned long)); // why the sizeof?
470 data->length = length;
471
472 return data;
473 }
udf_space_type
udf_space_type
Definition: libudffs.h:61
udf_extent::blocks
uint32_t blocks
Definition: libudffs.h:135
prev_extent
struct udf_extent * prev_extent(struct udf_extent *start_ext, enum udf_space_type type)
find the previous udf_extent of a given space_type on a udf_extent list
Definition: extent.c:159
udf_disc::tail
struct udf_extent * tail
Definition: libudffs.h:128
udf_extent::next
struct udf_extent * next
Definition: libudffs.h:140
prev_extent_size
uint32_t prev_extent_size(struct udf_extent *start_ext, enum udf_space_type type, uint32_t blocks, uint32_t offset)
find the previous udf_extent of a given space_type on a udf_extent list that satisfies the necessary ...
Definition: extent.c:176
udf_extent::tail
struct udf_desc * tail
Definition: libudffs.h:138
set_desc
struct udf_desc * set_desc(struct udf_disc *disc, struct udf_extent *ext, uint16_t ident, uint32_t offset, uint32_t length, struct udf_data *data)
allocate a new udf_descriptor having a udf_data item and insert it into the udf_descriptor list of a ...
Definition: extent.c:393
udf_data::prev
struct udf_data * prev
Definition: libudffs.h:160
udf_disc::head
struct udf_extent * head
Definition: libudffs.h:127
udf_desc::length
uint64_t length
Definition: libudffs.h:148
alloc_data
struct udf_data * alloc_data(void *buffer, int length)
allocate a new udf_data item and initialize it with either allocated zeros or the supplied payload ...
Definition: extent.c:462
udf_desc::next
struct udf_desc * next
Definition: libudffs.h:151
udf_desc::data
struct udf_data * data
Definition: libudffs.h:149
udf_data::length
uint64_t length
Definition: libudffs.h:157
next_extent
struct udf_extent * next_extent(struct udf_extent *start_ext, enum udf_space_type type)
find the next udf_extent of a given space_type on a udf_extent list
Definition: extent.c:112
udf_data::next
struct udf_data * next
Definition: libudffs.h:159
udf_desc::ident
uint16_t ident
Definition: libudffs.h:146
udf_data
Definition: libudffs.h:155
next_extent_size
uint32_t next_extent_size(struct udf_extent *start_ext, enum udf_space_type type, uint32_t blocks, uint32_t offset)
find the next udf_extent of a given space_type on a udf_extent list that satisfies the necessary size...
Definition: extent.c:129
udf_extent
Definition: libudffs.h:131
udf_desc::prev
struct udf_desc * prev
Definition: libudffs.h:152
set_extent
struct udf_extent * set_extent(struct udf_disc *disc, enum udf_space_type type, uint32_t start, uint32_t blocks)
set the space_type, location and size of a udf_extent on a udf_disc's udf_extent list, splitting the udf_extent if required to have the returned udf_extent only contain the requested blocks
Definition: extent.c:230
next_desc
struct udf_desc * next_desc(struct udf_desc *start_desc, uint16_t ident)
find the next udf_descriptor of a given tag ident on a udf_descriptor list
Definition: extent.c:351
udf_extent::start
uint32_t start
Definition: libudffs.h:134
udf_desc
Definition: libudffs.h:144
udf_desc::offset
uint32_t offset
Definition: libudffs.h:147
udf_disc
Definition: libudffs.h:95
udf_extent::head
struct udf_desc * head
Definition: libudffs.h:137
find_desc
struct udf_desc * find_desc(struct udf_extent *ext, uint32_t offset)
search the udf_descriptor list of a udf_extent to find the udf_descriptor that describes a particular...
Definition: extent.c:366
libudffs.h
udf_extent::prev
struct udf_extent * prev
Definition: libudffs.h:141
udf_data::buffer
void * buffer
Definition: libudffs.h:158
append_data
void append_data(struct udf_desc *desc, struct udf_data *data)
append a udf_data list to the end of the udf_data list of a udf_descriptor and update the udf_descrip...
Definition: extent.c:442
udf_extent::space_type
enum udf_space_type space_type
Definition: libudffs.h:133
find_extent
struct udf_extent * find_extent(struct udf_disc *disc, uint32_t start)
find the udf_extent on a udf_disc's udf_extent list which contains a particular block ...
Definition: extent.c:207