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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [ntfs/] [dir.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * dir.c
3
 *
4
 * Copyright (C) 1995-1997, 1999 Martin von Löwis
5
 * Copyright (C) 1999 Steve Dodd
6
 * Copyright (C) 1999 Joseph Malicki
7
 * Copyright (C) 2001 Anton Altaparmakov (AIA)
8
 */
9
 
10
#include "ntfstypes.h"
11
#include "struct.h"
12
#include "dir.h"
13
#include "macros.h"
14
 
15
#include <linux/errno.h>
16
#include "super.h"
17
#include "inode.h"
18
#include "attr.h"
19
#include "support.h"
20
#include "util.h"
21
#include <linux/smp_lock.h>
22
#include <linux/bitops.h>
23
 
24
static char I30[] = "$I30";
25
 
26
/* An index record should start with INDX, and the last word in each block
27
 * should contain the check value. If it passes, the original values need to
28
 * be restored. */
29
int ntfs_check_index_record(ntfs_inode *ino, char *record)
30
{
31
        return ntfs_fixup_record(record, "INDX", ino->u.index.recordsize);
32
}
33
 
34
static inline int ntfs_is_top(ntfs_u64 stack)
35
{
36
        return stack == 14;
37
}
38
 
39
static int ntfs_pop(ntfs_u64 *stack)
40
{
41
        static int width[16] = {1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,-1};
42
        int res = -1;
43
 
44
        switch (width[*stack & 15]) {
45
        case 1:
46
                res = (int)((*stack & 15) >> 1);
47
                *stack >>= 4;
48
                break;
49
        case 2:
50
                res = (int)(((*stack & 63) >> 2) + 7);
51
                *stack >>= 6;
52
                break;
53
        case 3:
54
                res = (int)(((*stack & 255) >> 3) + 23);
55
                *stack >>= 8;
56
                break;
57
        case 4:
58
                res = (int)(((*stack & 1023) >> 4) + 55);
59
                *stack >>= 10;
60
                break;
61
        default:
62
                ntfs_error("Unknown encoding\n");
63
        }
64
        return res;
65
}
66
 
67
static inline unsigned int ntfs_top(void)
68
{
69
        return 14;
70
}
71
 
72
static ntfs_u64 ntfs_push(ntfs_u64 stack, int i)
73
{
74
        if (i < 7)
75
                return (stack << 4) | (i << 1);
76
        if (i < 23)
77
                return (stack << 6) | ((i - 7) << 2) | 1;
78
        if (i < 55)
79
                return (stack << 8) | ((i - 23) << 3) | 3;
80
        if (i < 120)
81
                return (stack << 10) | ((i - 55) << 4) | 7;
82
        ntfs_error("Too many entries\n");
83
        return ~((ntfs_u64)0);
84
}
85
 
86
#if 0
87
static void ntfs_display_stack(ntfs_u64 stack)
88
{
89
        while(!ntfs_is_top(stack))
90
        {
91
                printf("%d ", ntfs_pop(&stack));
92
        }
93
        printf("\n");
94
}
95
#endif
96
 
97
/* True if the entry points to another block of entries. */
98
static inline int ntfs_entry_has_subnodes(char *entry)
99
{
100
        return (NTFS_GETU16(entry + 0xc) & 1);
101
}
102
 
103
/* True if it is not the 'end of dir' entry. */
104
static inline int ntfs_entry_is_used(char *entry)
105
{
106
        return !(NTFS_GETU16(entry + 0xc) & 2);
107
}
108
 
109
/*
110
 * Removed RACE for allocating index blocks. But stil not too happy.
111
 * There might be more races afterwards. (AIA)
112
 */
113
static int ntfs_allocate_index_block(ntfs_iterate_s *walk)
114
{
115
        ntfs_attribute *allocation, *bitmap = 0;
116
        int error, size, i, bit;
117
        ntfs_u8 *bmap;
118
        ntfs_io io;
119
        ntfs_volume *vol = walk->dir->vol;
120
 
121
        /* Check for allocation attribute. */
122
        allocation = ntfs_find_attr(walk->dir, vol->at_index_allocation, I30);
123
        if (!allocation) {
124
                ntfs_u8 bmp[8];
125
                /* Create index allocation attribute. */
126
                error = ntfs_create_attr(walk->dir, vol->at_index_allocation,
127
                                         I30, 0, 0, &allocation);
128
                if (error)
129
                        goto err_ret;
130
                ntfs_bzero(bmp, sizeof(bmp));
131
                error = ntfs_create_attr(walk->dir, vol->at_bitmap, I30, bmp,
132
                                         sizeof(bmp), &bitmap);
133
                if (error)
134
                        goto err_ret;
135
        } else
136
                bitmap = ntfs_find_attr(walk->dir, vol->at_bitmap, I30);
137
        if (!bitmap) {
138
                ntfs_error("Directory w/o bitmap\n");
139
                error = -EINVAL;
140
                goto err_ret;
141
        }
142
        size = bitmap->size;
143
        bmap = ntfs_malloc(size);
144
        if (!bmap) {
145
                error = -ENOMEM;
146
                goto err_ret;
147
        }
148
        io.fn_put = ntfs_put;
149
        io.fn_get = ntfs_get;
150
try_again:
151
        io.param = bmap;
152
        io.size = size;
153
        error = ntfs_read_attr(walk->dir, vol->at_bitmap, I30, 0, &io);
154
        if (error || (io.size != size && (error = -EIO, 1)))
155
                goto err_fb_out;
156
        /* Allocate a bit. */
157
        for (bit = i = 0; i < size; i++) {
158
                if (bmap[i] == 0xFF)
159
                        continue;
160
                bit = ffz(bmap[i]);
161
                if (bit < 8)
162
                        break;
163
        }
164
        if (i >= size) {
165
                /* FIXME: Extend bitmap. */
166
                error = -EOPNOTSUPP;
167
                goto err_fb_out;
168
        }
169
        /* Get the byte containing our bit again, now taking the BKL. */
170
        io.param = bmap;
171
        io.size = 1;
172
        lock_kernel();
173
        error = ntfs_read_attr(walk->dir, vol->at_bitmap, I30, i, &io);
174
        if (error || (io.size != 1 && (error = -EIO, 1)))
175
                goto err_unl_out;
176
        if (ntfs_test_and_set_bit(bmap, bit)) {
177
                unlock_kernel();
178
                /* Give other process(es) a chance to finish. */
179
                schedule();
180
                goto try_again;
181
        }
182
        walk->newblock = (i * 8 + bit) * walk->dir->u.index.clusters_per_record;
183
        io.param = bmap;
184
        error = ntfs_write_attr(walk->dir, vol->at_bitmap, I30, i, &io);
185
        if (error || (io.size != size && (error = -EIO, 1)))
186
                goto err_unl_out;
187
        /* Change inode on disk, required when bitmap is resident. */
188
        error = ntfs_update_inode(walk->dir);
189
        if (error)
190
                goto err_unl_out;
191
        unlock_kernel();
192
        ntfs_free(bmap);
193
        /* Check whether record is out of allocated range. */
194
        size = allocation->size;
195
        if (walk->newblock * vol->cluster_size >= size) {
196
                /* Build index record. */
197
                int hsize;
198
                int s1 = walk->dir->u.index.recordsize;
199
                int nr_fix = (s1 >> vol->sector_size) + 1;
200
                char *record = ntfs_malloc(s1);
201
                if (!record) {
202
                        error = -ENOMEM;
203
                        goto err_ret;
204
                }
205
                ntfs_bzero(record, s1);
206
                /* Magic */
207
                ntfs_memcpy(record, "INDX", 4);
208
                /* Offset to fixups */
209
                NTFS_PUTU16(record + 4, 0x28);
210
                /* Number of fixups. */
211
                NTFS_PUTU16(record + 6, nr_fix);
212
                /* Log file sequence number - We don't do journalling so we
213
                 * just set it to zero which should be the Right Thing. (AIA) */
214
                NTFS_PUTU64(record + 8, 0);
215
                /* VCN of buffer */
216
                NTFS_PUTU64(record + 0x10, walk->newblock);
217
                /* Header size. */
218
                hsize = 0x10 + 2 * nr_fix;
219
                hsize = (hsize + 7) & ~7; /* Align. */
220
                NTFS_PUTU16(record + 0x18, hsize);
221
                /* Total size of record. */
222
                NTFS_PUTU32(record + 0x20, s1 - 0x18);
223
                /* Writing the data will extend the attribute. */
224
                io.param = record;
225
                io.size = s1;
226
                io.do_read = 0;
227
                error = ntfs_readwrite_attr(walk->dir, allocation, size, &io);
228
                ntfs_free(record);
229
                if (error || (io.size != s1 && (error = -EIO, 1)))
230
                        goto err_ret;
231
                error = ntfs_update_inode(walk->dir);
232
                if (error)
233
                        goto err_ret;
234
        }
235
        return 0;
236
err_unl_out:
237
        unlock_kernel();
238
err_fb_out:
239
        ntfs_free(bmap);
240
err_ret:
241
        return error;
242
}
243
 
244
/* Write an index block (root or allocation) back to storage.
245
 * Used is the total number of bytes in buf, including all headers. */
246
static int ntfs_index_writeback(ntfs_iterate_s *walk, ntfs_u8 *buf, int block,
247
                                int used)
248
{
249
        ntfs_io io;
250
        int error;
251
        ntfs_attribute *a;
252
        ntfs_volume *vol = walk->dir->vol;
253
 
254
        io.fn_put = 0;
255
        io.fn_get = ntfs_get;
256
        io.param = buf;
257
        if (block == -1) {      /* Index root. */
258
                NTFS_PUTU16(buf + 0x14, used - 0x10);
259
                /* 0x18 is a copy thereof. */
260
                NTFS_PUTU16(buf + 0x18, used - 0x10);
261
                io.size = used;
262
                error = ntfs_write_attr(walk->dir, vol->at_index_root, I30, 0,
263
                                        &io);
264
                if (error || (io.size != used && (error = -EIO, 1)))
265
                        return error;
266
                /* Shrink if necessary. */
267
                a = ntfs_find_attr(walk->dir, vol->at_index_root, I30);
268
                ntfs_resize_attr(walk->dir, a, used);
269
        } else {
270
                NTFS_PUTU16(buf + 0x1C, used - 0x18);
271
                io.size = walk->dir->u.index.recordsize;
272
                error = ntfs_insert_fixups(buf, io.size);
273
                if (error) {
274
                        printk(KERN_ALERT "NTFS: ntfs_index_writeback() caught "
275
                                        "corrupt index record ntfs record "
276
                                        "header. Refusing to write corrupt "
277
                                        "data to disk. Unmount and run chkdsk "
278
                                        "immediately!\n");
279
                        return -EIO;
280
                }
281
                error = ntfs_write_attr(walk->dir, vol->at_index_allocation,
282
                                I30, (__s64)block << vol->cluster_size_bits,
283
                                &io);
284
                if (error || (io.size != walk->dir->u.index.recordsize &&
285
                                (error = -EIO, 1)))
286
                        return error;
287
        }
288
        return 0;
289
}
290
 
291
static int ntfs_split_record(ntfs_iterate_s *walk, char *start, int bsize,
292
                             int usize)
293
{
294
        char *entry, *prev;
295
        ntfs_u8 *newbuf = 0, *middle = 0;
296
        int error, othersize, mlen;
297
        ntfs_io io;
298
        ntfs_volume *vol = walk->dir->vol;
299
        int oldblock;
300
 
301
        error = ntfs_allocate_index_block(walk);
302
        if (error)
303
                return error;
304
        /* This should not happen. */
305
        if (walk->block == -1) {
306
                ntfs_error("Trying to split root");
307
                return -EOPNOTSUPP;
308
        }
309
        entry = start + NTFS_GETU16(start + 0x18) + 0x18;
310
        for (prev = entry; entry - start < usize / 2;
311
                                               entry += NTFS_GETU16(entry + 8))
312
                prev = entry;
313
        newbuf = ntfs_malloc(vol->index_record_size);
314
        if (!newbuf)
315
                return -ENOMEM;
316
        io.fn_put = ntfs_put;
317
        io.fn_get = ntfs_get;
318
        io.param = newbuf;
319
        io.size = vol->index_record_size;
320
        /* Read in old header. FIXME: Reading everything is overkill. */
321
        error = ntfs_read_attr(walk->dir, vol->at_index_allocation, I30,
322
                        (__s64)walk->newblock << vol->cluster_size_bits, &io);
323
        if (error)
324
                goto out;
325
        if (io.size != vol->index_record_size) {
326
                error = -EIO;
327
                goto out;
328
        }
329
        /* FIXME: Adjust header. */
330
        /* Copy everything from entry to new block. */
331
        othersize = usize - (entry - start);
332
        ntfs_memcpy(newbuf + NTFS_GETU16(newbuf + 0x18) + 0x18, entry,
333
                                                                    othersize);
334
        /* Copy flags. */
335
        NTFS_PUTU32(newbuf + 0x24, NTFS_GETU32(start + 0x24));
336
        error = ntfs_index_writeback(walk, newbuf, walk->newblock,
337
                                othersize + NTFS_GETU16(newbuf + 0x18) + 0x18);
338
        if (error)
339
                goto out;
340
        /* Move prev to walk. */
341
        mlen = NTFS_GETU16(prev + 0x8);
342
        /* Remember old child node. */
343
        if (ntfs_entry_has_subnodes(prev))
344
                oldblock = NTFS_GETU32(prev + mlen - 8);
345
        else
346
                oldblock = -1;
347
        /* Allow for pointer to subnode. */
348
        middle = ntfs_malloc(ntfs_entry_has_subnodes(prev) ? mlen : mlen + 8);
349
        if (!middle){
350
                error = -ENOMEM;
351
                goto out;
352
        }
353
        ntfs_memcpy(middle, prev, mlen);
354
        /* Set has_subnodes flag. */
355
        NTFS_PUTU8(middle + 0xC, NTFS_GETU8(middle + 0xC) | 1);
356
        /* Middle entry points to block, parent entry will point to newblock. */
357
        NTFS_PUTU64(middle + mlen - 8, walk->block);
358
        if (walk->new_entry)
359
                ntfs_error("Entry not reset");
360
        walk->new_entry = middle;
361
        walk->u.flags |= ITERATE_SPLIT_DONE;
362
        /* Terminate old block. */
363
        othersize = usize - (prev-start);
364
        NTFS_PUTU64(prev, 0);
365
        if (oldblock == -1) {
366
                NTFS_PUTU32(prev + 8, 0x10);
367
                NTFS_PUTU32(prev + 0xC, 2);
368
                othersize += 0x10;
369
        } else {
370
                NTFS_PUTU32(prev + 8, 0x18);
371
                NTFS_PUTU32(prev + 0xC, 3);
372
                NTFS_PUTU64(prev + 0x10, oldblock);
373
                othersize += 0x18;
374
        }
375
        /* Write back original block. */
376
        error = ntfs_index_writeback(walk, start, walk->block, othersize);
377
 out:
378
        if (newbuf)
379
                ntfs_free(newbuf);
380
        if (middle)
381
                ntfs_free(middle);
382
        return error;
383
}
384
 
385
static int ntfs_dir_insert(ntfs_iterate_s *walk, char *start, char* entry)
386
{
387
        int blocksize, usedsize, error, offset;
388
        int do_split = 0;
389
        offset = entry - start;
390
        if (walk->block == -1) { /* index root */
391
                blocksize = walk->dir->vol->mft_record_size;
392
                usedsize = NTFS_GETU16(start + 0x14) + 0x10;
393
        } else {
394
                blocksize = walk->dir->u.index.recordsize;
395
                usedsize = NTFS_GETU16(start + 0x1C) + 0x18;
396
        }
397
        if (usedsize + walk->new_entry_size > blocksize) {
398
                char* s1 = ntfs_malloc(blocksize + walk->new_entry_size);
399
                if (!s1)
400
                        return -ENOMEM;
401
                ntfs_memcpy(s1, start, usedsize);
402
                do_split = 1;
403
                /* Adjust entry to s1. */
404
                entry = s1 + (entry - start);
405
                start = s1;
406
        }
407
        ntfs_memmove(entry + walk->new_entry_size, entry, usedsize - offset);
408
        ntfs_memcpy(entry, walk->new_entry, walk->new_entry_size);
409
        usedsize += walk->new_entry_size;
410
        ntfs_free(walk->new_entry);
411
        walk->new_entry = 0;
412
        if (do_split) {
413
                error = ntfs_split_record(walk, start, blocksize, usedsize);
414
                ntfs_free(start);
415
        } else {
416
                error = ntfs_index_writeback(walk, start, walk->block,usedsize);
417
                if (error)
418
                        return error;
419
        }
420
        return 0;
421
}
422
 
423
/* Try to split INDEX_ROOT attributes. Return -E2BIG if nothing changed. */
424
int ntfs_split_indexroot(ntfs_inode *ino)
425
{
426
        ntfs_attribute *ra;
427
        ntfs_u8 *root = 0, *index = 0;
428
        ntfs_io io;
429
        int error, off, i, bsize, isize;
430
        ntfs_iterate_s walk;
431
 
432
        ra = ntfs_find_attr(ino, ino->vol->at_index_root, I30);
433
        if (!ra)
434
                return -ENOTDIR;
435
        bsize = ino->vol->mft_record_size;
436
        root = ntfs_malloc(bsize);
437
        if (!root)
438
                return -E2BIG;
439
        io.fn_put = ntfs_put;
440
        io.param = root;
441
        io.size = bsize;
442
        error = ntfs_read_attr(ino, ino->vol->at_index_root, I30, 0, &io);
443
        if (error)
444
                goto out;
445
        off = 0x20;
446
        /* Count number of entries. */
447
        for (i = 0; ntfs_entry_is_used(root + off); i++)
448
                off += NTFS_GETU16(root + off + 8);
449
        if (i <= 2) {
450
                /* We don't split small index roots. */
451
                error = -E2BIG;
452
                goto out;
453
        }
454
        index = ntfs_malloc(ino->vol->index_record_size);
455
        if (!index) {
456
                error = -ENOMEM;
457
                goto out;
458
        }
459
        walk.dir = ino;
460
        walk.block = -1;
461
        walk.result = walk.new_entry = 0;
462
        walk.name = 0;
463
        error = ntfs_allocate_index_block(&walk);
464
        if (error)
465
                goto out;
466
        /* Write old root to new index block. */
467
        io.param = index;
468
        io.size = ino->vol->index_record_size;
469
        error = ntfs_read_attr(ino, ino->vol->at_index_allocation, I30,
470
                (__s64)walk.newblock << ino->vol->cluster_size_bits, &io);
471
        if (error)
472
                goto out;
473
        isize = NTFS_GETU16(root + 0x18) - 0x10;
474
        ntfs_memcpy(index + NTFS_GETU16(index + 0x18) + 0x18, root+0x20, isize);
475
        /* Copy flags. */
476
        NTFS_PUTU32(index + 0x24, NTFS_GETU32(root + 0x1C));
477
        error = ntfs_index_writeback(&walk, index, walk.newblock,
478
                                     isize + NTFS_GETU16(index + 0x18) + 0x18);
479
        if (error)
480
                goto out;
481
        /* Mark root as split. */
482
        NTFS_PUTU32(root + 0x1C, 1);
483
        /* Truncate index root. */
484
        NTFS_PUTU64(root + 0x20, 0);
485
        NTFS_PUTU32(root + 0x28, 0x18);
486
        NTFS_PUTU32(root + 0x2C, 3);
487
        NTFS_PUTU64(root + 0x30, walk.newblock);
488
        error = ntfs_index_writeback(&walk, root, -1, 0x38);
489
 out:
490
        ntfs_free(root);
491
        ntfs_free(index);
492
        return error;
493
}
494
 
495
/* The entry has been found. Copy the result in the caller's buffer */
496
static int ntfs_copyresult(char *dest, char *source)
497
{
498
        int length = NTFS_GETU16(source + 8);
499
        ntfs_memcpy(dest, source, length);
500
        return 1;
501
}
502
 
503
/* Use $UpCase some day. */
504
static inline unsigned short ntfs_my_toupper(ntfs_volume *vol, ntfs_u16 x)
505
{
506
        /* We should read any pending rest of $UpCase here. */
507
        if (x >= vol->upcase_length)
508
                return x;
509
        return vol->upcase[x];
510
}
511
 
512
/* Everything passed in walk and entry. */
513
static int ntfs_my_strcmp(ntfs_iterate_s *walk, const unsigned char *entry)
514
{
515
        int lu = *(entry + 0x50);
516
        int i;
517
 
518
        ntfs_u16* name = (ntfs_u16*)(entry + 0x52);
519
        ntfs_volume *vol = walk->dir->vol;
520
        for (i = 0; i < lu && i < walk->namelen; i++)
521
                if (ntfs_my_toupper(vol, NTFS_GETU16(name + i)) !=
522
                             ntfs_my_toupper(vol, NTFS_GETU16(walk->name + i)))
523
                        break;
524
        if (i == lu && i == walk->namelen)
525
                return 0;
526
        if (i == lu)
527
                return 1;
528
        if (i == walk->namelen)
529
                return -1;
530
        if (ntfs_my_toupper(vol, NTFS_GETU16(name + i)) <
531
                            ntfs_my_toupper(vol, NTFS_GETU16(walk->name + i)))
532
                return 1;
533
        return -1;
534
}
535
 
536
/* Necessary forward declaration. */
537
static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry);
538
 
