2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
9 * $FreeBSD: src/lib/libdisk/chunk.c,v 1.21.2.6 2002/01/07 07:53:29 dillon Exp $
17 #include <sys/types.h>
21 #define new_chunk() memset(malloc(sizeof(struct chunk)), 0, sizeof(struct chunk))
23 /* Is c2 completely inside c1 ? */
26 Chunk_Inside(struct chunk *c1, struct chunk *c2)
28 /* if c1 ends before c2 do */
29 if (c1->end < c2->end)
31 /* if c1 starts after c2 do */
32 if (c1->offset > c2->offset)
38 Find_Mother_Chunk(struct chunk *chunks, u_long offset, u_long end, chunk_e type)
40 struct chunk *c1,*c2,ct;
46 if (Chunk_Inside(chunks, &ct))
50 for(c1 = chunks->part; c1; c1 = c1->next) {
53 if (Chunk_Inside(c1, &ct))
59 for(c1 = chunks->part; c1; c1 = c1->next) {
61 if (Chunk_Inside(c1, &ct))
63 if (c1->type != extended)
65 for(c2 = c1->part; c2; c2 = c2->next)
67 && Chunk_Inside(c2, &ct))
72 warn("Unsupported mother type in Find_Mother_Chunk");
78 Free_Chunk(struct chunk *c1)
81 if(c1->private_data && c1->private_free)
82 (*c1->private_free)(c1->private_data);
95 Clone_Chunk(struct chunk *c1)
102 if (!c2) return NULL;
104 if (c1->private_data && c1->private_clone)
105 c2->private_data = c2->private_clone(c2->private_data);
106 c2->name = strdup(c2->name);
108 c2->sname = strdup(c2->sname);
110 c2->next = Clone_Chunk(c2->next);
111 c2->part = Clone_Chunk(c2->part);
117 Insert_Chunk(struct chunk *c2, u_long offset, u_long size, const char *name,
118 chunk_e type, int subtype, u_long flags, const char *sname)
120 Insert_Chunk(struct chunk *c2, u_long offset, u_long size, const char *name,
121 chunk_e type, int subtype, u_long flags)
124 struct chunk *ct,*cs;
126 /* We will only insert into empty spaces */
127 if (c2->type != unused)
131 if (!ct) return __LINE__;
132 memset(ct, 0, sizeof *ct);
136 ct->end = offset + size - 1;
139 ct->sname = strdup(sname);
141 ct->name = strdup(name);
142 ct->subtype = subtype;
145 if (!Chunk_Inside(c2, ct)) {
150 if(type==freebsd || type==extended) {
152 if (!cs) return __LINE__;
153 memset(cs, 0, sizeof *cs);
157 cs->end = offset + size - 1;
160 cs->sname = strdup(sname);
162 cs->name = strdup("-");
166 /* Make a new chunk for any trailing unused space */
167 if (c2->end > ct->end) {
169 if (!cs) return __LINE__;
172 cs->offset = ct->end + 1;
173 cs->size = c2->end - ct->end;
176 cs->sname = strdup(c2->sname);
179 cs->name = strdup(c2->name);
181 c2->size -= c2->end - ct->end;
184 /* If no leading unused space just occupy the old chunk */
185 if (c2->offset == ct->offset) {
187 c2->sname = ct->sname;
192 c2->subtype = ct->subtype;
193 c2->flags = ct->flags;
202 /* else insert new chunk and adjust old one */
203 c2->end = ct->offset - 1;
204 c2->size -= ct->size;
212 Add_Chunk(struct disk *d, long offset, u_long size, const char *name,
213 chunk_e type, int subtype, u_long flags, const char *sname)
215 Add_Chunk(struct disk *d, long offset, u_long size, const char *name,
216 chunk_e type, int subtype, u_long flags)
219 struct chunk *c1,*c2,ct;
220 u_long end = offset + size - 1;
226 d->chunks = c1 = new_chunk();
227 if (!c1) return __LINE__;
228 memset(c1, 0, sizeof *c1);
229 c2 = c1->part = new_chunk();
230 if (!c2) return __LINE__;
231 memset(c2,0,sizeof *c2);
232 c2->disk = c1->disk = d;
233 c2->offset = c1->offset = offset;
234 c2->size = c1->size = size;
235 c2->end = c1->end = end;
237 c1->sname = strdup(sname);
238 c2->sname = strdup("-");
240 c1->name = strdup(name);
241 c2->name = strdup("-");
245 c1->subtype = subtype;
256 if(!c1 && (type == freebsd || type == fat || type == unknown))
257 c1 = Find_Mother_Chunk(d->chunks, offset, end, extended);
259 if(!c1 && (type == freebsd || type == fat || type == unknown))
260 c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
262 if(!c1 && type == extended)
263 c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
265 if(!c1 && type == part)
266 c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd);
269 for(c2 = c1->part; c2; c2 = c2->next) {
270 if (c2->type != unused)
272 if(Chunk_Inside(c2, &ct)) {
275 if (!(flags & CHUNK_ALIGN))
277 if (offset == d->chunks->offset
278 && end == d->chunks->end)
281 /* Round down to prev cylinder */
282 offset = Prev_Cyl_Aligned(d,offset);
283 /* Stay inside the parent */
284 if (offset < c2->offset)
286 /* Round up to next cylinder */
287 offset = Next_Cyl_Aligned(d, offset);
288 /* Keep one track clear in front of parent */
289 if (offset == c1->offset)
290 offset = Next_Track_Aligned(d, offset + 1);
292 /* Work on the (end+1) */
294 /* Round up to cylinder */
295 size = Next_Cyl_Aligned(d, size);
296 /* Stay inside parent */
297 if ((size-1) > c2->end)
299 /* Round down to cylinder */
300 size = Prev_Cyl_Aligned(d, size);
302 /* Convert back to size */
307 return Insert_Chunk(c2, offset, size, name,
308 type, subtype, flags, sname);
310 return Insert_Chunk(c2, offset, size, name,
311 type, subtype, flags);
319 ShowChunkFlags(struct chunk *c)
324 if (c->flags & CHUNK_BSD_COMPAT) ret[i++] = 'C';
325 if (c->flags & CHUNK_ACTIVE) ret[i++] = 'A';
326 if (c->flags & CHUNK_ALIGN) ret[i++] = '=';
327 if (c->flags & CHUNK_IS_ROOT) ret[i++] = 'R';
333 Print_Chunk(struct chunk *c1,int offset)
337 for(i = 0; i < offset - 2; i++) putchar(' ');
338 for(; i < offset; i++) putchar('-');
340 for(; i < 10; i++) putchar(' ');
342 printf("%p %8ld %8lu %8lu %-8s %-16s %-8s 0x%02x %s",
343 c1, c1->offset, c1->size, c1->end, c1->name, c1->sname,
345 printf("%p %8ld %8lu %8lu %-8s %-8s 0x%02x %s",
346 c1, c1->offset, c1->size, c1->end, c1->name,
348 chunk_n[c1->type], c1->subtype,
351 Print_Chunk(c1->part, offset + 2);
352 Print_Chunk(c1->next, offset);
356 Debug_Chunk(struct chunk *c1)
362 Delete_Chunk(struct disk *d, struct chunk *c)
364 return(Delete_Chunk2(d, c, 0));
368 Delete_Chunk2(struct disk *d, struct chunk *c, int rflags)
370 struct chunk *c1=0, *c2, *c3;
371 chunk_e type = c->type;
372 long offset = c->offset;
377 if(!c1 && (type == freebsd || type == fat || type == unknown))
378 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, extended);
380 if(!c1 && (type == freebsd || type == fat || type == unknown))
381 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, whole);
383 if(!c1 && type == extended)
384 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, whole);
386 if(!c1 && type == part)
387 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, freebsd);
390 for(c2 = c1->part; c2; c2 = c2->next) {
397 c2->sname = strdup("-");
400 c2->name = strdup("-");
401 Free_Chunk(c2->part);
409 * Collapse multiple unused elements together, and attempt
410 * to extend the previous chunk into the freed chunk.
412 * We only extend non-unused elements which are marked
413 * for newfs (we can't extend working filesystems), and
414 * only if we are called with DELCHUNK_RECOVER.
416 for(c2 = c1->part; c2; c2 = c2->next) {
417 if (c2->type != unused) {
418 if (c2->offset + c2->size != offset ||
419 (rflags & DELCHUNK_RECOVER) == 0 ||
420 (c2->flags & CHUNK_NEWFS) == 0) {
423 /* else extend into free area */
427 if (c2->next->type != unused)
430 c2->size += c3->size;
443 Collapse_Chunk(struct disk *d, struct chunk *c1)
445 struct chunk *c2, *c3;
447 if(c1->next && Collapse_Chunk(d, c1->next))
450 if(c1->type == unused && c1->next && c1->next->type == unused) {
452 c1->size += c3->size;
462 if (Collapse_Chunk(d, c1->part))
465 if (c1->type == whole)
468 if(c3->type == unused && c3->size == c1->size) {
472 if(c3->type == unused) {
474 if (!c2) barfout(1, "malloc failed");
479 c1->sname = strdup("-");
481 c1->name = strdup("-");
488 c2->offset += c1->size;
489 c2->size -= c1->size;
495 for(c2=c3;c2->next;c2 = c2->next)
497 if (c2 && c2->type == unused) {
501 c1->size -= c2->size;