OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [hfs/] [extent.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/fs/hfs/extent.c
3
 *
4
 * Copyright (C) 1995-1997  Paul H. Hargrove
5
 * This file may be distributed under the terms of the GNU General Public License.
6
 *
7
 * This file contains the functions related to the extents B-tree.
8
 *
9
 * "XXX" in a comment is a note to myself to consider changing something.
10
 *
11
 * In function preconditions the term "valid" applied to a pointer to
12
 * a structure means that the pointer is non-NULL and the structure it
13
 * points to has all fields initialized to consistent values.
14
 */
15
 
16
#include "hfs.h"
17
 
18
/*================ File-local data type ================*/
19
 
20
/* An extent record on disk*/
21
struct hfs_raw_extent {
22
        hfs_word_t      block1;
23
        hfs_word_t      length1;
24
        hfs_word_t      block2;
25
        hfs_word_t      length2;
26
        hfs_word_t      block3;
27
        hfs_word_t      length3;
28
};
29
 
30
/*================ File-local functions ================*/
31
 
32
/*
33
 * build_key
34
 */
35
static inline void build_key(struct hfs_ext_key *key,
36
                             const struct hfs_fork *fork, hfs_u16 block)
37
{
38
        key->KeyLen = 7;
39
        key->FkType = fork->fork;
40
        hfs_put_nl(fork->entry->cnid, key->FNum);
41
        hfs_put_hs(block,             key->FABN);
42
}
43
 
44
 
45
/*
46
 * lock_bitmap()
47
 *
48
 * Get an exclusive lock on the B-tree bitmap.
49
 */
50
static inline void lock_bitmap(struct hfs_mdb *mdb) {
51
        while (mdb->bitmap_lock) {
52
                hfs_sleep_on(&mdb->bitmap_wait);
53
        }
54
        mdb->bitmap_lock = 1;
55
}
56
 
57
/*
58
 * unlock_bitmap()
59
 *
60
 * Relinquish an exclusive lock on the B-tree bitmap.
61
 */
62
static inline void unlock_bitmap(struct hfs_mdb *mdb) {
63
        mdb->bitmap_lock = 0;
64
        hfs_wake_up(&mdb->bitmap_wait);
65
}
66
 
67
/*
68
 * dump_ext()
69
 *
70
 * prints the content of a extent for debugging purposes.
71
 */
72
#if defined(DEBUG_EXTENTS) || defined(DEBUG_ALL)
73
static void dump_ext(const char *msg, const struct hfs_extent *e) {
74
        if (e) {
75
                hfs_warn("%s (%d-%d) (%d-%d) (%d-%d)\n", msg,
76
                         e->start,
77
                         e->start + e->length[0] - 1,
78
                         e->start + e->length[0],
79
                         e->start + e->length[0] + e->length[1] - 1,
80
                         e->start + e->length[0] + e->length[1],
81
                         e->end);
82
        } else {
83
                hfs_warn("%s NULL\n", msg);
84
        }
85
}
86
#else
87
#define dump_ext(A,B) {}
88
#endif
89
 
90
/*
91
 * read_extent()
92
 *
93
 * Initializes a (struct hfs_extent) from a (struct hfs_raw_extent) and
94
 * the number of the starting block for the extent.
95
 *
96
 * Note that the callers must check that to,from != NULL
97
 */
98
static void read_extent(struct hfs_extent *to,
99
                        const struct hfs_raw_extent *from,
100
                        hfs_u16 start)
101
{
102
        to->start = start;
103
        to->block[0]  = hfs_get_hs(from->block1);
104
        to->length[0] = hfs_get_hs(from->length1);
105
        to->block[1]  = hfs_get_hs(from->block2);
106
        to->length[1] = hfs_get_hs(from->length2);
107
        to->block[2]  = hfs_get_hs(from->block3);
108
        to->length[2] = hfs_get_hs(from->length3);
109
        to->end = start + to->length[0] + to->length[1] + to->length[2] - 1;
110
        to->next = to->prev = NULL;
111
        to->count = 0;
112
}
113
 
114
/*
115
 * write_extent()
116
 *
117
 * Initializes a (struct hfs_raw_extent) from a (struct hfs_extent).
118
 *
119
 * Note that the callers must check that to,from != NULL
120
 */
121
static void write_extent(struct hfs_raw_extent *to,
122
                         const struct hfs_extent *from)
123
{
124
        hfs_put_hs(from->block[0], to->block1);
125
        hfs_put_hs(from->length[0], to->length1);
126
        hfs_put_hs(from->block[1], to->block2);
127
        hfs_put_hs(from->length[1], to->length2);
128
        hfs_put_hs(from->block[2], to->block3);
129
        hfs_put_hs(from->length[2], to->length3);
130
}
131
 
132
/*
133
 * decode_extent()
134
 *
135
 * Given an extent record and allocation block offset into the file,
136
 * return the number of the corresponding allocation block on disk,
137
 * or -1 if the desired block is not mapped by the given extent.
138
 *
139
 * Note that callers must check that extent != NULL
140
 */
141
static int decode_extent(const struct hfs_extent * extent, int block)
142
{
143
        if (!extent || (block < extent->start) || (block > extent->end) ||
144
            (extent->end == (hfs_u16)(extent->start - 1))) {
145
                return -1;
146
        }
147
        block -= extent->start;
148
        if (block < extent->length[0]) {
149
                return block + extent->block[0];
150
        }
151
        block -= extent->length[0];
152
        if (block < extent->length[1]) {
153
                return block + extent->block[1];
154
        }
155
        return block + extent->block[2] - extent->length[1];
156
}
157
 
158
/*
159
 * relse_ext()
160
 *
161
 * Reduce the reference count of an in-core extent record by one,
162
 * removing it from memory if the count falls to zero.
163
 */
164
static void relse_ext(struct hfs_extent *ext)
165
{
166
        if (--ext->count || !ext->start) {
167
                return;
168
        }
169
        ext->prev->next = ext->next;
170
        if (ext->next) {
171
                ext->next->prev = ext->prev;
172
        }
173
        HFS_DELETE(ext);
174
}
175
 
176
/*
177
 * set_cache()
178
 *
179
 * Changes the 'cache' field of the fork.
180
 */
181
static inline void set_cache(struct hfs_fork *fork, struct hfs_extent *ext)
182
{
183
        struct hfs_extent *tmp = fork->cache;
184
 
185
        ++ext->count;
186
        fork->cache = ext;
187
        relse_ext(tmp);
188
}
189
 
190
/*
191
 * find_ext()
192
 *
193
 * Given a pointer to a (struct hfs_file) and an allocation block
194
 * number in the file, find the extent record containing that block.
195
 * Returns a pointer to the extent record on success or NULL on failure.
196
 * The 'cache' field of 'fil' also points to the extent so it has a
197
 * reference count of at least 2.
198
 *
199
 * Callers must check that fil != NULL
200
 */
201
static struct hfs_extent * find_ext(struct hfs_fork *fork, int alloc_block)
202
{
203
        struct hfs_cat_entry *entry = fork->entry;
204
        struct hfs_btree *tr= entry->mdb->ext_tree;
205
        struct hfs_ext_key target, *key;
206
        struct hfs_brec brec;
207
        struct hfs_extent *ext, *ptr;
208
        int tmp;
209
 
210
        if (alloc_block < 0) {
211
                ext = &fork->first;
212
                goto found;
213
        }
214
 
215
        ext = fork->cache;
216
        if (!ext || (alloc_block < ext->start)) {
217
                ext = &fork->first;
218
        }
219
        while (ext->next && (alloc_block > ext->end)) {
220
                ext = ext->next;
221
        }
222
        if ((alloc_block <= ext->end) && (alloc_block >= ext->start)) {
223
                goto found;
224
        }
225
 
226
        /* time to read more extents */
227
        if (!HFS_NEW(ext)) {
228
                goto bail3;
229
        }
230
 
231
        build_key(&target, fork, alloc_block);
232
 
233
        tmp = hfs_bfind(&brec, tr, HFS_BKEY(&target), HFS_BFIND_READ_LE);
234
        if (tmp < 0) {
235
                goto bail2;
236
        }
237
 
238
        key = (struct hfs_ext_key *)brec.key;
239
        if ((hfs_get_nl(key->FNum) != hfs_get_nl(target.FNum)) ||
240
            (key->FkType != fork->fork)) {
241
                goto bail1;
242
        }
243
 
244
        read_extent(ext, brec.data, hfs_get_hs(key->FABN));
245
        hfs_brec_relse(&brec, NULL);
246
 
247
        if ((alloc_block > ext->end) && (alloc_block < ext->start)) {
248
                /* something strange happened */
249
                goto bail2;
250
        }
251
 
252
        ptr = fork->cache;
253
        if (!ptr || (alloc_block < ptr->start)) {
254
                ptr = &fork->first;
255
        }
256
        while (ptr->next && (alloc_block > ptr->end)) {
257
                ptr = ptr->next;
258
        }
259
        if (ext->start == ptr->start) {
260
                /* somebody beat us to it. */
261
                HFS_DELETE(ext);
262
                ext = ptr;
263
        } else if (ext->start < ptr->start) {
264
                /* insert just before ptr */
265
                ptr->prev->next = ext;
266
                ext->prev = ptr->prev;
267
                ext->next = ptr;
268
                ptr->prev = ext;
269
        } else {
270
                /* insert at end */
271
                ptr->next = ext;
272
                ext->prev = ptr;
273
        }
274
 found:
275
        ++ext->count; /* for return value */
276
        set_cache(fork, ext);
277
        return ext;
278
 
279
 bail1:
280
        hfs_brec_relse(&brec, NULL);
281
 bail2:
282
        HFS_DELETE(ext);
283
 bail3:
284
        return NULL;
285
}
286
 
287
/*
288
 * delete_extent()
289
 *
290
 * Description:
291
 *   Deletes an extent record from a fork, reducing its physical length.
292
 * Input Variable(s):
293
 *   struct hfs_fork *fork: the fork
294
 *   struct hfs_extent *ext: the current last extent for 'fork'
295
 * Output Variable(s):
296
 *   NONE
297
 * Returns:
298
 *   void
299
 * Preconditions:
300
 *   'fork' points to a valid (struct hfs_fork)
301
 *   'ext' point to a valid (struct hfs_extent) which is the last in 'fork'
302
 *    and which is not also the first extent in 'fork'.
303
 * Postconditions:
304
 *   The extent record has been removed if possible, and a warning has been
305
 *   printed otherwise.
306
 */
307
static void delete_extent(struct hfs_fork *fork, struct hfs_extent *ext)
308
{
309
        struct hfs_mdb *mdb = fork->entry->mdb;
310
        struct hfs_ext_key key;
311
        int error;
312
 
313
        if (fork->cache == ext) {
314
                set_cache(fork, ext->prev);
315
        }
316
        ext->prev->next = NULL;
317
        if (ext->count != 1) {
318
                hfs_warn("hfs_truncate: extent has count %d.\n", ext->count);
319
        }
320
 
321
        lock_bitmap(mdb);
322
        error = hfs_clear_vbm_bits(mdb, ext->block[2], ext->length[2]);
323
        if (error) {
324
                hfs_warn("hfs_truncate: error %d freeing blocks.\n", error);
325
        }
326
        error = hfs_clear_vbm_bits(mdb, ext->block[1], ext->length[1]);
327
        if (error) {
328
                hfs_warn("hfs_truncate: error %d freeing blocks.\n", error);
329
        }
330
        error = hfs_clear_vbm_bits(mdb, ext->block[0], ext->length[0]);
331
        if (error) {
332
                hfs_warn("hfs_truncate: error %d freeing blocks.\n", error);
333
        }
334
        unlock_bitmap(mdb);
335
 
336
        build_key(&key, fork, ext->start);
337
 
338
        error = hfs_bdelete(mdb->ext_tree, HFS_BKEY(&key));
339
        if (error) {
340
                hfs_warn("hfs_truncate: error %d deleting an extent.\n", error);
341
        }
342
 
343
        HFS_DELETE(ext);
344
}
345
 
346
/*
347
 * new_extent()
348
 *
349
 * Description:
350
 *   Adds a new extent record to a fork, extending its physical length.
351
 * Input Variable(s):
352
 *   struct hfs_fork *fork: the fork to extend
353
 *   struct hfs_extent *ext: the current last extent for 'fork'
354
 *   hfs_u16 ablock: the number of allocation blocks in 'fork'.
355
 *   hfs_u16 start: first allocation block to add to 'fork'.
356
 *   hfs_u16 len: the number of allocation blocks to add to 'fork'.
357
 *   hfs_u32 ablksz: number of sectors in an allocation block.
358
 * Output Variable(s):
359
 *   NONE
360
 * Returns:
361
 *   (struct hfs_extent *) the new extent or NULL
362
 * Preconditions:
363
 *   'fork' points to a valid (struct hfs_fork)
364
 *   'ext' point to a valid (struct hfs_extent) which is the last in 'fork'
365
 *   'ablock', 'start', 'len' and 'ablksz' are what they claim to be.
366
 * Postconditions:
367
 *   If NULL is returned then no changes have been made to 'fork'.
368
 *   If the return value is non-NULL that it is the extent that has been
369
 *   added to 'fork' both in memory and on disk.  The 'psize' field of
370
 *   'fork' has been updated to reflect the new physical size.
371
 */
372
static struct hfs_extent *new_extent(struct hfs_fork *fork,
373
                                     struct hfs_extent *ext,
374
                                     hfs_u16 ablock, hfs_u16 start,
375
                                     hfs_u16 len, hfs_u16 ablksz)
376
{
377
        struct hfs_raw_extent raw;
378
        struct hfs_ext_key key;
379
        int error;
380
 
381
        if (fork->entry->cnid == htonl(HFS_EXT_CNID)) {
382
                /* Limit extents tree to the record in the MDB */
383
                return NULL;
384
        }
385
 
386
        if (!HFS_NEW(ext->next)) {
387
                return NULL;
388
        }
389
        ext->next->prev = ext;
390
        ext->next->next = NULL;
391
        ext = ext->next;
392
        relse_ext(ext->prev);
393
 
394
        ext->start = ablock;
395
        ext->block[0] = start;
396
        ext->length[0] = len;
397
        ext->block[1] = 0;
398
        ext->length[1] = 0;
399
        ext->block[2] = 0;
400
        ext->length[2] = 0;
401
        ext->end = ablock + len - 1;
402
        ext->count = 1;
403
 
404
        write_extent(&raw, ext);
405
 
406
        build_key(&key, fork, ablock);
407
 
408
        error = hfs_binsert(fork->entry->mdb->ext_tree,
409
                            HFS_BKEY(&key), &raw, sizeof(raw));
410
        if (error) {
411
                ext->prev->next = NULL;
412
                HFS_DELETE(ext);
413
                return NULL;
414
        }
415
        set_cache(fork, ext);
416
        return ext;
417
}
418
 
419
/*
420
 * update_ext()
421
 *
422
 * Given a (struct hfs_fork) write an extent record back to disk.
423
 */
424
static void update_ext(struct hfs_fork *fork, struct hfs_extent *ext)
425
{
426
        struct hfs_ext_key target;
427
        struct hfs_brec brec;
428
 
429
        if (ext->start) {
430
                build_key(&target, fork, ext->start);
431
 
432
                if (!hfs_bfind(&brec, fork->entry->mdb->ext_tree,
433
                               HFS_BKEY(&target), HFS_BFIND_WRITE)) {
434
                        write_extent(brec.data, ext);
435
                        hfs_brec_relse(&brec, NULL);
436
                }
437
        }
438
}
439
 
440
/*
441
 * zero_blocks()
442
 *
443
 * Zeros-out 'num' allocation blocks beginning with 'start'.
444
 */
445
static int zero_blocks(struct hfs_mdb *mdb, int start, int num) {
446
        hfs_buffer buf;
447
        int end;
448
        int j;
449
 
450
        start = mdb->fs_start + start * mdb->alloc_blksz;
451
        end = start + num * mdb->alloc_blksz;
452
 
453
        for (j=start; j<end; ++j) {
454
                if (hfs_buffer_ok(buf = hfs_buffer_get(mdb->sys_mdb, j, 0))) {
455
                        memset(hfs_buffer_data(buf), 0, HFS_SECTOR_SIZE);
456
                        hfs_buffer_dirty(buf);
457
                        hfs_buffer_put(buf);
458
                }
459
        }
460
        return 0;
461
}
462
 
463
/*
464
 * shrink_fork()
465
 *
466
 * Try to remove enough allocation blocks from 'fork'
467
 * so that it is 'ablocks' allocation blocks long.
468
 */
469
static void shrink_fork(struct hfs_fork *fork, int ablocks)
470
{
471
        struct hfs_mdb *mdb = fork->entry->mdb;
472
        struct hfs_extent *ext;
473
        int i, error, next, count;
474
        hfs_u32 ablksz = mdb->alloc_blksz;
475
 
476
        next =  (fork->psize / ablksz) - 1;
477
        ext = find_ext(fork, next);
478
        while (ext && ext->start && (ext->start >= ablocks)) {
479
                next = ext->start - 1;
480
                delete_extent(fork, ext);
481
                ext = find_ext(fork, next);
482
        }
483
        if (!ext) {
484
                fork->psize = (next + 1) * ablksz;
485
                return;
486
        }
487
 
488
        if ((count = next + 1 - ablocks) > 0) {
489
                for (i=2; (i>=0) && !ext->length[i]; --i) {};
490
                lock_bitmap(mdb);
491
                while (count && (ext->length[i] <= count)) {
492
                        ext->end -= ext->length[i];
493
                        count -= ext->length[i];
494
                        error = hfs_clear_vbm_bits(mdb, ext->block[i],
495
                                                   ext->length[i]);
496
                        if (error) {
497
                                hfs_warn("hfs_truncate: error %d freeing "
498
                                       "blocks.\n", error);
499
                        }
500
                        ext->block[i] = ext->length[i] = 0;
501
                        --i;
502
                }
503
                if (count) {
504
                        ext->end -= count;
505
                        ext->length[i] -= count;
506
                        error = hfs_clear_vbm_bits(mdb, ext->block[i] +
507
                                                       ext->length[i], count);
508
                        if (error) {
509
                                hfs_warn("hfs_truncate: error %d freeing "
510
                                       "blocks.\n", error);
511
                        }
512
                }
513
                unlock_bitmap(mdb);
514
                update_ext(fork, ext);
515
        }
516
 
517
        fork->psize = ablocks * ablksz;
518
}
519
 
520
/*
521
 * grow_fork()
522
 *
523
 * Try to add enough allocation blocks to 'fork'
524
 * so that it is 'ablock' allocation blocks long.
525
 */
526
static int grow_fork(struct hfs_fork *fork, int ablocks)
527
{
528
        struct hfs_cat_entry *entry = fork->entry;
529
        struct hfs_mdb *mdb = entry->mdb;
530
        struct hfs_extent *ext;
531
        int i, start, err;
532
        hfs_u16 need, len=0;
533
        hfs_u32 ablksz = mdb->alloc_blksz;
534
        hfs_u32 blocks, clumpablks;
535
 
536
        blocks = fork->psize;
537
        need = ablocks - blocks/ablksz;
538
        if (need < 1) { /* no need to grow the fork */
539
                return 0;
540
        }
541
 
542
        /* round up to clumpsize */
543
        if (entry->u.file.clumpablks) {
544
                clumpablks = entry->u.file.clumpablks;
545
        } else {
546
                clumpablks = mdb->clumpablks;
547
        }
548
        need = ((need + clumpablks - 1) / clumpablks) * clumpablks;
549
 
550
        /* find last extent record and try to extend it */
551
        if (!(ext = find_ext(fork, blocks/ablksz - 1))) {
552
                /* somehow we couldn't find the end of the file! */
553
                return -1;
554
        }
555
 
556
        /* determine which is the last used extent in the record */
557
        /* then try to allocate the blocks immediately following it */
558
        for (i=2; (i>=0) && !ext->length[i]; --i) {};
559
        if (i>=0) {
560
                /* try to extend the last extent */
561
                start = ext->block[i] + ext->length[i];
562
 
563
                err = 0;
564
                lock_bitmap(mdb);
565
                len = hfs_vbm_count_free(mdb, start);
566
                if (!len) {
567
                        unlock_bitmap(mdb);
568
                        goto more_extents;
569
                }
570
                if (need < len) {
571
                        len = need;
572
                }
573
                err = hfs_set_vbm_bits(mdb, start, len);
574
                unlock_bitmap(mdb);
575
                if (err) {
576
                        relse_ext(ext);
577
                        return -1;
578
                }
579
 
580
                zero_blocks(mdb, start, len);
581
 
582
                ext->length[i] += len;
583
                ext->end += len;
584
                blocks = (fork->psize += len * ablksz);
585
                need -= len;
586
                update_ext(fork, ext);
587
        }
588
 
589
more_extents:
590
        /* add some more extents */
591
        while (need) {
592
                len = need;
593
                err = 0;
594
                lock_bitmap(mdb);
595
                start = hfs_vbm_search_free(mdb, &len);
596
                if (need < len) {
597
                        len = need;
598
                }
599
                err = hfs_set_vbm_bits(mdb, start, len);
600
                unlock_bitmap(mdb);
601
                if (!len || err) {
602
                        relse_ext(ext);
603
                        return -1;
604
                }
605
                zero_blocks(mdb, start, len);
606
 
607
                /* determine which is the first free extent in the record */
608
                for (i=0; (i<3) && ext->length[i]; ++i) {};
609
                if (i < 3) {
610
                        ext->block[i] = start;
611
                        ext->length[i] = len;
612
                        ext->end += len;
613
                        update_ext(fork, ext);
614
                } else {
615
                        if (!(ext = new_extent(fork, ext, blocks/ablksz,
616
                                               start, len, ablksz))) {
617
                                lock_bitmap(mdb);
618
                                hfs_clear_vbm_bits(mdb, start, len);
619
                                unlock_bitmap(mdb);
620
                                return -1;
621
                        }
622
                }
623
                blocks = (fork->psize += len * ablksz);
624
                need -= len;
625
        }
626
        set_cache(fork, ext);
627
        relse_ext(ext);
628
        return 0;
629
}
630
 
631
/*================ Global functions ================*/
632
 
633
/*
634
 * hfs_ext_compare()
635
 *
636
 * Description:
637
 *   This is the comparison function used for the extents B-tree.  In
638
 *   comparing extent B-tree entries, the file id is the most
639
 *   significant field (compared as unsigned ints); the fork type is
640
 *   the second most significant field (compared as unsigned chars);
641
 *   and the allocation block number field is the least significant
642
 *   (compared as unsigned ints).
643
 * Input Variable(s):
644
 *   struct hfs_ext_key *key1: pointer to the first key to compare
645
 *   struct hfs_ext_key *key2: pointer to the second key to compare
646
 * Output Variable(s):
647
 *   NONE
648
 * Returns:
649
 *   int: negative if key1<key2, positive if key1>key2, and 0 if key1==key2
650
 * Preconditions:
651
 *   key1 and key2 point to "valid" (struct hfs_ext_key)s.
652
 * Postconditions:
653
 *   This function has no side-effects */
654
int hfs_ext_compare(const struct hfs_ext_key *key1,
655
                    const struct hfs_ext_key *key2)
656
{
657
        unsigned int tmp;
658
        int retval;
659
 
660
        tmp = hfs_get_hl(key1->FNum) - hfs_get_hl(key2->FNum);
661
        if (tmp != 0) {
662
                retval = (int)tmp;
663
        } else {
664
                tmp = (unsigned char)key1->FkType - (unsigned char)key2->FkType;
665
                if (tmp != 0) {
666
                        retval = (int)tmp;
667
                } else {
668
                        retval = (int)(hfs_get_hs(key1->FABN)
669
                                       - hfs_get_hs(key2->FABN));
670
                }
671
        }
672
        return retval;
673
}
674
 
675
/*
676
 * hfs_extent_adj()
677
 *
678
 * Given an hfs_fork shrink or grow the fork to hold the
679
 * forks logical size.
680
 */
681
void hfs_extent_adj(struct hfs_fork *fork)
682
{
683
        if (fork) {
684
                hfs_u32 blks, ablocks, ablksz;
685
 
686
                if (fork->lsize > HFS_FORK_MAX) {
687
                        fork->lsize = HFS_FORK_MAX;
688
                }
689
 
690
                blks = (fork->lsize+HFS_SECTOR_SIZE-1) >> HFS_SECTOR_SIZE_BITS;
691
                ablksz = fork->entry->mdb->alloc_blksz;
692
                ablocks = (blks + ablksz - 1) / ablksz;
693
 
694
                if (blks > fork->psize) {
695
                        grow_fork(fork, ablocks);
696
                        if (blks > fork->psize) {
697
                                fork->lsize =
698
                                        fork->psize >> HFS_SECTOR_SIZE_BITS;
699
                        }
700
                } else if (blks < fork->psize) {
701
                        shrink_fork(fork, ablocks);
702
                }
703
        }
704
}
705
 
706
/*
707
 * hfs_extent_map()
708
 *
709
 * Given an hfs_fork and a block number within the fork, return the
710
 * number of the corresponding physical block on disk, or zero on
711
 * error.
712
 */
713
int hfs_extent_map(struct hfs_fork *fork, int block, int create)
714
{
715
        int ablksz, ablock, offset, tmp;
716
        struct hfs_extent *ext;
717
 
718
        if (!fork || !fork->entry || !fork->entry->mdb) {
719
                return 0;
720
        }
721
 
722
#if defined(DEBUG_EXTENTS) || defined(DEBUG_ALL)
723
        hfs_warn("hfs_extent_map: ablock %d of file %d, fork %d\n",
724
                 block, fork->entry->cnid, fork->fork);
725
#endif
726
 
727
        if (block < 0) {
728
                hfs_warn("hfs_extent_map: block < 0\n");
729
                return 0;
730
        }
731
        if (block > (HFS_FORK_MAX >> HFS_SECTOR_SIZE_BITS)) {
732
                hfs_warn("hfs_extent_map: block(0x%08x) > big; cnid=%d "
733
                         "fork=%d\n", block, fork->entry->cnid, fork->fork);
734
                return 0;
735
        }
736
        ablksz = fork->entry->mdb->alloc_blksz;
737
        offset = fork->entry->mdb->fs_start + (block % ablksz);
738
        ablock = block / ablksz;
739
 
740
        if (block >= fork->psize) {
741
                if (!create || (grow_fork(fork, ablock + 1) < 0))
742
                        return 0;
743
        }
744
 
745
#if defined(DEBUG_EXTENTS) || defined(DEBUG_ALL)
746
        hfs_warn("(lblock %d offset %d)\n", ablock, offset);
747
#endif
748
 
749
        if ((ext = find_ext(fork, ablock))) {
750
                dump_ext("trying new: ", ext);
751
                tmp = decode_extent(ext, ablock);
752
                relse_ext(ext);
753
                if (tmp >= 0) {
754
                        return tmp*ablksz + offset;
755
                }
756
        }
757
 
758
        return 0;
759
}
760
 
761
/*
762
 * hfs_extent_out()
763
 *
764
 * Copy the first extent record from a (struct hfs_fork) to a (struct
765
 * raw_extent), record (normally the one in the catalog entry).
766
 */
767
void hfs_extent_out(const struct hfs_fork *fork, hfs_byte_t dummy[12])
768
{
769
        struct hfs_raw_extent *ext = (struct hfs_raw_extent *)dummy;
770
 
771
        if (fork && ext) {
772
                write_extent(ext, &fork->first);
773
                dump_ext("extent out: ", &fork->first);
774
        }
775
}
776
 
777
/*
778
 * hfs_extent_in()
779
 *
780
 * Copy an raw_extent to the 'first' and 'cache' fields of an hfs_fork.
781
 */
782
void hfs_extent_in(struct hfs_fork *fork, const hfs_byte_t dummy[12])
783
{
784
        const struct hfs_raw_extent *ext =
785
                (const struct hfs_raw_extent *)dummy;
786
 
787
        if (fork && ext) {
788
                read_extent(&fork->first, ext, 0);
789
                fork->cache = &fork->first;
790
                fork->first.count = 2;
791
                dump_ext("extent in: ", &fork->first);
792
        }
793
}
794
 
795
/*
796
 * hfs_extent_free()
797
 *
798
 * Removes from memory all extents associated with 'fil'.
799
 */
800
void hfs_extent_free(struct hfs_fork *fork)
801
{
802
        if (fork) {
803
                set_cache(fork, &fork->first);
804
 
805
                if (fork->first.next) {
806
                        hfs_warn("hfs_extent_free: extents in use!\n");
807
                }
808
        }
809
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.