539
/* Parse a block of entries. Load the block, fix it up, and iterate over the
540
 * entries. The block is given as virtual cluster number. */
541
static int ntfs_getdir_record(ntfs_iterate_s *walk, int block)
542
{
543
        int length = walk->dir->u.index.recordsize;
544
        char *record = (char*)ntfs_malloc(length);
545
        char *offset;
546
        int retval,error;
547
        int oldblock;
548
        ntfs_io io;
549
 
550
        if (!record)
551
                return -ENOMEM;
552
        io.fn_put = ntfs_put;
553
        io.param = record;
554
        io.size = length;
555
        /* Read the block from the index allocation attribute. */
556
        error = ntfs_read_attr(walk->dir, walk->dir->vol->at_index_allocation,
557
                I30, (__s64)block << walk->dir->vol->cluster_size_bits, &io);
558
        if (error || io.size != length) {
559
                ntfs_error("read failed\n");
560
                ntfs_free(record);
561
                return 0;
562
        }
563
        if (!ntfs_check_index_record(walk->dir, record)) {
564
                ntfs_error("%x is not an index record\n", block);
565
                ntfs_free(record);
566
                return 0;
567
        }
568
        offset = record + NTFS_GETU16(record + 0x18) + 0x18;
569
        oldblock = walk->block;
570
        walk->block = block;
571
        retval = ntfs_getdir_iterate(walk, record, offset);
572
        walk->block = oldblock;
573
        ntfs_free(record);
574
        return retval;
575
}
576
 
