linux-old/fs/ntfs/dir.c
<<
>>
Prefs
   1/*
   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
  24static 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. */
  29int ntfs_check_index_record(ntfs_inode *ino, char *record)
  30{
  31        return ntfs_fixup_record(record, "INDX", ino->u.index.recordsize);
  32}
  33
  34static inline int ntfs_is_top(ntfs_u64 stack)
  35{
  36        return stack == 14;
  37}
  38
  39static 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
  67static inline unsigned int ntfs_top(void)
  68{
  69        return 14;
  70}
  71
  72static 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
  87static 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. */
  98static 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. */
 104static 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 */
 113static 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;
 150try_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;
 236err_unl_out:
 237        unlock_kernel();
 238err_fb_out:
 239        ntfs_free(bmap);
 240err_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. */
 246static 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
 291static 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
 385static 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. */
 424int 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 */
 496static 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. */
 504static 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. */
 513static 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. */
 537static 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. */
 541static 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. */
 579static 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
 601static 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 */
 669static 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. */
 744int 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. */
 779int 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. */
 786int ntfs_getdir_byname(ntfs_iterate_s *walk)
 787{
 788        walk->type = BY_NAME;
 789        return ntfs_getdir(walk);
 790}
 791
 792int 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) {
 948fake_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;
 968read_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
 977int 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
1009int 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. */
1050int 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
1081int 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
1104
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.