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 $
10 * $DragonFly: src/lib/libdisk/Attic/chunk.c,v 1.3 2005/03/13 15:10:03 swildner Exp $
18 #include <sys/types.h>
22 #define new_chunk() memset(malloc(sizeof(struct chunk)), 0, sizeof(struct chunk))
24 /* Is c2 completely inside c1 ? */
27 Chunk_Inside(struct chunk *c1, struct chunk *c2)
29 /* if c1 ends before c2 do */
30 if (c1->end < c2->end)
32 /* if c1 starts after c2 do */
33 if (c1->offset > c2->offset)
39 Find_Mother_Chunk(struct chunk *chunks, u_long offset, u_long end, chunk_e type)
41 struct chunk *c1,*c2,ct;
47 if (Chunk_Inside(chunks, &ct))
50 for(c1 = chunks->part; c1; c1 = c1->next) {
53 if (Chunk_Inside(c1, &ct))
58 for(c1 = chunks->part; c1; c1 = c1->next) {
60 if (Chunk_Inside(c1, &ct))
62 if (c1->type != extended)
64 for(c2 = c1->part; c2; c2 = c2->next)
66 && Chunk_Inside(c2, &ct))
71 warn("Unsupported mother type in Find_Mother_Chunk");
77 Free_Chunk(struct chunk *c1)
80 if(c1->private_data && c1->private_free)
81 (*c1->private_free)(c1->private_data);
91 Clone_Chunk(struct chunk *c1)
100 if (c1->private_data && c1->private_clone)
101 c2->private_data = c2->private_clone(c2->private_data);
102 c2->name = strdup(c2->name);
103 c2->next = Clone_Chunk(c2->next);
104 c2->part = Clone_Chunk(c2->part);
109 Insert_Chunk(struct chunk *c2, u_long offset, u_long size, const char *name,
110 chunk_e type, int subtype, u_long flags)
112 struct chunk *ct,*cs;
114 /* We will only insert into empty spaces */
115 if (c2->type != unused)
119 if (!ct) return __LINE__;
120 memset(ct, 0, sizeof *ct);
124 ct->end = offset + size - 1;
126 ct->name = strdup(name);
127 ct->subtype = subtype;
130 if (!Chunk_Inside(c2, ct)) {
135 if(type==freebsd || type==extended) {
137 if (!cs) return __LINE__;
138 memset(cs, 0, sizeof *cs);
142 cs->end = offset + size - 1;
144 cs->name = strdup("-");
148 /* Make a new chunk for any trailing unused space */
149 if (c2->end > ct->end) {
151 if (!cs) return __LINE__;
154 cs->offset = ct->end + 1;
155 cs->size = c2->end - ct->end;
157 cs->name = strdup(c2->name);
159 c2->size -= c2->end - ct->end;
162 /* If no leading unused space just occupy the old chunk */
163 if (c2->offset == ct->offset) {
167 c2->subtype = ct->subtype;
168 c2->flags = ct->flags;
174 /* else insert new chunk and adjust old one */
175 c2->end = ct->offset - 1;
176 c2->size -= ct->size;
183 Add_Chunk(struct disk *d, long offset, u_long size, const char *name,
184 chunk_e type, int subtype, u_long flags)
186 struct chunk *c1,*c2,ct;
187 u_long end = offset + size - 1;
193 d->chunks = c1 = new_chunk();
194 if (!c1) return __LINE__;
195 memset(c1, 0, sizeof *c1);
196 c2 = c1->part = new_chunk();
197 if (!c2) return __LINE__;
198 memset(c2,0,sizeof *c2);
199 c2->disk = c1->disk = d;
200 c2->offset = c1->offset = offset;
201 c2->size = c1->size = size;
202 c2->end = c1->end = end;
203 c1->name = strdup(name);
204 c2->name = strdup("-");
208 c1->subtype = subtype;
214 if(!c1 && (type == freebsd || type == fat || type == unknown))
215 c1 = Find_Mother_Chunk(d->chunks, offset, end, extended);
216 if(!c1 && (type == freebsd || type == fat || type == unknown))
217 c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
218 if(!c1 && type == extended)
219 c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
220 if(!c1 && type == part)
221 c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd);
224 for(c2 = c1->part; c2; c2 = c2->next) {
225 if (c2->type != unused)
227 if(Chunk_Inside(c2, &ct)) {
230 if (!(flags & CHUNK_ALIGN))
232 if (offset == d->chunks->offset
233 && end == d->chunks->end)
236 /* Round down to prev cylinder */
237 offset = Prev_Cyl_Aligned(d,offset);
238 /* Stay inside the parent */
239 if (offset < c2->offset)
241 /* Round up to next cylinder */
242 offset = Next_Cyl_Aligned(d, offset);
243 /* Keep one track clear in front of parent */
244 if (offset == c1->offset)
245 offset = Next_Track_Aligned(d, offset + 1);
247 /* Work on the (end+1) */
249 /* Round up to cylinder */
250 size = Next_Cyl_Aligned(d, size);
251 /* Stay inside parent */
252 if ((size-1) > c2->end)
254 /* Round down to cylinder */
255 size = Prev_Cyl_Aligned(d, size);
257 /* Convert back to size */
261 return Insert_Chunk(c2, offset, size, name,
262 type, subtype, flags);
269 ShowChunkFlags(struct chunk *c)
274 if (c->flags & CHUNK_BSD_COMPAT) ret[i++] = 'C';
275 if (c->flags & CHUNK_ACTIVE) ret[i++] = 'A';
276 if (c->flags & CHUNK_ALIGN) ret[i++] = '=';
277 if (c->flags & CHUNK_IS_ROOT) ret[i++] = 'R';
283 Print_Chunk(struct chunk *c1,int offset)
287 for(i = 0; i < offset - 2; i++) putchar(' ');
288 for(; i < offset; i++) putchar('-');
290 for(; i < 10; i++) putchar(' ');
291 printf("%p %8ld %8lu %8lu %-8s %-8s 0x%02x %s",
292 c1, c1->offset, c1->size, c1->end, c1->name,
293 chunk_n[c1->type], c1->subtype,
296 Print_Chunk(c1->part, offset + 2);
297 Print_Chunk(c1->next, offset);
301 Debug_Chunk(struct chunk *c1)
307 Delete_Chunk(struct disk *d, struct chunk *c)
309 return(Delete_Chunk2(d, c, 0));
313 Delete_Chunk2(struct disk *d, struct chunk *c, int rflags)
315 struct chunk *c1=0, *c2, *c3;
316 chunk_e type = c->type;
317 long offset = c->offset;
321 if(!c1 && (type == freebsd || type == fat || type == unknown))
322 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, extended);
323 if(!c1 && (type == freebsd || type == fat || type == unknown))
324 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, whole);
325 if(!c1 && type == extended)
326 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, whole);
327 if(!c1 && type == part)
328 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, freebsd);
331 for(c2 = c1->part; c2; c2 = c2->next) {
337 c2->name = strdup("-");
338 Free_Chunk(c2->part);
346 * Collapse multiple unused elements together, and attempt
347 * to extend the previous chunk into the freed chunk.
349 * We only extend non-unused elements which are marked
350 * for newfs (we can't extend working filesystems), and
351 * only if we are called with DELCHUNK_RECOVER.
353 for(c2 = c1->part; c2; c2 = c2->next) {
354 if (c2->type != unused) {
355 if (c2->offset + c2->size != offset ||
356 (rflags & DELCHUNK_RECOVER) == 0 ||
357 (c2->flags & CHUNK_NEWFS) == 0) {
360 /* else extend into free area */
364 if (c2->next->type != unused)
367 c2->size += c3->size;
380 Collapse_Chunk(struct disk *d, struct chunk *c1)
382 struct chunk *c2, *c3;
384 if(c1->next && Collapse_Chunk(d, c1->next))
387 if(c1->type == unused && c1->next && c1->next->type == unused) {
389 c1->size += c3->size;
399 if (Collapse_Chunk(d, c1->part))
402 if (c1->type == whole)
405 if(c3->type == unused && c3->size == c1->size) {
409 if(c3->type == unused) {
411 if (!c2) barfout(1, "malloc failed");
415 c1->name = strdup("-");
422 c2->offset += c1->size;
423 c2->size -= c1->size;
429 for(c2=c3;c2->next;c2 = c2->next)
431 if (c2 && c2->type == unused) {
435 c1->size -= c2->size;