577
/* Go down to the next block of entries. These collate before the current
578
 * entry. */
579
static int ntfs_descend(ntfs_iterate_s *walk, ntfs_u8 *start, ntfs_u8 *entry)
580
{
581
        int length = NTFS_GETU16(entry + 8);
582
        int nextblock = NTFS_GETU32(entry + length - 8);
583
        int error;
584
 
585
        if (!ntfs_entry_has_subnodes(entry)) {
586
                ntfs_error("illegal ntfs_descend call\n");
587
                return 0;
588
        }
589
        error = ntfs_getdir_record(walk, nextblock);
590
        if (!error && walk->type == DIR_INSERT &&
591
            (walk->u.flags & ITERATE_SPLIT_DONE)) {
592
                /* Split has occurred. Adjust entry, insert new_entry. */
593
                NTFS_PUTU32(entry + length - 8, walk->newblock);
594
                /* Reset flags, as the current block might be split again. */
595
                walk->u.flags &= ~ITERATE_SPLIT_DONE;
596
                error = ntfs_dir_insert(walk, start, entry);
597
        }
598
        return error;
599
}
600
 
601
static int ntfs_getdir_iterate_byposition(ntfs_iterate_s *walk, char* start,
602
                                          char *entry)
603
{
604
        int retval = 0;
605
        int curpos = 0, destpos = 0;
606
        int length;
607
        if (walk->u.pos != 0) {
608
                if (ntfs_is_top(walk->u.pos))
609
                        return 0;
610
                destpos = ntfs_pop(&walk->u.pos);
611
        }
612
        while (1) {
613
                if (walk->u.pos == 0) {
614
                        if (ntfs_entry_has_subnodes(entry))
615
                                ntfs_descend(walk, start, entry);
616
                        else
617
                                walk->u.pos = ntfs_top();
618
                        if (ntfs_is_top(walk->u.pos) &&
619
                            !ntfs_entry_is_used(entry))
620
                                return 1;
621
                        walk->u.pos = ntfs_push(walk->u.pos, curpos);
622
                        return 1;
623
                }
624
                if (curpos == destpos) {
625
                        if (!ntfs_is_top(walk->u.pos) &&
626
                            ntfs_entry_has_subnodes(entry)) {
627
                                retval = ntfs_descend(walk, start, entry);
628
                                if (retval) {
629
                                        walk->u.pos = ntfs_push(walk->u.pos,
630
                                                                curpos);
631
                                        return retval;
632
                                }
633
                                if (!ntfs_entry_is_used(entry))
634
                                        return 0;
635
                                walk->u.pos = 0;
636
                        }
637
                        if (ntfs_entry_is_used(entry)) {
638
                                retval = ntfs_copyresult(walk->result, entry);
639
                                walk->u.pos = 0;
640
                        } else {
641
                                walk->u.pos = ntfs_top();
642
                                return 0;
643
                        }
644
                }
645
                curpos++;
646
                if (!ntfs_entry_is_used(entry))
647
                        break;
648
                length = NTFS_GETU16(entry + 8);
649
                if (!length) {
650
                        ntfs_error("infinite loop\n");
651
                        break;
652
                }
653
                entry += length;
654
        }
655
        return -1;
656
}
657
 
658
/* Iterate over a list of entries, either from an index block, or from the
659
 * index root.
660
 * If searching BY_POSITION, pop the top index from the position. If the
661
 * position stack is empty then, return the item at the index and set the
662
 * position to the next entry. If the position stack is not empty,
663
 * recursively proceed for subnodes. If the entry at the position is the
664
 * 'end of dir' entry, return 'not found' and the empty stack.
665
 * If searching BY_NAME, walk through the items until found or until
666
 * one item is collated after the requested item. In the former case, return
667
 * the result. In the latter case, recursively proceed to the subnodes.
668
 * If 'end of dir' is reached, the name is not in the directory */
669
static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry)
670
{
671
        int length;
672
        int cmp;
673
 
674
        if (walk->type == BY_POSITION)
675
                return ntfs_getdir_iterate_byposition(walk, start, entry);
676
        do {
677
                /* If the current entry is a real one, compare with the
678
                 * requested item. If the current entry is the last item, it
679
                 * is always larger than the requested item. */
680
                cmp = ntfs_entry_is_used(entry) ?
681
                                                ntfs_my_strcmp(walk,entry) : -1;
682
                switch (walk->type) {
683
                case BY_NAME:
684
                        switch (cmp) {
685
                        case -1:
686
                                return ntfs_entry_has_subnodes(entry) ?
687
                                        ntfs_descend(walk, start, entry) : 0;
688
                        case  0:
689
                                return ntfs_copyresult(walk->result, entry);
690
                        case  1:
691
                                break;
692
                        }
693
                        break;
694
                case DIR_INSERT:
695
                        switch (cmp) {
696
                        case -1:
697
                                return ntfs_entry_has_subnodes(entry) ?
698
                                        ntfs_descend(walk, start, entry) :
699
                                        ntfs_dir_insert(walk, start, entry);
700
                        case  0:
701
                                return -EEXIST;
702
                        case  1:
703
                                break;
704
                        }
705
                        break;
706
                default:
707
                        ntfs_error("TODO\n"); /* FIXME: ? */
708
                }
709
                if (!ntfs_entry_is_used(entry))
710
                        break;
711
                length = NTFS_GETU16(entry + 8);
712
                if (!length) {
713
                        ntfs_error("infinite loop\n");
714
                        break;
715
                }
716
                entry += length;
717
        } while (1);
718
        return 0;
719
}
720
 
721
/*  Tree walking is done using position numbers. The following numbers have a
722
 *  special meaning:
723
 *       0   start (.)
724
 *      -1   no more entries
725
 *      -2   ..
726
 *  All other numbers encode sequences of indices. The sequence a, b, c is
727
 *  encoded as <stop><c><b><a>, where <foo> is the encoding of foo. The
728
 *  first few integers are encoded as follows:
729
 *      0:    0000    1:    0010    2:    0100    3:    0110
730
 *      4:    1000    5:    1010    6:    1100 stop:    1110
731
 *      7:  000001    8:  000101    9:  001001   10:  001101
732
 *  The least significant bits give the width of this encoding, the other bits
733
 *  encode the value, starting from the first value of the interval.
734
 *   tag     width  first value  last value
735
 *   0       3      0            6
736
 *   01      4      7            22
737
 *   011     5      23           54
738
 *   0111    6      55           119
739
 *   More values are hopefully not needed, as the file position has currently
740
 *   64 bits in total. */
741
 
742
/* Find an entry in the directory. Return 0 if not found, otherwise copy the
743
 * entry to the result buffer. */
744
int ntfs_getdir(ntfs_iterate_s *walk)
745
{
746
        int length = walk->dir->vol->mft_record_size;
747
        int retval, error;
748
        /* Start at the index root. */
749
        char *root = ntfs_malloc(length);
750
        ntfs_io io;
751
 
752
        if (!root)
753
                return -ENOMEM;
754
        io.fn_put = ntfs_put;
755
        io.param = root;
756
        io.size = length;
757
        error = ntfs_read_attr(walk->dir, walk->dir->vol->at_index_root, I30,
758
                               0, &io);
759
        if (error) {
760
                ntfs_error("Not a directory\n");
761
                return 0;
762
        }
763
        walk->block = -1;
764
        /* FIXME: Move these to walk. */
765
        walk->dir->u.index.recordsize = NTFS_GETU32(root + 0x8);
766
        walk->dir->u.index.clusters_per_record = NTFS_GETU32(root + 0xC);
767
        /* FIXME: Consistency check. */
768
        /* Skip header. */
769
        retval = ntfs_getdir_iterate(walk, root, root + 0x20);
770
        ntfs_free(root);
771
        return retval;
772
}
773
 
774
/* Find an entry in the directory by its position stack. Iteration starts
775
 * if the stack is 0, in which case the position is set to the first item
776
 * in the directory. If the position is nonzero, return the item at the
777
 * position and change the position to the next item. The position is -1
778
 * if there are no more items. */
779
int ntfs_getdir_byposition(ntfs_iterate_s *walk)
780
{
781
        walk->type = BY_POSITION;
782
        return ntfs_getdir(walk);
783
}
784
 
785
/* Find an entry in the directory by its name. Return 0 if not found. */
786
int ntfs_getdir_byname(ntfs_iterate_s *walk)
787
{
788
        walk->type = BY_NAME;
789
        return ntfs_getdir(walk);
790
}
791
 
792
int ntfs_getdir_unsorted(ntfs_inode *ino, u32 *p_high, u32 *p_low,
793
                int (*cb)(ntfs_u8 *, void *), void *param)
794
{
795
        s64 ib_ofs;
796
        char *buf = 0, *entry = 0;
797
        ntfs_attribute *attr;
798
        ntfs_volume *vol;
799
        int byte, bit, err = 0;
800
        u32 start, finish, ibs, max_size;
801
        ntfs_io io;
802
        u8 ibs_bits;
803
 
804
        if (!ino) {
805
                ntfs_error("%s(): No inode! Returning -EINVAL.\n",__FUNCTION__);
806
                return -EINVAL;
807
        }
808
        vol = ino->vol;
809
        if (!vol) {
810
                ntfs_error("%s(): Inode 0x%lx has no volume. Returning "
811
                            "-EINVAL.\n", __FUNCTION__, ino->i_number);
812
                return -EINVAL;
813
        }
814
        ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 1: Entering for inode 0x%lx, "
815
                        "p_high = 0x%x, p_low = 0x%x.\n", __FUNCTION__,
816
                        ino->i_number, *p_high, *p_low);
817
        if (!*p_high) {
818
                /* We are still in the index root. */
819
                buf = ntfs_malloc(io.size = vol->mft_record_size);
820
                if (!buf)
821
                        return -ENOMEM;
822
                io.fn_put = ntfs_put;
823
                io.param = buf;
824
                err = ntfs_read_attr(ino, vol->at_index_root, I30, 0, &io);
825
                if (err || !io.size)
826
                        goto read_err_ret;
827
                ino->u.index.recordsize = ibs = NTFS_GETU32(buf + 0x8);
828
                ino->u.index.clusters_per_record = NTFS_GETU32(buf + 0xC);
829
                entry = buf + 0x20;
830
                ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 2: In index root.\n",
831
                                __FUNCTION__);
832
                ibs_bits = ffs(ibs) - 1;
833
                /* Compensate for faked "." and "..". */
834
                start = 2;
835
        } else { /* We are in an index record. */
836
                io.size = ibs = ino->u.index.recordsize;
837
                buf = ntfs_malloc(ibs);
838
                if (!buf)
839
                        return -ENOMEM;
840
                ibs_bits = ffs(ibs) - 1;
841
                io.fn_put = ntfs_put;
842
                io.param = buf;
843
                /*
844
                 * 0 is index root, index allocation starts at 1 and works in
845
                 * units of index block size (ibs).
846
                 */
847
                ib_ofs = (s64)(*p_high - 1) << ibs_bits;
848
                err = ntfs_read_attr(ino, vol->at_index_allocation, I30, ib_ofs,
849
                                &io);
850
                if (err || io.size != ibs)
851
                        goto read_err_ret;
852
                if (!ntfs_check_index_record(ino, buf)) {
853
                        ntfs_error("%s(): Index block 0x%x is not an index "
854
                                        "record. Returning -ENOTDIR.\n",
855
                                         __FUNCTION__, *p_high - 1);
856
                        ntfs_free(buf);
857
                        return -ENOTDIR;
858
                }
859
                entry = buf + 0x18 + NTFS_GETU16(buf + 0x18);
860
                ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 3: In index "
861
                                "allocation.\n", __FUNCTION__);
862
                start = 0;
863
        }
864
        /* Process the entries. */
865
        finish = *p_low;
866
        for (; entry < (buf + ibs) && ntfs_entry_is_used(entry);
867
                        entry += NTFS_GETU16(entry + 8)) {
868
                if (start < finish) {
869
                        /* Skip entries that were already processed. */
870
                        ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 4: Skipping "
871
                                        "already processed entry p_high 0x%x, "
872
                                        "p_low 0x%x.\n", __FUNCTION__, *p_high,
873
                                        start);
874
                        start++;
875
                        continue;
876
                }
877
                ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 5: Processing entry "
878
                                "p_high 0x%x, p_low 0x%x.\n", __FUNCTION__,
879
                                *p_high, *p_low);
880
                if ((err = cb(entry, param))) {
881
                        /* filldir signalled us to stop. */
882
                        ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 6: cb returned "
883
                                        "%i, returning 0, p_high 0x%x, "
884
                                        "p_low 0x%x.\n", __FUNCTION__, err,
885
                                        *p_high, *p_low);
886
                        ntfs_free(buf);
887
                        return 0;
888
                }
889
                ++*p_low;
890
        }
891
        ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 7: After processing entries, "
892
                        "p_high 0x%x, p_low 0x%x.\n", __FUNCTION__, *p_high,
893
                        *p_low);
894
        /* We have to locate the next record. */
895
        ntfs_free(buf);
896
        buf = 0;
897
        *p_low = 0;
898
        attr = ntfs_find_attr(ino, vol->at_bitmap, I30);
899
        if (!attr) {
900
                /* Directory does not have index bitmap and index allocation. */
901
                *p_high = 0x7fff;
902
                ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 8: No index allocation. "
903
                                "Returning 0, p_high 0x7fff, p_low 0x0.\n",
904
                                __FUNCTION__);
905
                return 0;
906
        }
907
        max_size = attr->size;
908
        if (max_size > 0x7fff >> 3) {
909
                ntfs_error("%s(): Directory too large. Visible "
910
                                "length is truncated.\n", __FUNCTION__);
911
                max_size = 0x7fff >> 3;
912
        }
913
        buf = ntfs_malloc(max_size);
914
        if (!buf)
915
                return -ENOMEM;
916
        io.param = buf;
917
        io.size = max_size;
918
        err = ntfs_read_attr(ino, vol->at_bitmap, I30, 0, &io);
919
        if (err || io.size != max_size)
920
                goto read_err_ret;
921
        attr = ntfs_find_attr(ino, vol->at_index_allocation, I30);
922
        if (!attr) {
923
                ntfs_free(buf);
924
                ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 9: Find attr failed. "
925
                                "Returning -EIO.\n", __FUNCTION__);
926
                return -EIO;
927
        }
928
        if (attr->resident) {
929
                ntfs_free(buf);
930
                ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 9.5: IA is resident. Not"
931
                                " allowed. Returning EINVAL.\n", __FUNCTION__);
932
                return -EINVAL;
933
        }
934
        /* Loop while going through non-allocated index records. */
935
        max_size <<= 3;
936
        while (1) {
937
                if (++*p_high >= 0x7fff) {
938
                        ntfs_error("%s(): Unsorted 10: Directory "
939
                                        "inode 0x%lx overflowed the maximum "
940
                                        "number of index allocation buffers "
941
                                        "the driver can cope with. Pretending "
942
                                        "to be at end of directory.\n",
943
                                        __FUNCTION__, ino->i_number);
944
                        goto fake_eod;
945
                }
946
                if (*p_high > max_size || (s64)*p_high << ibs_bits >
947
                                attr->initialized) {
948
fake_eod:
949
                        /* No more index records. */
950
                        *p_high = 0x7fff;
951
                        *p_low = 0;
952
                        ntfs_free(buf);
953
                        ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 10.5: No more "
954
                                        "index records. Returning 0, p_high "
955
                                        "0x7fff, p_low 0.\n", __FUNCTION__);
956
                        return 0;
957
                }
958
                byte = (ntfs_cluster_t)(*p_high - 1);
959
                bit = 1 << (byte & 7);
960
                byte >>= 3;
961
                if ((buf[byte] & bit))
962
                        break;
963
        };
964
        ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 11: Done. Returning 0, p_high "
965
                        "0x%x, p_low 0x%x.\n", __FUNCTION__, *p_high, *p_low);
966
        ntfs_free(buf);
967
        return 0;
968
read_err_ret:
969
        if (!err)
970
                err = -EIO;
971
        ntfs_error("%s(): Read failed. Returning error code %i.\n",
972
                        __FUNCTION__, err);
973
        ntfs_free(buf);
974
        return err;
975
}
976
 
977
int ntfs_dir_add(ntfs_inode *dir, ntfs_inode *new, ntfs_attribute *name)
978
{
979
        ntfs_iterate_s walk;
980
        int nsize, esize;
981
        ntfs_u8* entry, *ndata;
982
        int error;
983
 
984
        walk.type = DIR_INSERT;
985
        walk.dir = dir;
986
        walk.u.flags = 0;
987
        nsize = name->size;
988
        ndata = name->d.data;
989
        walk.name = (ntfs_u16*)(ndata + 0x42);
990
        walk.namelen = NTFS_GETU8(ndata + 0x40);
991
        walk.new_entry_size = esize = (nsize + 0x10 + 7) & ~7;
992
        walk.new_entry = entry = ntfs_malloc(esize);
993
        if (!entry)
994
                return -ENOMEM;
995
        NTFS_PUTINUM(entry, new);
996
        NTFS_PUTU16(entry + 0x8, esize); /* Size of entry. */
997
        NTFS_PUTU16(entry + 0xA, nsize); /* Size of original name attribute. */
998
        NTFS_PUTU16(entry + 0xC, 0);     /* Flags. */
999
        NTFS_PUTU16(entry + 0xE, 0);      /* Reserved. */
1000
        ntfs_memcpy(entry + 0x10, ndata, nsize);
1001
        ntfs_bzero(entry + 0x10 + nsize, esize - 0x10 - nsize);
1002
        error = ntfs_getdir(&walk);
1003
        if (walk.new_entry)
1004
                ntfs_free(walk.new_entry);
1005
        return error;
1006
}
1007
 
1008
#if 0
1009
int ntfs_dir_add1(ntfs_inode *dir, const char* name, int namelen,
1010
                  ntfs_inode *ino)
1011
{
1012
        ntfs_iterate_s walk;
1013
        int error;
1014
        int nsize;
1015
        char *entry;
1016
        ntfs_attribute *name_attr;
1017
        error = ntfs_decodeuni(dir->vol, name, namelen, &walk.name,
1018
                               &walk.namelen);
1019
        if (error)
1020
                return error;
1021
        /* FIXME: Set flags. */
1022
        walk.type = DIR_INSERT;
1023
        walk.dir = dir;
1024
        /* walk.new = ino; */
1025
        /* Prepare new entry. */
1026
        /* Round up to a multiple of 8. */
1027
        walk.new_entry_size = nsize = ((0x52 + 2 * walk.namelen + 7) / 8) * 8;
1028
        walk.new_entry = entry = ntfs_malloc(nsize);
1029
        if (!entry)
1030
                return -ENOMEM;
1031
        ntfs_bzero(entry, nsize);
1032
        NTFS_PUTINUM(entry, ino);
1033
        NTFS_PUTU16(entry + 8, nsize);
1034
        NTFS_PUTU16(entry + 0xA, 0x42 + 2 * namelen); /* FIXME: Size of name
1035
                                                       * attribute. */
1036
        NTFS_PUTU32(entry + 0xC, 0); /* FIXME: D-F? */
1037
        name_attr = ntfs_find_attr(ino, vol->at_file_name, 0);
1038
                                                    /* FIXME: multiple names */
1039
        if (!name_attr || !name_attr->resident)
1040
                return -EIDRM;
1041
        /* Directory, file stamps, sizes, filename. */
1042
        ntfs_memcpy(entry + 0x10, name_attr->d.data, 0x42 + 2 * namelen);
1043
        error = ntfs_getdir(&walk);
1044
        ntfs_free(walk.name);
1045
        return error;
1046
}
1047
#endif
1048
 
1049
/* Fills out and creates an INDEX_ROOT attribute. */
1050
int ntfs_add_index_root(ntfs_inode *ino, int type)
1051
{
1052
        ntfs_attribute *da;
1053
        ntfs_u8 data[0x30]; /* 0x20 header, 0x10 last entry. */
1054
        char name[10];
1055
 
1056
        NTFS_PUTU32(data, type);
1057
        /* Collation rule. 1 == COLLATION_FILENAME */
1058
        NTFS_PUTU32(data + 4, 1);
1059
        NTFS_PUTU32(data + 8, ino->vol->index_record_size);
1060
        NTFS_PUTU32(data + 0xC, ino->vol->index_clusters_per_record);
1061
        /* Byte offset to first INDEX_ENTRY. */
1062
        NTFS_PUTU32(data + 0x10, 0x10);
1063
        /* Size of entries, including header. */
1064
        NTFS_PUTU32(data + 0x14, 0x20);
1065
        NTFS_PUTU32(data + 0x18, 0x20);
1066
        /* No index allocation, yet. */
1067
        NTFS_PUTU32(data + 0x1C, 0);
1068
        /* Add last entry. */
1069
        /* Indexed MFT record. */
1070
        NTFS_PUTU64(data + 0x20, 0);
1071
        /* Size of entry. */
1072
        NTFS_PUTU32(data + 0x28, 0x10);
1073
        /* Flags: Last entry, no child nodes. */
1074
        NTFS_PUTU32(data + 0x2C, 2);
1075
        /* Compute name. */
1076
        ntfs_indexname(name, type);
1077
        return ntfs_create_attr(ino, ino->vol->at_index_root, name,
1078
                                data, sizeof(data), &da);
1079
}
1080
 
1081
int ntfs_mkdir(ntfs_inode *dir, const char *name, int namelen,
1082
               ntfs_inode *result)
1083
{
1084
        int error;
1085
 
1086
        error = ntfs_alloc_inode(dir, result, name, namelen, NTFS_AFLAG_DIR);
1087
        if (error)
1088
                goto out;
1089
        error = ntfs_add_index_root(result, 0x30);
1090
        if (error)
1091
                goto out;
1092
        /* Set directory bit. */
1093
        result->attr[0x16] |= 2;
1094
        error = ntfs_update_inode(dir);
1095
        if (error)
1096
                goto out;
1097
        error = ntfs_update_inode(result);
1098
        if (error)
1099
                goto out;
1100
 out:
1101
        return error;
1102
}
1103
 

powered by: WebSVN 2.1.0

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