"Fossies" - the Fresh Open Source Software Archive

Member "ntfsprogs-1.12.1/ntfsprogs/ntfsrm.c" (7 Oct 2005, 110841 Bytes) of package /linux/misc/old/ntfsprogs-1.12.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ntfsrm.c" see the Fossies "Dox" file reference documentation.

    1 /**
    2  * ntfsrm - Part of the Linux-NTFS project.
    3  *
    4  * Copyright (c) 2005 Anton Altaparmakov
    5  * Copyright (c) 2004-2005 Richard Russon
    6  *
    7  * This utility will delete files from an NTFS volume.
    8  *
    9  * This program is free software; you can redistribute it and/or modify
   10  * it under the terms of the GNU General Public License as published by
   11  * the Free Software Foundation; either version 2 of the License, or
   12  * (at your option) any later version.
   13  *
   14  * This program is distributed in the hope that it will be useful,
   15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17  * GNU General Public License for more details.
   18  *
   19  * You should have received a copy of the GNU General Public License
   20  * along with this program (in the main directory of the Linux-NTFS
   21  * distribution in the file COPYING); if not, write to the Free Software
   22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   23  */
   24 
   25 #include "config.h"
   26 
   27 #ifdef HAVE_STDIO_H
   28 #include <stdio.h>
   29 #endif
   30 #ifdef HAVE_GETOPT_H
   31 #include <getopt.h>
   32 #endif
   33 #ifdef HAVE_STDLIB_H
   34 #include <stdlib.h>
   35 #endif
   36 #ifdef HAVE_STRING_H
   37 #include <string.h>
   38 #endif
   39 #ifdef HAVE_TIME_H
   40 #include <time.h>
   41 #endif
   42 
   43 #include "utils.h"
   44 #include "ntfsrm.h"
   45 #include "debug.h"
   46 #include "dir.h"
   47 #include "lcnalloc.h"
   48 #include "mft.h"
   49 #include "ntfstime.h"
   50 #include "version.h"
   51 
   52 static const char *EXEC_NAME = "ntfsrm";
   53 static struct options opts;
   54 static const char *space_line = "                                                                                ";
   55 
   56 GEN_PRINTF (Eprintf, stderr, NULL,          FALSE)
   57 GEN_PRINTF (Vprintf, stdout, &opts.verbose, TRUE)
   58 GEN_PRINTF (Qprintf, stdout, &opts.quiet,   FALSE)
   59 
   60 #define RM_WRITE 0
   61 
   62 /**
   63  * version - Print version information about the program
   64  *
   65  * Print a copyright statement and a brief description of the program.
   66  *
   67  * Return:  none
   68  */
   69 static void version (void)
   70 {
   71     printf("\n%s v%s (libntfs %s) - Delete files from an NTFS volume.\n\n",
   72             EXEC_NAME, VERSION, ntfs_libntfs_version());
   73     printf ("Copyright (c) 2004 Richard Russon\n");
   74     printf ("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
   75 }
   76 
   77 /**
   78  * usage - Print a list of the parameters to the program
   79  *
   80  * Print a list of the parameters and options for the program.
   81  *
   82  * Return:  none
   83  */
   84 static void usage (void)
   85 {
   86     printf ("\nUsage: %s [options] device file\n"
   87         "\n"
   88         "    -r  --recursive    Delete files in subdirectories\n"
   89         "    -i  --interactive  Ask before deleting files\n"
   90         //"    -I num  --inode num  Delete the file with this inode number\n"
   91         //"    -U      --unlink     Unlink the file, deleting all references \n"
   92         "\n"
   93         "    -D  --no-dirty     Do not mark volume dirty (require chkdsk)\n"
   94         "    -n  --no-action    Do not write to disk\n"
   95         "    -f  --force        Use less caution\n"
   96         "    -h  --help         Print this help\n"
   97         "    -q  --quiet        Less output\n"
   98         "    -V  --version      Version information\n"
   99         "    -v  --verbose      More output\n\n",
  100         EXEC_NAME);
  101     printf ("%s%s\n", ntfs_bugs, ntfs_home);
  102 }
  103 
  104 /**
  105  * parse_options - Read and validate the programs command line
  106  *
  107  * Read the command line, verify the syntax and parse the options.
  108  * This function is very long, but quite simple.
  109  *
  110  * Return:  1 Success
  111  *      0 Error, one or more problems
  112  */
  113 static int parse_options (int argc, char **argv)
  114 {
  115     static const char *sopt = "-Dfh?inqRrVv"; //"-Dfh?I:inqRrUVv";
  116     static const struct option lopt[] = {
  117         { "force",      no_argument,        NULL, 'f' },
  118         { "help",       no_argument,        NULL, 'h' },
  119         //{ "inode",        required_argument,  NULL, 'I' },
  120         { "interactive",    no_argument,        NULL, 'i' },
  121         { "no-action",      no_argument,        NULL, 'n' },
  122         { "no-dirty",       no_argument,        NULL, 'D' },
  123         { "quiet",      no_argument,        NULL, 'q' },
  124         { "recursive",      no_argument,        NULL, 'r' },
  125         //{ "unlink",       no_argument,        NULL, 'U' },
  126         { "verbose",        no_argument,        NULL, 'v' },
  127         { "version",        no_argument,        NULL, 'V' },
  128         { NULL,         0,          NULL, 0   }
  129     };
  130 
  131     char c = -1;
  132     int err  = 0;
  133     int ver  = 0;
  134     int help = 0;
  135 
  136     opterr = 0; /* We'll handle the errors, thank you. */
  137 
  138     while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != -1) {
  139         switch (c) {
  140         case 1: /* A non-option argument */
  141             if (!opts.device) {
  142                 opts.device = argv[optind-1];
  143             } else if (!opts.file) {
  144                 opts.file = argv[optind-1];
  145             } else {
  146                 opts.device = NULL;
  147                 opts.file   = NULL;
  148                 err++;
  149             }
  150             break;
  151         case 'D':
  152             opts.nodirty++;
  153             break;
  154         case 'f':
  155             opts.force++;
  156             break;
  157         case 'h':
  158         case '?':
  159             help++;
  160             break;
  161         case 'i':
  162             opts.interactive++;
  163             break;
  164         case 'n':
  165             opts.noaction++;
  166             break;
  167         case 'q':
  168             opts.quiet++;
  169             break;
  170         case 'R':
  171         case 'r':
  172             opts.recursive++;
  173             break;
  174         case 'V':
  175             ver++;
  176             break;
  177         case 'v':
  178             opts.verbose++;
  179             break;
  180         default:
  181             Eprintf ("Unknown option '%s'.\n", argv[optind-1]);
  182             err++;
  183             break;
  184         }
  185     }
  186 
  187     if (help || ver) {
  188         opts.quiet = 0;
  189     } else {
  190         if ((opts.device == NULL) ||
  191             (opts.file   == NULL)) {
  192             if (argc > 1)
  193                 Eprintf ("You must specify one device and one file.\n");
  194             err++;
  195         }
  196 
  197         if (opts.quiet && opts.verbose) {
  198             Eprintf("You may not use --quiet and --verbose at the "
  199                     "same time.\n");
  200             err++;
  201         }
  202     }
  203 
  204     if (ver)
  205         version();
  206     if (help || err)
  207         usage();
  208 
  209     return (!err && !help && !ver);
  210 }
  211 
  212 
  213 /**
  214  * ntfs_name_print
  215  */
  216 static void ntfs_name_print (ntfschar *name, int name_len)
  217 {
  218     char *buffer = NULL;
  219 
  220     if (name_len) {
  221         ntfs_ucstombs (name, name_len, &buffer, 0);
  222         printf ("%s", buffer);
  223         free (buffer);
  224     } else {
  225         printf ("!");
  226     }
  227 }
  228 
  229 /**
  230  * ntfs_dir_print
  231  */
  232 static void ntfs_dir_print (struct ntfs_dir *dir, int indent)
  233 {
  234     int i;
  235     if (!dir)
  236         return;
  237 
  238     printf ("%.*s%p ", indent, space_line, dir);
  239     ntfs_name_print (dir->name, dir->name_len);
  240     printf ("\n");
  241 
  242     for (i = 0; i < dir->child_count; i++) {
  243         ntfs_dir_print (dir->children[i], indent + 4);
  244     }
  245 
  246 }
  247 
  248 /**
  249  * ntfs_dt_print
  250  */
  251 static void ntfs_dt_print (struct ntfs_dt *dt, int indent)
  252 {
  253     int i;
  254 
  255     if (!dt)
  256         return;
  257 
  258     printf ("%.*s%p (%d)\n", indent, space_line, dt, dt->child_count);
  259 
  260     for (i = 0; i < dt->child_count; i++) {
  261         ntfs_dt_print (dt->sub_nodes[i], indent + 4);
  262     }
  263 }
  264 
  265 
  266 /**
  267  * ntfs_bmp_rollback
  268  */
  269 static int ntfs_bmp_rollback (struct ntfs_bmp *bmp)
  270 {
  271     int i;
  272 
  273     if ((!bmp) || (bmp->count == 0))
  274         return 0;
  275 
  276     for (i = 0; i < bmp->count; i++)
  277         free (bmp->data[i]);
  278 
  279     free (bmp->data);
  280     free (bmp->data_vcn);
  281     bmp->data = NULL;
  282     bmp->data_vcn = NULL;
  283     bmp->count = 0;
  284 
  285     return 0;
  286 }
  287 
  288 /**
  289  * ntfs_bmp_commit
  290  */
  291 static int ntfs_bmp_commit (struct ntfs_bmp *bmp)
  292 {
  293     int i;
  294     u32 cs;
  295 #ifdef RM_WRITE
  296     u32 ws; // write size
  297 #endif
  298 
  299     if (!bmp)
  300         return 0;
  301     if (bmp->count == 0)
  302         return 0;
  303 
  304 #if 0
  305     printf ("attr = 0x%02X\n", bmp->attr->type);
  306     printf ("resident = %d\n", !NAttrNonResident (bmp->attr));
  307     printf ("\ta size = %lld\n", bmp->attr->allocated_size);
  308     printf ("\td size = %lld\n", bmp->attr->data_size);
  309     printf ("\ti size = %lld\n", bmp->attr->initialized_size);
  310 #endif
  311 
  312     printf ("commit bmp inode %lld, 0x%02X (%sresident)\n", bmp->attr->ni->mft_no, bmp->attr->type, NAttrNonResident (bmp->attr) ? "non-" : "");
  313 
  314     if (NAttrNonResident (bmp->attr)) {
  315         cs = bmp->vol->cluster_size;
  316 
  317         // non-resident
  318         for (i = 0; i < bmp->count; i++) {
  319 #ifdef RM_WRITE
  320             if (((bmp->data_vcn[i]+1) * cs) < bmp->attr->data_size)
  321                 ws = cs;
  322             else
  323                 ws = bmp->attr->data_size & (cs - 1);
  324             //printf ("writing %d bytes\n", ws);
  325             ntfs_attr_pwrite (bmp->attr, bmp->data_vcn[i] * cs, ws, bmp->data[i]); // XXX retval
  326 #endif
  327             printf (RED "\tntfs_attr_pwrite (vcn %lld)\n" END, bmp->data_vcn[i]);
  328         }
  329     } else {
  330         // resident
  331 #ifdef RM_WRITE
  332         ntfs_attr_pwrite (bmp->attr, bmp->data_vcn[0], bmp->attr->data_size, bmp->data[0]); // XXX retval
  333 #endif
  334         printf (RED "\tntfs_attr_pwrite resident (%lld)\n" END, bmp->attr->data_size);
  335     }
  336 
  337     ntfs_bmp_rollback (bmp);
  338 
  339     return 0;
  340 }
  341 
  342 /**
  343  * ntfs_bmp_free
  344  */
  345 static void ntfs_bmp_free (struct ntfs_bmp *bmp)
  346 {
  347     if (!bmp)
  348         return;
  349 
  350     ntfs_bmp_rollback (bmp);
  351 
  352     ntfs_attr_close (bmp->attr);
  353 
  354     free (bmp);
  355 }
  356 
  357 /**
  358  * ntfs_bmp_create
  359  */
  360 static struct ntfs_bmp * ntfs_bmp_create (ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len)
  361 {
  362     struct ntfs_bmp *bmp;
  363     ntfs_attr *attr;
  364 
  365     if (!inode)
  366         return NULL;
  367 
  368     attr = ntfs_attr_open (inode, type, name, name_len);
  369     if (!attr)
  370         return NULL;
  371 
  372     bmp = calloc (1, sizeof (*bmp));
  373     if (!bmp) {
  374         ntfs_attr_close (attr);
  375         return NULL;
  376     }
  377 
  378     bmp->vol       = inode->vol;
  379     bmp->attr      = attr;
  380     bmp->data      = NULL;
  381     bmp->data_vcn  = NULL;
  382     bmp->count     = 0;
  383 
  384     return bmp;
  385 }
  386 
  387 /**
  388  * ntfs_bmp_add_data
  389  */
  390 static int ntfs_bmp_add_data (struct ntfs_bmp *bmp, VCN vcn, u8 *data)
  391 {
  392     int i = 0;
  393     int old;
  394     int new;
  395 
  396     if (!bmp || !data)
  397         return -1;
  398 
  399     old = ROUND_UP (bmp->count, 16);
  400     bmp->count++;
  401     new = ROUND_UP (bmp->count, 16);
  402 
  403     if (old != new) {
  404         bmp->data     = realloc (bmp->data,      new * sizeof (*bmp->data));
  405         bmp->data_vcn = realloc (bmp->data_vcn , new * sizeof (*bmp->data_vcn));
  406     }
  407 
  408     for (i = 0; i < bmp->count-1; i++)
  409         if (bmp->data_vcn[i] > vcn)
  410             break;
  411 
  412     if ((bmp->count-i) > 0) {
  413         memmove (&bmp->data[i+1],     &bmp->data[i],     (bmp->count-i) * sizeof (*bmp->data));
  414         memmove (&bmp->data_vcn[i+1], &bmp->data_vcn[i], (bmp->count-i) * sizeof (*bmp->data_vcn));
  415     }
  416 
  417     bmp->data[i]     = data;
  418     bmp->data_vcn[i] = vcn;
  419 
  420     return bmp->count;
  421 }
  422 
  423 /**
  424  * ntfs_bmp_get_data
  425  */
  426 static u8 * ntfs_bmp_get_data (struct ntfs_bmp *bmp, VCN vcn)
  427 {
  428     u8 *buffer;
  429     int i;
  430     int cs;
  431     int cb;
  432 
  433     if (!bmp)
  434         return NULL;
  435 
  436     cs = bmp->vol->cluster_size;
  437     cb = bmp->vol->cluster_size_bits;
  438 
  439     // XXX range check against vol,attr
  440     // never compressed, so data = init
  441 
  442     vcn >>= (cb + 3);   // convert to bitmap clusters
  443 
  444     for (i = 0; i < bmp->count; i++) {
  445         if (vcn == bmp->data_vcn[i]) {
  446             //printf ("reusing bitmap cluster %lld\n", vcn);
  447             return bmp->data[i];
  448         }
  449     }
  450 
  451     buffer = calloc (1, cs);    // XXX could be smaller if attr size < cluster size
  452     if (!buffer)
  453         return NULL;
  454 
  455     //printf ("loading from bitmap cluster %lld\n", vcn);
  456     //printf ("loading from bitmap byte    %lld\n", vcn<<cb);
  457     if (ntfs_attr_pread (bmp->attr, vcn<<cb, cs, buffer) < 0) {
  458         free (buffer);
  459         return NULL;
  460     }
  461 
  462     ntfs_bmp_add_data (bmp, vcn, buffer);   // XXX retval
  463     return buffer;
  464 }
  465 
  466 /**
  467  * ntfs_bmp_set_range
  468  */
  469 static int ntfs_bmp_set_range (struct ntfs_bmp *bmp, VCN vcn, s64 length, int value)
  470 {
  471     // shouldn't all the vcns be lcns?
  472     s64 i;
  473     u8 *buffer;
  474     int csib;           // cluster size in bits
  475 
  476     int block_start, block_finish;  // rename to c[sf]  (rename to clust_)
  477     int vcn_start, vcn_finish;  // rename to v[sf]
  478     int byte_start, byte_finish;    // rename to b[sf]
  479     u8 mask_start, mask_finish; // rename to m[sf]
  480 
  481     s64 a,b;
  482 
  483     if (!bmp)
  484         return -1;
  485 
  486     if (value)
  487         value = 0xFF;
  488 
  489     csib = bmp->vol->cluster_size << 3;
  490 
  491     vcn_start  = vcn;
  492     vcn_finish = vcn + length - 1;
  493 
  494     //printf ("vcn_start = %d, vcn_finish = %d\n", vcn_start, vcn_finish);
  495     a = ROUND_DOWN (vcn_start,  csib);
  496     b = ROUND_DOWN (vcn_finish, csib) + 1;
  497 
  498     //printf ("a = %lld, b = %lld\n", a, b);
  499 
  500     for (i = a; i < b; i += csib) {
  501         //printf ("ntfs_bmp_get_data %lld\n", i);
  502         buffer = ntfs_bmp_get_data (bmp, i);
  503         if (!buffer)
  504             return -1;
  505 
  506         block_start  = i;
  507         block_finish = block_start + csib - 1;
  508 
  509         mask_start  = (0xFF << (vcn_start & 7));
  510         mask_finish = (0xFF >> (7 - (vcn_finish & 7)));
  511 
  512         if ((vcn_start >= block_start) && (vcn_start <= block_finish)) {
  513             byte_start = (vcn_start - block_start) >> 3;
  514         } else {
  515             byte_start = 0;
  516             mask_start = 0xFF;
  517         }
  518 
  519         if ((vcn_finish >= block_start) && (vcn_finish <= block_finish)) {
  520             byte_finish = (vcn_finish - block_start) >> 3;
  521         } else {
  522             byte_finish = bmp->vol->cluster_size - 1;
  523             mask_finish = 0xFF;
  524         }
  525 
  526         if ((byte_finish - byte_start) > 1) {
  527             memset (buffer+byte_start+1, value, byte_finish-byte_start-1);
  528         } else if (byte_finish == byte_start) {
  529             mask_start &= mask_finish;
  530             mask_finish = 0x00;
  531         }
  532 
  533         if (value) {
  534             buffer[byte_start]  |= mask_start;
  535             buffer[byte_finish] |= mask_finish;
  536         } else {
  537             buffer[byte_start]  &= (~mask_start);
  538             buffer[byte_finish] &= (~mask_finish);
  539         }
  540     }
  541 
  542 #if 1
  543     printf (GREEN "Modified: inode %lld, ", bmp->attr->ni->mft_no);
  544     switch (bmp->attr->type) {
  545         case AT_BITMAP: printf ("$BITMAP"); break;
  546         case AT_DATA:   printf ("$DATA");   break;
  547         default:                break;
  548     }
  549     printf (" vcn %lld-%lld\n" END, vcn>>12, (vcn+length-1)>>12);
  550 #endif
  551     return 1;
  552 }
  553 
  554 /**
  555  * ntfs_bmp_find_last_set
  556  */
  557 static s64 ntfs_bmp_find_last_set (struct ntfs_bmp *bmp)
  558 {
  559     s64 clust_count;
  560     s64 byte_count;
  561     s64 clust;
  562     int byte;
  563     int bit;
  564     int note;
  565     u8 *buffer;
  566 
  567     if (!bmp)
  568         return -2;
  569 
  570     // find byte size of bmp
  571     // find cluster size of bmp
  572 
  573     byte_count = bmp->attr->data_size;
  574     clust_count = ROUND_UP (byte_count, bmp->vol->cluster_size) >> bmp->vol->cluster_size_bits;
  575 
  576     //printf ("bitmap = %lld bytes\n", byte_count);
  577     //printf ("bitmap = %lld buffers\n", clust_count);
  578 
  579     // for each cluster backwards
  580     for (clust = clust_count-1; clust >= 0; clust--) {
  581         //printf ("cluster %lld\n", clust);
  582         //printf ("get vcn %lld\n", clust << (bmp->vol->cluster_size_bits + 3));
  583         buffer = ntfs_bmp_get_data (bmp, clust << (bmp->vol->cluster_size_bits + 3));
  584         //utils_dump_mem (buffer, 0, 8, DM_NO_ASCII);
  585         if (!buffer)
  586             return -2;
  587         if ((clust == (clust_count-1) && ((byte_count % bmp->vol->cluster_size) != 0))) {
  588             byte = byte_count % bmp->vol->cluster_size;
  589         } else {
  590             byte = bmp->vol->cluster_size;
  591         }
  592         //printf ("start byte = %d\n", byte);
  593         // for each byte backward
  594         for (byte--; byte >= 0; byte--) {
  595             //printf ("\tbyte %d (%d)\n", byte, buffer[byte]);
  596             // for each bit shift up
  597             note = -1;
  598             for (bit = 7; bit >= 0; bit--) {
  599                 //printf ("\t\tbit %d (%d)\n", (1<<bit), buffer[byte] & (1<<bit));
  600                 if (buffer[byte] & (1<<bit)) {
  601                     // if set, keep note
  602                     note = bit;
  603                     break;
  604                 }
  605             }
  606             if (note >= 0) {
  607                 // if note, return value
  608                 //printf ("match %lld (c=%lld,b=%d,n=%d)\n", (((clust << bmp->vol->cluster_size_bits) + byte) << 3) + note, clust, byte, note);
  609                 return ((((clust << bmp->vol->cluster_size_bits) + byte) << 3) + note);
  610             }
  611         }
  612     }
  613 
  614     return -1;
  615 }
  616 
  617 /**
  618  * ntfs_bmp_find_space
  619  */
  620 static int ntfs_bmp_find_space (struct ntfs_bmp *bmp, LCN start, long size)
  621 {
  622     if (!bmp)
  623         return 0;
  624 
  625     start = 0;
  626     size = 0;
  627 
  628     /*
  629     bmp find space - uncached bmp's
  630         $Bitmap/$DATA   free space on volume
  631         dir/$BITMAP free index record
  632         $MFT/$BITMAP    free record in mft
  633     */
  634     return 0;
  635 }
  636 
  637 
  638 /**
  639  * ntfs_ie_free
  640  */
  641 static void ntfs_ie_free (INDEX_ENTRY *ie)
  642 {
  643     free (ie);
  644 }
  645 
  646 /**
  647  * ntfs_ie_create
  648  */
  649 static INDEX_ENTRY * ntfs_ie_create (void)
  650 {
  651     int length;
  652     INDEX_ENTRY *ie;
  653 
  654     length = 16;
  655     ie = calloc (1, length);
  656     if (!ie)
  657         return NULL;
  658 
  659     ie->indexed_file = 0;
  660     ie->length       = length;
  661     ie->key_length   = 0;
  662     ie->flags        = INDEX_ENTRY_END;
  663     ie->reserved     = 0;
  664     return ie;
  665 }
  666 
  667 /**
  668  * ntfs_ie_get_vcn
  669  */
  670 static VCN ntfs_ie_get_vcn (INDEX_ENTRY *ie)
  671 {
  672     if (!ie)
  673         return -1;
  674     if (!(ie->flags & INDEX_ENTRY_NODE))
  675         return -1;
  676 
  677     return *((VCN*) ((u8*) ie + ie->length - 8));
  678 }
  679 
  680 /**
  681  * ntfs_ie_copy
  682  */
  683 static INDEX_ENTRY * ntfs_ie_copy (INDEX_ENTRY *ie)
  684 {
  685     INDEX_ENTRY *copy = NULL;
  686 
  687     if (!ie)
  688         return NULL;
  689 
  690     copy = malloc (ie->length);
  691     if (!copy)
  692         return NULL;
  693     memcpy (copy, ie, ie->length);
  694 
  695     return copy;
  696 }
  697 
  698 /**
  699  * ntfs_ie_set_vcn
  700  */
  701 static INDEX_ENTRY * ntfs_ie_set_vcn (INDEX_ENTRY *ie, VCN vcn)
  702 {
  703     if (!ie)
  704         return 0;
  705 
  706     if (!(ie->flags & INDEX_ENTRY_NODE)) {
  707         ie->length += 8;
  708         ie = realloc (ie, ie->length);
  709         if (!ie)
  710             return NULL;
  711 
  712         ie->flags |= INDEX_ENTRY_NODE;
  713     }
  714 
  715     *((VCN*) ((u8*) ie + ie->length - 8)) = vcn;
  716     return ie;
  717 }
  718 
  719 /**
  720  * ntfs_ie_remove_vcn
  721  */
  722 static INDEX_ENTRY * ntfs_ie_remove_vcn (INDEX_ENTRY *ie)
  723 {
  724     if (!ie)
  725         return NULL;
  726     if (!(ie->flags & INDEX_ENTRY_NODE))
  727         return ie;
  728 
  729     ie->length -= 8;
  730     ie->flags &= ~INDEX_ENTRY_NODE;
  731     ie = realloc (ie, ie->length);
  732     return ie;
  733 }
  734 
  735 /**
  736  * ntfs_ie_set_name
  737  */
  738 static INDEX_ENTRY * ntfs_ie_set_name (INDEX_ENTRY *ie, ntfschar *name, int namelen, FILE_NAME_TYPE_FLAGS nametype)
  739 {
  740     FILE_NAME_ATTR *file;
  741     int need;
  742     BOOL wipe = FALSE;
  743     VCN vcn = 0;
  744 
  745     if (!ie || !name)
  746         return NULL;
  747 
  748     /*
  749      * INDEX_ENTRY
  750      *  MFT_REF indexed_file;
  751      *  u16 length;
  752      *  u16 key_length;
  753      *  INDEX_ENTRY_FLAGS flags;
  754      *  u16 reserved;
  755      *
  756      *  FILENAME
  757      *      MFT_REF parent_directory;
  758      *      s64 creation_time;
  759      *      s64 last_data_change_time;
  760      *      s64 last_mft_change_time;
  761      *      s64 last_access_time;
  762      *      s64 allocated_size;
  763      *      s64 data_size;
  764      *      FILE_ATTR_FLAGS file_attributes;
  765      *      u32 reserved;
  766      *      u8 file_name_length;
  767      *      FILE_NAME_TYPE_FLAGS file_name_type;
  768      *      ntfschar file_name[l];
  769      *      u8 reserved[n]
  770      *
  771      *  VCN vcn;
  772      */
  773 
  774     //printf ("key length = 0x%02X\n", ie->key_length);
  775     //printf ("new name length = %d\n", namelen);
  776     if (ie->key_length > 0) {
  777         file = &ie->key.file_name;
  778         //printf ("filename, length %d\n", file->file_name_length);
  779         need =  ATTR_SIZE (namelen * sizeof (ntfschar) + 2) -
  780             ATTR_SIZE (file->file_name_length * sizeof (ntfschar) + 2);
  781     } else {
  782         //printf ("no filename\n");
  783         need = ATTR_SIZE (sizeof (FILE_NAME_ATTR) + (namelen * sizeof (ntfschar)));
  784         wipe = TRUE;
  785     }
  786 
  787     //printf ("need 0x%02X bytes\n", need);
  788 
  789     if (need != 0) {
  790         if (ie->flags & INDEX_ENTRY_NODE)
  791             vcn = ntfs_ie_get_vcn (ie);
  792 
  793         ie->length += need;
  794         ie->key_length += need;
  795 
  796         //printf ("realloc 0x%02X\n", ie->length);
  797         ie = realloc (ie, ie->length);
  798         if (!ie)
  799             return NULL;
  800 
  801         if (ie->flags & INDEX_ENTRY_NODE)
  802             ie = ntfs_ie_set_vcn (ie, vcn);
  803 
  804         if (wipe)
  805             memset (&ie->key.file_name, 0, sizeof (FILE_NAME_ATTR));
  806         if (need > 0)
  807             memset ((u8*)ie + ie->length - need, 0, need);
  808     }
  809 
  810     memcpy (ie->key.file_name.file_name, name, namelen * sizeof (ntfschar));
  811 
  812     ie->key.file_name.file_name_length = namelen;
  813     ie->key.file_name.file_name_type = nametype;
  814     ie->flags &= ~INDEX_ENTRY_END;
  815 
  816     //printf ("ie->length     = 0x%02X\n", ie->length);
  817     //printf ("ie->key_length = 0x%02X\n", ie->key_length);
  818 
  819     return ie;
  820 }
  821 
  822 /**
  823  * ntfs_ie_remove_name
  824  */
  825 static INDEX_ENTRY * ntfs_ie_remove_name (INDEX_ENTRY *ie)
  826 {
  827     VCN vcn = 0;
  828 
  829     if (!ie)
  830         return NULL;
  831     if (ie->key_length == 0)
  832         return ie;
  833 
  834     if (ie->flags & INDEX_ENTRY_NODE)
  835         vcn = ntfs_ie_get_vcn (ie);
  836 
  837     ie->length -= ATTR_SIZE (ie->key_length);
  838     ie->key_length = 0;
  839     ie->flags |= INDEX_ENTRY_END;
  840 
  841     ie = realloc (ie, ie->length);
  842     if (!ie)
  843         return NULL;
  844 
  845     if (ie->flags & INDEX_ENTRY_NODE)
  846         ie = ntfs_ie_set_vcn (ie, vcn);
  847     return ie;
  848 }
  849 
  850 
  851 /**
  852  * ntfs_inode_close2
  853  */
  854 static int ntfs_inode_close2 (ntfs_inode *ni)
  855 {
  856     if (!ni)
  857         return 0;
  858 
  859     //printf (BOLD YELLOW "inode close %lld (%d)\n" END, ni->mft_no, ni->ref_count);
  860 
  861     ni->ref_count--;
  862     if (ni->ref_count > 0)
  863         return 0;
  864 
  865     // unlink
  866     //   ino->private_data
  867 
  868     // XXX temporary until we have commit/rollback
  869     NInoClearDirty(ni);
  870 
  871     return ntfs_inode_close (ni);
  872 }
  873 
  874 
  875 /**
  876  * ntfs_dt_free
  877  */
  878 static void ntfs_dt_free (struct ntfs_dt *dt)
  879 {
  880     int i;
  881 
  882     if (!dt)
  883         return;
  884 
  885     for (i = 0; i < dt->child_count; i++) {
  886         ntfs_dt_free (dt->sub_nodes[i]);
  887         ntfs_inode_close2 (dt->inodes[i]);
  888     }
  889 
  890     free (dt->sub_nodes);
  891     free (dt->children);
  892     free (dt->inodes);
  893     free (dt->data);    // XXX is this always ours?
  894     free (dt);
  895 }
  896 
  897 /**
  898  * ntfs_dt_rollback
  899  */
  900 static int ntfs_dt_rollback (struct ntfs_dt *dt)
  901 {
  902     int i;
  903 
  904     if (!dt)
  905         return 0;
  906     if (dt->child_count == 0)   // No children or nothing mapped
  907         return 0;
  908 
  909     if (dt->changed) {
  910         // We can't trust anything below us in the tree
  911         for (i = 0; i < dt->child_count; i++) {
  912             ntfs_dt_free (dt->sub_nodes[i]);
  913             ntfs_inode_close2 (dt->inodes[i]);
  914         }
  915 
  916         dt->child_count = 0;
  917 
  918         free (dt->data);
  919         free (dt->children);
  920         free (dt->sub_nodes);
  921         free (dt->inodes);
  922 
  923         dt->data = NULL;
  924         dt->children = NULL;
  925         dt->sub_nodes = NULL;
  926         dt->inodes = NULL;
  927     } else {
  928         // This node is OK, check the su-nodes
  929         for (i = 0; i < dt->child_count; i++) {
  930             if (ntfs_dt_rollback (dt->sub_nodes[i])) {
  931                 ntfs_inode_close2 (dt->inodes[i]);
  932                 // Child was changed so unmap it
  933                 dt->sub_nodes[i] = NULL;
  934                 dt->inodes[i] = NULL;
  935             }
  936         }
  937     }
  938 
  939     return (dt->child_count == 0);
  940 }
  941 
  942 /**
  943  * ntfs_dt_commit
  944  */
  945 static int ntfs_dt_commit (struct ntfs_dt *dt)
  946 {
  947     ntfs_volume *vol;
  948     ntfs_attr *attr;
  949     struct ntfs_dir *dir;
  950     int i;
  951     int size;
  952 
  953     if (!dt)
  954         return 0;
  955 
  956     dir = dt->dir;
  957     if (!dir)
  958         return -1;
  959 
  960     vol = dir->vol; // cluster size
  961 
  962     if (dt->changed) {
  963         if (dt->parent) {
  964             printf ("commit dt (alloc)\n");
  965             attr = dt->dir->ialloc;
  966             size = dt->dir->index_size;
  967             //utils_dump_mem (dt->data, 0, size, DM_DEFAULTS);
  968 #ifdef RM_WRITE
  969             ntfs_attr_mst_pwrite(attr, dt->vcn * vol->cluster_size, 1, size, dt->data); // XXX retval
  970 #endif
  971         } else {
  972             printf ("commit dt (root)\n");
  973             attr = dt->dir->iroot;
  974             size = dt->data_len;
  975             //utils_dump_mem (dt->data, 0, size, DM_DEFAULTS);
  976 #ifdef RM_WRITE
  977             ntfs_attr_pwrite(attr, 0, size, dt->data); // XXX retval
  978 #endif
  979         }
  980 
  981         printf (RED "\tntfs_attr_pwrite (vcn %lld)\n" END, dt->vcn);
  982 
  983         dt->changed = FALSE;
  984     }
  985 
  986     for (i = 0; i < dt->child_count; i++) {
  987         if ((dt->inodes[i]) && (NInoDirty (dt->inodes[i]))) {
  988             //utils_dump_mem (dt->inodes[i]->mrec, 0, vol->mft_record_size, DM_DEFAULTS);
  989 #ifdef RM_WRITE
  990             ntfs_inode_sync (dt->inodes[i]);
  991 #endif
  992             printf (RED "\tntfs_inode_sync %llu\n" END, dt->inodes[i]->mft_no);
  993         }
  994 
  995         if (ntfs_dt_commit (dt->sub_nodes[i]) < 0)
  996             return -1;
  997     }
  998 
  999     return 0;
 1000 }
 1001 
 1002 /**
 1003  * ntfs_dt_create_children2
 1004  */
 1005 static BOOL ntfs_dt_create_children2 (struct ntfs_dt *dt, int count)
 1006 {
 1007     // XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN)
 1008 
 1009     int old = (dt->child_count + 0x1e) & ~0x1f;
 1010     int new = (count           + 0x1f) & ~0x1f;
 1011 
 1012     if (old == new)
 1013         return TRUE;
 1014 
 1015     dt->children  = realloc (dt->children,  new * sizeof (*dt->children));
 1016     dt->sub_nodes = realloc (dt->sub_nodes, new * sizeof (*dt->sub_nodes));
 1017     dt->inodes    = realloc (dt->inodes,    new * sizeof (*dt->inodes));
 1018 
 1019     if (!dt->children || !dt->sub_nodes || !dt->inodes)
 1020         return FALSE;       // dt->child_count = -1 ?
 1021 
 1022     memset ((u8*)dt->children  + old, 0, (new - old) * sizeof (*dt->children));
 1023     memset ((u8*)dt->sub_nodes + old, 0, (new - old) * sizeof (*dt->sub_nodes));
 1024     memset ((u8*)dt->inodes    + old, 0, (new - old) * sizeof (*dt->inodes));
 1025 
 1026     return TRUE;
 1027 }
 1028 
 1029 /**
 1030  * ntfs_dt_resize_children3
 1031  */
 1032 static BOOL ntfs_dt_resize_children3 (struct ntfs_dt *dt, int new)
 1033 {
 1034     int old;
 1035 
 1036     // XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN)
 1037     // XXX assumption:  sizeof (*dt->children) == sizeof (*dt->sub_nodes) == sizeof (*dt->inodes)
 1038     // XXX put back blocking factor
 1039 
 1040     if (!dt)
 1041         return FALSE;
 1042 
 1043     old = dt->child_count;
 1044     if (old == new)
 1045         return TRUE;
 1046 
 1047     dt->child_count = new;
 1048 
 1049     old *= sizeof (*dt->children);
 1050     new *= sizeof (*dt->children);
 1051 
 1052     dt->children  = realloc (dt->children,  new);
 1053     dt->sub_nodes = realloc (dt->sub_nodes, new);
 1054     dt->inodes    = realloc (dt->inodes,    new);
 1055 
 1056     if (!dt->children || !dt->sub_nodes || !dt->inodes)
 1057         return FALSE;
 1058 
 1059     if (new > old) {
 1060         memset ((u8*)dt->children  + old, 0, (new - old));
 1061         memset ((u8*)dt->sub_nodes + old, 0, (new - old));
 1062         memset ((u8*)dt->inodes    + old, 0, (new - old));
 1063     }
 1064 
 1065     return TRUE;
 1066 }
 1067 
 1068 /**
 1069  * ntfs_dt_root_count
 1070  */
 1071 static int ntfs_dt_root_count (struct ntfs_dt *dt)
 1072 {
 1073     u8 *buffer = NULL;
 1074     u8 *ptr = NULL;
 1075     VCN vcn;
 1076     s64 size = 0;
 1077     char *name = NULL;
 1078 
 1079     INDEX_ROOT *root;
 1080     INDEX_HEADER *header;
 1081     INDEX_ENTRY *entry;
 1082 
 1083     if (!dt)
 1084         return -1;
 1085 
 1086     buffer = dt->data;
 1087     size   = dt->data_len;
 1088 
 1089     root = (INDEX_ROOT*) buffer;
 1090     if (root->type != AT_FILE_NAME)
 1091         return -1;
 1092 
 1093     header = (INDEX_HEADER*) (buffer + 0x10);
 1094     if (header->index_length > size)
 1095         return -1;
 1096 
 1097     dt->child_count = 0;
 1098     ptr = buffer + header->entries_offset + 0x10;
 1099 
 1100     while (ptr < (buffer + size)) {
 1101         entry = (INDEX_ENTRY*) ptr;
 1102 
 1103         ntfs_dt_resize_children3 (dt, dt->child_count + 1); // XXX retval
 1104 
 1105         if (entry->flags & INDEX_ENTRY_NODE) {
 1106             vcn = ntfs_ie_get_vcn ((INDEX_ENTRY*) ptr);
 1107             //printf ("VCN %lld\n", vcn);
 1108         }
 1109 
 1110         if (!(entry->flags & INDEX_ENTRY_END)) {
 1111             ntfs_ucstombs (entry->key.file_name.file_name, entry->key.file_name.file_name_length, &name, 0);
 1112             //printf ("\tinode %8lld %s\n", MREF (entry->indexed_file), name);
 1113             free (name);
 1114             name = NULL;
 1115         }
 1116 
 1117         //printf ("CC[%d] = %p\n", dt->child_count-1, entry);
 1118         dt->children[dt->child_count-1] = entry;
 1119 
 1120         ptr += entry->length;
 1121     }
 1122 
 1123     //printf ("count = %d\n\n", dt->child_count);
 1124 
 1125     return dt->child_count;
 1126 }
 1127 
 1128 /**
 1129  * ntfs_dt_alloc_count
 1130  */
 1131 static int ntfs_dt_alloc_count (struct ntfs_dt *dt)
 1132 {
 1133     u8 *buffer = NULL;
 1134     u8 *ptr = NULL;
 1135     VCN vcn;
 1136     s64 size = 0;
 1137     char *name = NULL;
 1138 
 1139     INDEX_BLOCK *block;
 1140     INDEX_ENTRY *entry;
 1141 
 1142     if (!dt)
 1143         return -1;
 1144 
 1145     buffer = dt->data;
 1146     size   = dt->data_len;
 1147 
 1148     //utils_dump_mem (buffer, 0, 128, DM_DEFAULTS);
 1149 
 1150     block = (INDEX_BLOCK*) buffer;
 1151     //printf ("INDX %lld\n", block->index_block_vcn);
 1152 
 1153     ptr = buffer + 0x18 + block->index.entries_offset;
 1154 
 1155     //printf ("block size %d\n", block->index.index_length);
 1156     dt->child_count = 0;
 1157     //printf ("start = 0x%02X, end = 0x%02X\n", 0x18 + block->index.entries_offset, 0x18 + block->index.index_length);
 1158     while (ptr < (buffer + 0x18 + block->index.index_length)) {
 1159         entry = (INDEX_ENTRY*) ptr;
 1160 
 1161         ntfs_dt_resize_children3 (dt, dt->child_count + 1); // XXX retval
 1162 
 1163         if (entry->flags & INDEX_ENTRY_NODE) {
 1164             vcn = ntfs_ie_get_vcn ((INDEX_ENTRY*) ptr);
 1165             //printf ("\tVCN %lld\n", vcn);
 1166         }
 1167 
 1168         dt->children[dt->child_count-1] = entry;
 1169 
 1170         if (entry->flags & INDEX_ENTRY_END) {
 1171             break;
 1172         } else {
 1173             ntfs_ucstombs (entry->key.file_name.file_name, entry->key.file_name.file_name_length, &name, 0);
 1174             //printf ("\tinode %8lld %s\n", MREF (entry->indexed_file), name);
 1175             free (name);
 1176             name = NULL;
 1177         }
 1178 
 1179         ptr += entry->length;
 1180     }
 1181     //printf ("count = %d\n", dt->child_count);
 1182 
 1183     return dt->child_count;
 1184 }
 1185 
 1186 /**
 1187  * ntfs_dt_initialise2
 1188  */
 1189 static int ntfs_dt_initialise2 (ntfs_volume *vol, struct ntfs_dt *dt)
 1190 {
 1191     INDEX_ALLOCATION *alloc;
 1192     INDEX_ENTRY *entry;
 1193 
 1194     if (!vol)
 1195         return 1;
 1196     if (!dt)
 1197         return 1;
 1198 
 1199     memset (dt->data, 0, dt->data_len);
 1200 
 1201     alloc = (INDEX_ALLOCATION*) dt->data;
 1202 
 1203     alloc->magic           = magic_INDX;
 1204     alloc->usa_ofs         = 0x28;
 1205     alloc->usa_count       = (dt->data_len >> vol->sector_size_bits) + 1;
 1206     alloc->lsn             = 0;
 1207     alloc->index_block_vcn = 0;
 1208 
 1209     alloc->index.entries_offset   = 0x28;
 1210     alloc->index.index_length     = 0x10 + 0x28;
 1211     alloc->index.allocated_size   = dt->data_len - 0x18;
 1212     alloc->index.flags            = 0;
 1213 
 1214     entry = (INDEX_ENTRY*) (dt->data + 0x40);
 1215 
 1216     entry->indexed_file = 0;
 1217     entry->length       = 0x10;
 1218     entry->key_length   = 0;
 1219     entry->flags        = INDEX_ENTRY_END;
 1220 
 1221     ntfs_dt_resize_children3 (dt, 1);       // XXX retval
 1222 
 1223     dt->children[0] = entry;
 1224 
 1225     return 0;
 1226 }
 1227 
 1228 /**
 1229  * ntfs_dt_create
 1230  */
 1231 static struct ntfs_dt * ntfs_dt_create (struct ntfs_dir *dir, struct ntfs_dt *parent, VCN vcn)
 1232 {
 1233     struct ntfs_dt *dt = NULL;
 1234     //int i;
 1235 
 1236     if (!dir)
 1237         return NULL;
 1238 
 1239     dt = calloc (1, sizeof (*dt));
 1240     if (!dt)
 1241         return NULL;
 1242 
 1243     dt->dir     = dir;
 1244     dt->parent  = parent;
 1245     dt->child_count = 0;
 1246     dt->children    = NULL;
 1247     dt->sub_nodes   = NULL;
 1248     dt->inodes  = NULL;
 1249     dt->vcn     = vcn;
 1250     dt->changed = FALSE;
 1251 
 1252     if (parent) {
 1253         //printf ("alloc a = %lld\n", dir->ialloc->allocated_size);
 1254         //printf ("alloc d = %lld\n", dir->ialloc->data_size);
 1255         //printf ("alloc i = %lld\n", dir->ialloc->initialized_size);
 1256         //printf ("vcn = %lld\n", vcn);
 1257 
 1258         dt->data_len = dt->dir->index_size;
 1259         //printf ("parent size = %d\n", dt->data_len);
 1260         dt->data     = malloc (dt->data_len);
 1261 
 1262         if (vcn >= 0) {
 1263             //printf ("%lld\n", ntfs_attr_mst_pread (dir->ialloc, vcn*512, 1, dt->data_len, dt->data));
 1264             ntfs_attr_mst_pread (dir->ialloc, vcn*512, 1, dt->data_len, dt->data);
 1265         } else {
 1266             ntfs_dt_initialise2 (dir->vol, dt);
 1267         }
 1268 
 1269         //utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS);
 1270         //printf ("\n");
 1271 
 1272         ntfs_dt_alloc_count (dt);
 1273 
 1274         dt->header = &((INDEX_BLOCK*)dt->data)->index;
 1275         //printf ("USA = %d\n", ((INDEX_BLOCK*)dt->data)->usa_count);
 1276 
 1277 #if 0
 1278         for (i = 0; i < dt->child_count; i++) {
 1279             INDEX_ENTRY *ie = dt->children[i];
 1280 
 1281             printf ("%d\n", ((u8*)ie) - dt->data);
 1282             if (ie->flags & INDEX_ENTRY_END)
 1283                 printf ("IE (%d)\n", ie->length);
 1284             else
 1285                 printf ("IE %lld (%d)\n", MREF (ie->key.file_name.parent_directory), ie->length);
 1286             utils_dump_mem (ie, 0, ie->length, DM_DEFAULTS);
 1287             printf ("\n");
 1288         }
 1289 #endif
 1290     } else {
 1291         //printf ("root a  = %lld\n", dir->iroot->allocated_size);
 1292         //printf ("root d  = %lld\n", dir->iroot->data_size);
 1293         //printf ("root i  = %lld\n", dir->iroot->initialized_size);
 1294 
 1295         dt->data_len = dir->iroot->allocated_size;
 1296         dt->data     = malloc (dt->data_len);
 1297         //printf ("%lld\n", ntfs_attr_pread (dir->iroot, 0, dt->data_len, dt->data));
 1298         ntfs_attr_pread (dir->iroot, 0, dt->data_len, dt->data);
 1299         //utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS);
 1300         //printf ("\n");
 1301 
 1302         ntfs_dt_root_count (dt);
 1303 
 1304         dt->header = &((INDEX_ROOT*)dt->data)->index;
 1305         //dt->data_len = ((INDEX_ROOT*)dt->data)->index_block_size;
 1306         //printf ("IBS = %d\n", ((INDEX_ROOT*)dt->data)->index_block_size);
 1307 
 1308 #if 0
 1309         for (i = 0; i < dt->child_count; i++) {
 1310             INDEX_ENTRY *ie = dt->children[i];
 1311 
 1312             printf ("%d\n", ((u8*)ie) - dt->data);
 1313             if (ie->flags & INDEX_ENTRY_END)
 1314                 printf ("IE (%d)\n", ie->length);
 1315             else
 1316                 printf ("IE %lld (%d)\n", MREF (ie->key.file_name.parent_directory), ie->length);
 1317             utils_dump_mem (ie, 0, ie->length, DM_DEFAULTS);
 1318             printf ("\n");
 1319         }
 1320 #endif
 1321     }
 1322     //printf ("index_header (%d,%d)\n", dt->header.index_length, dt->header.allocated_size);
 1323 
 1324     return dt;
 1325 }
 1326 
 1327 /**
 1328  * ntfs_dt_find
 1329  * find dt by name, return MFT_REF
 1330  * maps dt's as necessary
 1331  */
 1332 static MFT_REF ntfs_dt_find (struct ntfs_dt *dt, ntfschar *name, int name_len)
 1333 {
 1334     MFT_REF res = -1;
 1335     INDEX_ENTRY *ie;
 1336     struct ntfs_dt *sub;
 1337     VCN vcn;
 1338     int i;
 1339     int r;
 1340 
 1341     if (!dt || !name)
 1342         return -1;
 1343 
 1344     /*
 1345      * State            Children  Action
 1346      * -------------------------------------------
 1347      * collates after      -      keep searching
 1348      * match name          -      return MREF
 1349      * collates before     no     return -1
 1350      * collates before     yes    map & recurse
 1351      * end marker          no     return -1
 1352      * end marker          yes    map & recurse
 1353      */
 1354 
 1355     //printf ("child_count = %d\n", dt->child_count);
 1356     for (i = 0; i < dt->child_count; i++) {
 1357         ie = dt->children[i];
 1358 
 1359         if (ie->flags & INDEX_ENTRY_END) {
 1360             r = -1;
 1361         } else {
 1362             //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n");
 1363             r = ntfs_names_collate (name, name_len,
 1364                         ie->key.file_name.file_name,
 1365                         ie->key.file_name.file_name_length,
 1366                         2, IGNORE_CASE,
 1367                         dt->dir->vol->upcase,
 1368                         dt->dir->vol->upcase_len);
 1369         }
 1370 
 1371         //printf ("%d, %d\n", i, r);
 1372 
 1373         if (r == 1) {
 1374             //printf ("keep searching\n");
 1375             continue;
 1376         } else if (r == 0) {
 1377             res = MREF (ie->indexed_file);
 1378             //printf ("match %lld\n", res);
 1379         } else if (r == -1) {
 1380             if (ie->flags & INDEX_ENTRY_NODE) {
 1381                 //printf ("map & recurse\n");
 1382                 //printf ("sub %p\n", dt->sub_nodes);
 1383                 if (!dt->sub_nodes[i]) {
 1384                     vcn = ntfs_ie_get_vcn (ie);
 1385                     //printf ("vcn = %lld\n", vcn);
 1386                     sub = ntfs_dt_create (dt->dir, dt, vcn);
 1387                     dt->sub_nodes[i] = sub;
 1388                 }
 1389                 res = ntfs_dt_find (dt->sub_nodes[i], name, name_len);
 1390             } else {
 1391                 //printf ("ENOENT\n");
 1392             }
 1393         } else {
 1394             printf ("error collating name\n");
 1395         }
 1396         break;
 1397     }
 1398 
 1399     return res;
 1400 }
 1401 
 1402 /**
 1403  * ntfs_dt_find2
 1404  * find dt by name, returns dt and index
 1405  * maps dt's as necessary
 1406  */
 1407 static struct ntfs_dt * ntfs_dt_find2 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num)
 1408 {
 1409     struct ntfs_dt *res = NULL;
 1410     INDEX_ENTRY *ie;
 1411     VCN vcn;
 1412     int i;
 1413     int r;
 1414 
 1415     if (!dt || !name)
 1416         return NULL;
 1417 
 1418     // XXX default index_num to -1
 1419 
 1420     /*
 1421      * State            Children  Action
 1422      * -------------------------------------------
 1423      * collates after      -      keep searching
 1424      * match name          -      return MREF
 1425      * collates before     no     return -1
 1426      * collates before     yes    map & recurse
 1427      * end marker          no     return -1
 1428      * end marker          yes    map & recurse
 1429      */
 1430 
 1431     //printf ("child_count = %d\n", dt->child_count);
 1432     for (i = 0; i < dt->child_count; i++) {
 1433         ie = dt->children[i];
 1434 
 1435         if (ie->flags & INDEX_ENTRY_END) {
 1436             r = -1;
 1437         } else {
 1438             //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n");
 1439             r = ntfs_names_collate (name, name_len,
 1440                         ie->key.file_name.file_name,
 1441                         ie->key.file_name.file_name_length,
 1442                         2, IGNORE_CASE,
 1443                         dt->dir->vol->upcase,
 1444                         dt->dir->vol->upcase_len);
 1445         }
 1446 
 1447         //printf ("%d, %d\n", i, r);
 1448 
 1449         if (r == 1) {
 1450             //printf ("keep searching\n");
 1451             continue;
 1452         } else if (r == 0) {
 1453             res = dt;
 1454             //printf ("match %p\n", res);
 1455             if (index_num)
 1456                 *index_num = i;
 1457         } else if ((r == -1) && (ie->flags & INDEX_ENTRY_NODE)) {
 1458             //printf ("recurse\n");
 1459             if (!dt->sub_nodes[i]) {
 1460                 vcn = ntfs_ie_get_vcn (ie);
 1461                 //printf ("vcn = %lld\n", vcn);
 1462                 dt->sub_nodes[i] = ntfs_dt_create (dt->dir, dt, vcn);
 1463             }
 1464             res = ntfs_dt_find2 (dt->sub_nodes[i], name, name_len, index_num);
 1465         } else {
 1466             printf ("error collating name\n");
 1467         }
 1468         break;
 1469     }
 1470 
 1471     return res;
 1472 }
 1473 
 1474 /**
 1475  * ntfs_dt_find3
 1476  * find dt by name, returns dt and index
 1477  * does not map new dt's
 1478  */
 1479 static struct ntfs_dt * ntfs_dt_find3 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num)
 1480 {
 1481     struct ntfs_dt *res = NULL;
 1482     INDEX_ENTRY *ie;
 1483     int i;
 1484     int r;
 1485 
 1486     if (!dt || !name)
 1487         return NULL;
 1488 
 1489     //printf ("child_count = %d\n", dt->child_count);
 1490     for (i = 0; i < dt->child_count; i++) {
 1491         ie = dt->children[i];
 1492 
 1493         if (ie->flags & INDEX_ENTRY_END) {
 1494             r = -1;
 1495         } else {
 1496             //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n");
 1497             r = ntfs_names_collate (name, name_len,
 1498                         ie->key.file_name.file_name,
 1499                         ie->key.file_name.file_name_length,
 1500                         2, IGNORE_CASE,
 1501                         dt->dir->vol->upcase,
 1502                         dt->dir->vol->upcase_len);
 1503         }
 1504 
 1505         //printf ("%d, %d\n", i, r);
 1506 
 1507         if (r == 1) {
 1508             //printf ("keep searching\n");
 1509             continue;
 1510         } else if (r == 0) {
 1511             res = dt;
 1512             //printf ("match %p\n", res);
 1513             if (index_num)
 1514                 *index_num = i;
 1515         } else if (r == -1) {
 1516             if (ie->flags & INDEX_ENTRY_NODE) {
 1517                 //printf ("recurse\n");
 1518                 res = ntfs_dt_find3 (dt->sub_nodes[i], name, name_len, index_num);
 1519             } else {
 1520                 //printf ("no match\n");
 1521                 res = dt;
 1522                 if (index_num)
 1523                     *index_num = i;
 1524             }
 1525         } else {
 1526             printf ("error collating name\n");
 1527         }
 1528         break;
 1529     }
 1530 
 1531     return res;
 1532 }
 1533 
 1534 /**
 1535  * ntfs_dt_find4
 1536  * find successor to specified name, returns dt and index
 1537  * maps dt's as necessary
 1538  */
 1539 static struct ntfs_dt * ntfs_dt_find4 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num)
 1540 {
 1541     struct ntfs_dt *res = NULL;
 1542     struct ntfs_dt *sub = NULL;
 1543     INDEX_ENTRY *ie;
 1544     VCN vcn;
 1545     int i;
 1546     int r;
 1547 
 1548     if (!dt || !name)
 1549         return NULL;
 1550 
 1551     //printf ("child_count = %d\n", dt->child_count);
 1552     for (i = 0; i < dt->child_count; i++) {
 1553         ie = dt->children[i];
 1554 
 1555         //printf ("ie->flags = %d\n", ie->flags);
 1556         if (ie->flags & INDEX_ENTRY_END) {
 1557             r = -1;
 1558         } else {
 1559             //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n");
 1560             r = ntfs_names_collate (name, name_len,
 1561                         ie->key.file_name.file_name,
 1562                         ie->key.file_name.file_name_length,
 1563                         2, IGNORE_CASE,
 1564                         dt->dir->vol->upcase,
 1565                         dt->dir->vol->upcase_len);
 1566         }
 1567 
 1568         //printf ("%d, %d\n", i, r);
 1569 
 1570         if (r == 1) {
 1571             //printf ("keep searching\n");
 1572         } else if (r == 0) {
 1573             //res = dt;
 1574             //printf ("match\n");
 1575             // ignore
 1576         } else if (r == -1) {
 1577             if (ie->flags & INDEX_ENTRY_NODE) {
 1578                 //printf ("recurse\n");
 1579                 if (!dt->sub_nodes[i]) {
 1580                     vcn = ntfs_ie_get_vcn (ie);
 1581                     //printf ("vcn = %lld\n", vcn);
 1582                     sub = ntfs_dt_create (dt->dir, dt, vcn);
 1583                     dt->sub_nodes[i] = sub;
 1584                 }
 1585                 res = ntfs_dt_find4 (dt->sub_nodes[i], name, name_len, index_num);
 1586             } else {
 1587                 //printf ("no match\n");
 1588                 res = dt;
 1589                 if (index_num)
 1590                     *index_num = i;
 1591             }
 1592             break;
 1593         } else {
 1594             printf ("error collating name\n");
 1595         }
 1596         //break;
 1597     }
 1598 
 1599     return res;
 1600 }
 1601 
 1602 /**
 1603  * ntfs_dt_find_all
 1604  * maps all dt's into memory
 1605  */
 1606 static void ntfs_dt_find_all (struct ntfs_dt *dt)
 1607 {
 1608     INDEX_ENTRY *ie;
 1609     VCN vcn;
 1610     int i;
 1611 
 1612     if (!dt)
 1613         return;
 1614 
 1615     for (i = 0; i < dt->child_count; i++) {
 1616         ie = dt->children[i];
 1617 
 1618         if (ie->flags & INDEX_ENTRY_NODE) {
 1619             if (!dt->sub_nodes[i]) {
 1620                 vcn = ntfs_ie_get_vcn (ie);
 1621                 dt->sub_nodes[i] = ntfs_dt_create (dt->dir, dt, vcn);
 1622             }
 1623             ntfs_dt_find_all (dt->sub_nodes[i]);
 1624         }
 1625     }
 1626 }
 1627 
 1628 /**
 1629  * ntfs_dt_find_parent
 1630  */
 1631 static int ntfs_dt_find_parent (struct ntfs_dt *dt)
 1632 {
 1633     int i;
 1634     struct ntfs_dt *parent;
 1635 
 1636     if (!dt)
 1637         return -1;
 1638 
 1639     parent = dt->parent;
 1640     if (!parent)
 1641         return -1;
 1642 
 1643     for (i = 0; i < parent->child_count; i++)
 1644         if (parent->sub_nodes[i] == dt)
 1645             return i;
 1646 
 1647     return -1;
 1648 }
 1649 
 1650 /**
 1651  * ntfs_dt_isroot
 1652  */
 1653 static BOOL ntfs_dt_isroot (struct ntfs_dt *dt)
 1654 {
 1655     if (!dt)
 1656         return FALSE;
 1657     return (dt->parent == NULL);
 1658 }
 1659 
 1660 /**
 1661  * ntfs_dt_root_freespace
 1662  */
 1663 static int ntfs_dt_root_freespace (struct ntfs_dt *dt)
 1664 {
 1665     int recsize;
 1666     int inuse;
 1667     MFT_RECORD *mrec;
 1668 
 1669     if (!dt)
 1670         return -1;
 1671 
 1672     recsize = dt->dir->inode->vol->mft_record_size;
 1673 
 1674     mrec = (MFT_RECORD*) dt->dir->inode->mrec;
 1675     inuse = mrec->bytes_in_use;
 1676 
 1677     return recsize - inuse;
 1678 }
 1679 
 1680 /**
 1681  * ntfs_dt_alloc_freespace
 1682  */
 1683 static int ntfs_dt_alloc_freespace (struct ntfs_dt *dt)
 1684 {
 1685     int recsize;
 1686     int inuse;
 1687     INDEX_BLOCK *block;
 1688 
 1689     if (!dt)
 1690         return -1;
 1691 
 1692     recsize = dt->dir->index_size;
 1693 
 1694     block = (INDEX_BLOCK*) dt->data;
 1695     inuse = block->index.index_length + 24;
 1696 
 1697     return recsize - inuse;
 1698 }
 1699 
 1700 /**
 1701  * ntfs_dt_transfer
 1702  */
 1703 static int ntfs_dt_transfer (struct ntfs_dt *old, struct ntfs_dt *new, int start, int count)
 1704 {
 1705     int i;
 1706     int need;
 1707     int space;
 1708     INDEX_ENTRY *mov_ie;
 1709     u8 *src;
 1710     u8 *dst;
 1711     int len;
 1712     int insert;
 1713     //FILE_NAME_ATTR *file;
 1714 
 1715     //XXX check len > 0
 1716 
 1717     if (!old || !new)
 1718         return -1;
 1719 
 1720     if ((start < 0) || ((start+count) >= old->child_count))
 1721         return -1;
 1722 
 1723     printf ("\n");
 1724     printf (BOLD YELLOW "Transferring children\n" END);
 1725 
 1726     need = 0;
 1727     for (i = start; i < (start+count+1); i++) {
 1728         mov_ie = old->children[i];
 1729         need += mov_ie->length;
 1730         //file = &mov_ie->key.file_name; printf ("\ttrn name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 1731     }
 1732 
 1733     if (ntfs_dt_isroot (new))
 1734         space = ntfs_dt_root_freespace (new);
 1735     else
 1736         space = ntfs_dt_alloc_freespace (new);
 1737 
 1738     // XXX if this is an index root, it'll go badly wrong
 1739     // restrict to allocs only?
 1740 
 1741     printf ("\tneed  = %d\n", need);
 1742     printf ("\tspace = %d\n", space);
 1743 
 1744     if (space < need)
 1745         return -1;
 1746 
 1747     if (new->child_count == 1) {
 1748         i = -1;
 1749     } else {
 1750         ntfschar *n1, *n2;
 1751         int l1, l2;
 1752 
 1753         n1 = new->children[0]->key.file_name.file_name;
 1754         l1 = new->children[0]->key.file_name.file_name_length;
 1755 
 1756         n2 = old->children[start]->key.file_name.file_name;
 1757         l2 = old->children[start]->key.file_name.file_name_length;
 1758 
 1759         i = ntfs_names_collate (n1, l1, n2, l2,
 1760                     2, IGNORE_CASE,
 1761                     old->dir->vol->upcase,
 1762                     old->dir->vol->upcase_len);
 1763     }
 1764 
 1765     if ((i == 0) || (i == 2))
 1766         return -1;
 1767 
 1768     // determine the insertion point
 1769     if (i == 1)
 1770         insert = 0;
 1771     else
 1772         insert = new->child_count-1;
 1773 
 1774     src = (u8*) new->children[insert];
 1775     dst = src + need;
 1776     len = (u8*) new->children[new->child_count-1] + new->children[new->child_count-1]->length - src;
 1777 
 1778     //printf ("src = %d, dst = %d, len = %d\n", src - new->data, dst - new->data, len);
 1779     memmove (dst, src, len);
 1780 
 1781     dst = src;
 1782     src = (u8*) old->children[start];
 1783     len = need;
 1784 
 1785     memcpy (dst, src, len);
 1786 
 1787     src = (u8*) old->children[start+count-1];
 1788     dst = (u8*) old->children[start];
 1789     len = (u8*) old->children[old->child_count-1] + old->children[old->child_count-1]->length - src;
 1790 
 1791     //printf ("src = %d, dst = %d, len = %d\n", src - old->data, dst - old->data, len);
 1792     memmove (dst, src, len);
 1793 
 1794     dst += len;
 1795     len = old->data + old->dir->index_size - dst;
 1796 
 1797     //printf ("dst = %d, len = %d\n", dst - old->data, len);
 1798     memset (dst, 0, len);
 1799 
 1800     if (!ntfs_dt_resize_children3 (new, new->child_count + count))
 1801         return -1;
 1802 
 1803     src = (u8*) &old->sub_nodes[start+count-1];
 1804     dst = (u8*) &old->sub_nodes[start];
 1805     len = (old->child_count - start - count + 1) * sizeof (struct ntfs_dt*);
 1806 
 1807     memmove (dst, src, len);
 1808 
 1809     src = (u8*) &new->sub_nodes[insert];
 1810     dst = (u8*) &new->sub_nodes[insert+count-1];
 1811     len = (new->child_count - insert - count + 1) * sizeof (struct ntfs_dt*);
 1812 
 1813     memmove (dst, src, len);
 1814 
 1815     if (!ntfs_dt_resize_children3 (old, old->child_count - count))
 1816         return -1;
 1817 
 1818     src = (u8*) new->children[0];
 1819     for (i = 0; i < new->child_count; i++) {
 1820         new->children[i] = (INDEX_ENTRY*) src;
 1821         src += new->children[i]->length;
 1822     }
 1823 
 1824     src = (u8*) old->children[0];
 1825     for (i = 0; i < old->child_count; i++) {
 1826         old->children[i] = (INDEX_ENTRY*) src;
 1827         src += old->children[i]->length;
 1828     }
 1829 
 1830     old->header->index_length -= need;
 1831     new->header->index_length += need;
 1832 
 1833     // resize children and sub_nodes
 1834     // memmove keys in new
 1835     // memcpy old to new
 1836     // memmove keys in old
 1837     // rebuild old/new children/sub_nodes without destroying tree
 1838     // update old/new headers
 1839 
 1840     old->changed = TRUE;
 1841     new->changed = TRUE;
 1842 
 1843     printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, old->dir->inode->mft_no, old->vcn, old->vcn + (old->dir->index_size>>9) - 1);
 1844     printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, new->dir->inode->mft_no, new->vcn, new->vcn + (new->dir->index_size>>9) - 1);
 1845 
 1846     return 0;
 1847 }
 1848 
 1849 
 1850 /**
 1851  * ntfs_dt_alloc_insert
 1852  */
 1853 static int ntfs_dt_alloc_insert (struct ntfs_dt *dt, INDEX_ENTRY *first, int count)
 1854 {
 1855     // XXX don't bother measuring, just subtract the children pointers
 1856 
 1857     int i;
 1858     int need;
 1859     INDEX_ENTRY *ie;
 1860     INDEX_ALLOCATION *alloc;
 1861     u8 *src;
 1862     u8 *dst;
 1863     int len;
 1864 
 1865     if (!dt)
 1866         return 1;
 1867     if (!first)
 1868         return 1;
 1869 
 1870     need = 0;
 1871     ie = first;
 1872     for (i = 0; i < count; i++) {
 1873         need += ie->length;
 1874         ie = (INDEX_ENTRY*) ((u8*)ie + ie->length);
 1875     }
 1876 
 1877     printf ("alloc insert %d bytes\n", need);
 1878 
 1879     alloc = (INDEX_ALLOCATION*) dt->data;
 1880     printf ("entries_offset = %d\n", alloc->index.entries_offset);
 1881     printf ("index_length   = %d\n", alloc->index.index_length);
 1882     printf ("allocated_size = %d\n", alloc->index.allocated_size);
 1883 
 1884     printf ("insert has %d children\n", dt->child_count);
 1885     printf ("children = %p\n", dt->children);
 1886     //utils_dump_mem (dt->data, 0, 128, DM_DEFAULTS);
 1887 
 1888     ie = dt->children[dt->child_count-1];
 1889 
 1890     printf ("last child = %p (%ld)\n", ie, (long)ie - (long)dt->data);
 1891     printf ("size = %d\n", ie->length);
 1892 
 1893     src = (u8*) ie;
 1894     dst = src + need;
 1895     len = ie->length;
 1896 
 1897     memmove (dst, src, len);
 1898 
 1899     src = (u8*) first;
 1900     dst = (u8*) ie;
 1901     len = need;
 1902 
 1903     memcpy (dst, src, len);
 1904 
 1905     // use create children
 1906     // measure need and update children list
 1907     // adjust headers
 1908 
 1909     utils_dump_mem (dt->data, 0, 256, DM_DEFAULTS);
 1910     return 0;
 1911 }
 1912 
 1913 /**
 1914  * ntfs_dt_alloc_insert2
 1915  */
 1916 static INDEX_ENTRY * ntfs_dt_alloc_insert2 (struct ntfs_dt *dt, int before, int count, int bytes)
 1917 {
 1918     int space;
 1919     u8 *src;
 1920     u8 *dst;
 1921     int len;
 1922 
 1923     // XXX don't bother measuring, just subtract the children pointers
 1924 
 1925     if (!dt)
 1926         return NULL;
 1927     if (before < 0)
 1928         return NULL;
 1929     if (count < 1)
 1930         return NULL;
 1931     if (bytes < 1)
 1932         return NULL;
 1933 
 1934     // check alloc has enough space
 1935     space = ntfs_dt_alloc_freespace (dt);
 1936     if (bytes > space)
 1937         return NULL;
 1938 
 1939     // move data
 1940     src = (u8*) dt->children[before];
 1941     dst = src + bytes;
 1942     len = dt->header->index_length - ((int)dt->children[before] - (int)dt->data) + 24;
 1943 
 1944     //printf ("%d, %d, %d\n", (int)src - (int)dt->data, (int)dst - (int)dt->data, len);
 1945 
 1946     memmove (dst, src, len);
 1947     memset (dst, 0, bytes);
 1948 
 1949     // resize arrays
 1950     ntfs_dt_resize_children3 (dt, dt->child_count + count);
 1951 
 1952     // move keys (children)
 1953     src = (u8*) (dt->children + before);
 1954     dst = src + (count * sizeof (u8*));
 1955     len = (dt->child_count - count - before) * sizeof (u8*);
 1956 
 1957     memmove (dst, src, len);
 1958     memset (src, 0, count * sizeof (u8*));
 1959 
 1960     // move keys (inodes)
 1961     src = (u8*) (dt->inodes + before);
 1962     dst = src + (count * sizeof (u8*));
 1963     len = (dt->child_count - count - before) * sizeof (u8*);
 1964 
 1965     memmove (dst, src, len);
 1966     memset (src, 0, count * sizeof (u8*));
 1967 
 1968     // move keys (sub_nodes)
 1969     src = (u8*) (dt->sub_nodes + before);
 1970     dst = src + (count * sizeof (u8*));
 1971     len = (dt->child_count - count - before) * sizeof (u8*);
 1972 
 1973     memmove (dst, src, len);
 1974     memset (src, 0, count * sizeof (u8*));
 1975 
 1976     return NULL;
 1977 }
 1978 
 1979 /**
 1980  * ntfs_dt_root_insert
 1981  */
 1982 static int ntfs_dt_root_insert (struct ntfs_dt *dt, INDEX_ENTRY *first, int count)
 1983 {
 1984     if (!dt)
 1985         return 1;
 1986     if (!first)
 1987         return 1;
 1988 
 1989     return count;
 1990 }
 1991 
 1992 
 1993 /**
 1994  * utils_array_insert
 1995  */
 1996 static int utils_array_insert (void *ptr, int asize, int before, int count)
 1997 {
 1998     static int esize = sizeof (u8*);
 1999     u8 *src;
 2000     u8 *dst;
 2001     int len;
 2002 
 2003     if (!ptr)
 2004         return -1;
 2005 
 2006     src = (u8*) ptr + (before * esize);
 2007     dst = src + (count * esize);
 2008     len = (asize - before) * esize;
 2009 
 2010     // XXX what about realloc?
 2011     memmove (dst, src, len);
 2012 
 2013     len = count * esize;
 2014 
 2015     memset (src, 0, len);
 2016 
 2017     return 0;
 2018 }
 2019 
 2020 /**
 2021  * utils_array_remove
 2022  */
 2023 static int utils_array_remove (void *ptr, int asize, int first, int count)
 2024 {
 2025     static int esize = sizeof (u8*);
 2026     u8 *src;
 2027     u8 *dst;
 2028     int len;
 2029 
 2030     if (!ptr)
 2031         return -1;
 2032 
 2033     dst = (u8*) ptr + (first * esize);
 2034     src = dst + (count * esize);
 2035     len = (asize - first) * esize;
 2036 
 2037     memmove (dst, src, len);
 2038 
 2039     src = (u8*) ptr + ((asize - count) * esize);
 2040     len = count * esize;
 2041 
 2042     memset (src, 0, len);
 2043     // XXX don't want to memset, want to realloc
 2044 
 2045     return 0;
 2046 }
 2047 
 2048 
 2049 /**
 2050  * ntfs_dt_alloc_remove2
 2051  */
 2052 static int ntfs_dt_alloc_remove2 (struct ntfs_dt *dt, int start, int count)
 2053 {
 2054     int i;
 2055     int size;
 2056 
 2057     if (!dt)
 2058         return 1;
 2059 
 2060     size = 0;
 2061     for (i = start; i < (start+count); i++) {
 2062         size += dt->children[i]->length;
 2063     }
 2064 
 2065     return start + count;
 2066 }
 2067 
 2068 /**
 2069  * ntfs_dt_root_remove2
 2070  */
 2071 static int ntfs_dt_root_remove2 (struct ntfs_dt *dt, int start, int count)
 2072 {
 2073     int i;
 2074     int size;
 2075 
 2076     if (!dt)
 2077         return -1;
 2078     if ((start < 0) || (start >= dt->child_count))
 2079         return -1;
 2080     if ((count < 1) || ((start + count - 1) >= dt->child_count))
 2081         return -1;
 2082 
 2083     printf ("s c/t %d %d/%d\n", start, count, dt->child_count);
 2084 
 2085     size = 0;
 2086     for (i = start; i < (start + count); i++)
 2087         size += dt->children[i]->length;
 2088     printf ("size1 = %d\n", size);
 2089 
 2090     size = (int) dt->children[start+count] - (int) dt->children[start];
 2091     printf ("size2 = %d\n", size);
 2092 
 2093     size = (int) dt->children[start+count-1] - (int) dt->children[start] + dt->children[start+count-1]->length;
 2094     printf ("size3 = %d\n", size);
 2095 
 2096     // XXX what shall we do with the inodes?
 2097     // transfer them to the dir (commit them for now)
 2098     // are they _our_ responsibility?  probably not
 2099 
 2100     // rearrange arrays
 2101     // shrink attribute
 2102 
 2103     ntfs_dt_resize_children3 (dt, dt->child_count - count);
 2104 
 2105     printf ("ntfs_dt_root_remove2\n");
 2106     return dt->child_count;
 2107 }
 2108 
 2109 /**
 2110  * ntfs_dt_transfer2
 2111  */
 2112 static int ntfs_dt_transfer2 (struct ntfs_dt *old, struct ntfs_dt *new, int start, int count)
 2113 {
 2114     int i;
 2115     int need;
 2116     int space;
 2117     INDEX_ENTRY *mov_ie;
 2118     u8 *src;
 2119     u8 *dst;
 2120     int len;
 2121     int insert;
 2122     //FILE_NAME_ATTR *file;
 2123 
 2124     if (!old || !new)
 2125         return -1;
 2126 
 2127     if ((start < 0) || (count < 0))
 2128         return -1;
 2129 
 2130     if ((start + count) >= old->child_count)
 2131         return -1;
 2132 
 2133     printf ("\n");
 2134     printf (BOLD YELLOW "Transferring children\n" END);
 2135 
 2136     need = 0;
 2137     for (i = start; i < (start+count); i++) {
 2138         mov_ie = old->children[i];
 2139         need += mov_ie->length;
 2140         //file = &mov_ie->key.file_name; printf ("\ttrn name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 2141     }
 2142 
 2143     if (ntfs_dt_isroot (new))
 2144         space = ntfs_dt_root_freespace (new);
 2145     else
 2146         space = ntfs_dt_alloc_freespace (new);
 2147 
 2148     printf ("\tneed  = %d\n", need);
 2149     printf ("\tspace = %d\n", space);
 2150 
 2151     if (need > space)
 2152         return -1;
 2153 
 2154     if (ntfs_dt_isroot (new))
 2155         ntfs_dt_root_insert (new, old->children[0], count);
 2156     else
 2157         ntfs_dt_alloc_insert2 (new, 0, count, need);
 2158 
 2159     if (ntfs_dt_isroot (old))
 2160         ntfs_dt_root_remove2 (old, 0, count);
 2161     else
 2162         ntfs_dt_alloc_remove2 (old, 0, count);
 2163 
 2164     if (1) return -1;
 2165     if (0) ntfs_dt_alloc_insert (NULL, NULL, 0);
 2166 
 2167     if (new->child_count == 1) {
 2168         i = -1;
 2169     } else {
 2170         ntfschar *n1, *n2;
 2171         int l1, l2;
 2172 
 2173         n1 = new->children[0]->key.file_name.file_name;
 2174         l1 = new->children[0]->key.file_name.file_name_length;
 2175 
 2176         n2 = old->children[start]->key.file_name.file_name;
 2177         l2 = old->children[start]->key.file_name.file_name_length;
 2178 
 2179         i = ntfs_names_collate (n1, l1, n2, l2,
 2180                     2, IGNORE_CASE,
 2181                     old->dir->vol->upcase,
 2182                     old->dir->vol->upcase_len);
 2183     }
 2184 
 2185     if ((i == 0) || (i == 2))
 2186         return -1;
 2187 
 2188     // determine the insertion point
 2189     if (i == 1)
 2190         insert = 0;
 2191     else
 2192         insert = new->child_count-1;
 2193 
 2194     src = (u8*) new->children[insert];
 2195     dst = src + need;
 2196     len = (u8*) new->children[new->child_count-1] + new->children[new->child_count-1]->length - src;
 2197 
 2198     //printf ("src = %d, dst = %d, len = %d\n", src - new->data, dst - new->data, len);
 2199     memmove (dst, src, len);
 2200 
 2201     dst = src;
 2202     src = (u8*) old->children[start];
 2203     len = need;
 2204 
 2205     memcpy (dst, src, len);
 2206 
 2207     src = (u8*) old->children[start+count-1];
 2208     dst = (u8*) old->children[start];
 2209     len = (u8*) old->children[old->child_count-1] + old->children[old->child_count-1]->length - src;
 2210 
 2211     //printf ("src = %d, dst = %d, len = %d\n", src - old->data, dst - old->data, len);
 2212     memmove (dst, src, len);
 2213 
 2214     dst += len;
 2215     len = old->data + old->dir->index_size - dst;
 2216 
 2217     //printf ("dst = %d, len = %d\n", dst - old->data, len);
 2218     memset (dst, 0, len);
 2219 
 2220     if (!ntfs_dt_resize_children3 (new, new->child_count + count))
 2221         return -1;
 2222 
 2223     src = (u8*) &old->sub_nodes[start+count-1];
 2224     dst = (u8*) &old->sub_nodes[start];
 2225     len = (old->child_count - start - count + 1) * sizeof (struct ntfs_dt*);
 2226 
 2227     memmove (dst, src, len);
 2228 
 2229     src = (u8*) &new->sub_nodes[insert];
 2230     dst = (u8*) &new->sub_nodes[insert+count-1];
 2231     len = (new->child_count - insert - count + 1) * sizeof (struct ntfs_dt*);
 2232 
 2233     memmove (dst, src, len);
 2234 
 2235     if (!ntfs_dt_resize_children3 (old, old->child_count - count))
 2236         return -1;
 2237 
 2238     src = (u8*) new->children[0];
 2239     for (i = 0; i < new->child_count; i++) {
 2240         new->children[i] = (INDEX_ENTRY*) src;
 2241         src += new->children[i]->length;
 2242     }
 2243 
 2244     src = (u8*) old->children[0];
 2245     for (i = 0; i < old->child_count; i++) {
 2246         old->children[i] = (INDEX_ENTRY*) src;
 2247         src += old->children[i]->length;
 2248     }
 2249 
 2250     old->header->index_length -= need;
 2251     new->header->index_length += need;
 2252 
 2253     // resize children and sub_nodes
 2254     // memmove keys in new
 2255     // memcpy old to new
 2256     // memmove keys in old
 2257     // rebuild old/new children/sub_nodes without destroying tree
 2258     // update old/new headers
 2259 
 2260     old->changed = TRUE;
 2261     new->changed = TRUE;
 2262 
 2263     printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, old->dir->inode->mft_no, old->vcn, old->vcn + (old->dir->index_size>>9) - 1);
 2264     printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, new->dir->inode->mft_no, new->vcn, new->vcn + (new->dir->index_size>>9) - 1);
 2265 
 2266     return 0;
 2267 }
 2268 
 2269 
 2270 /**
 2271  * utils_free_non_residents3
 2272  */
 2273 static int utils_free_non_residents3 (struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_RECORD *attr)
 2274 {
 2275     ntfs_attr *na;
 2276     runlist_element *rl;
 2277     LCN size;
 2278     LCN count;
 2279 
 2280     if (!bmp)
 2281         return 1;
 2282     if (!inode)
 2283         return 1;
 2284     if (!attr)
 2285         return 1;
 2286     if (!attr->non_resident)
 2287         return 0;
 2288 
 2289     na = ntfs_attr_open (inode, attr->type, NULL, 0);
 2290     if (!na)
 2291         return 1;
 2292 
 2293     ntfs_attr_map_whole_runlist (na);
 2294     rl = na->rl;
 2295     size = na->allocated_size >> inode->vol->cluster_size_bits;
 2296     for (count = 0; count < size; count += rl->length, rl++) {
 2297         if (ntfs_bmp_set_range (bmp, rl->lcn, rl->length, 0) < 0) {
 2298             printf (RED "set range : %lld - %lld FAILED\n" END, rl->lcn, rl->lcn+rl->length-1);
 2299         }
 2300     }
 2301     ntfs_attr_close (na);
 2302 
 2303     return 0;
 2304 }
 2305 
 2306 /**
 2307  * utils_free_non_residents2
 2308  */
 2309 static int utils_free_non_residents2 (ntfs_inode *inode, struct ntfs_bmp *bmp)
 2310 {
 2311     ntfs_attr_search_ctx *ctx;
 2312 
 2313     if (!inode)
 2314         return -1;
 2315     if (!bmp)
 2316         return -1;
 2317 
 2318     ctx = ntfs_attr_get_search_ctx (inode, NULL);
 2319     if (!ctx) {
 2320         printf ("can't create a search context\n");
 2321         return -1;
 2322     }
 2323 
 2324     while (ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx) == 0) {
 2325         utils_free_non_residents3 (bmp, inode, ctx->attr);
 2326     }
 2327 
 2328     ntfs_attr_put_search_ctx (ctx);
 2329     return 0;
 2330 }
 2331 
 2332 
 2333 /**
 2334  * ntfs_mft_remove_attr
 2335  */
 2336 static int ntfs_mft_remove_attr (struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_TYPES type)
 2337 {
 2338     ATTR_RECORD *attr20, *attrXX;
 2339     MFT_RECORD *mft;
 2340     u8 *src, *dst;
 2341     int len;
 2342 
 2343     if (!inode)
 2344         return 1;
 2345 
 2346     attr20 = find_first_attribute (AT_ATTRIBUTE_LIST, inode->mrec);
 2347     if (attr20)
 2348         return 1;
 2349 
 2350     printf ("remove inode %lld, attr 0x%02X\n", inode->mft_no, type);
 2351 
 2352     attrXX = find_first_attribute (type, inode->mrec);
 2353     if (!attrXX)
 2354         return 1;
 2355 
 2356     if (utils_free_non_residents3 (bmp, inode, attrXX))
 2357         return 1;
 2358 
 2359     // remove entry
 2360     // inode->mrec
 2361 
 2362     mft = inode->mrec;
 2363     //utils_dump_mem (mft, 0, mft->bytes_in_use, DM_DEFAULTS); printf ("\n");
 2364 
 2365     //utils_dump_mem (attrXX, 0, attrXX->length, DM_DEFAULTS); printf ("\n");
 2366 
 2367     //printf ("mrec = %p, attr = %p, diff = %d (0x%02X)\n", mft, attrXX, (u8*)attrXX - (u8*)mft, (u8*)attrXX - (u8*)mft);
 2368     // memmove
 2369 
 2370     dst = (u8*) attrXX;
 2371     src = dst + attrXX->length;
 2372     len = (((u8*) mft + mft->bytes_in_use) - src);
 2373 
 2374     // fix mft header
 2375     mft->bytes_in_use -= attrXX->length;
 2376 
 2377 #if 0
 2378     printf ("dst = 0x%02X, src = 0x%02X, len = 0x%02X\n", (dst - (u8*)mft), (src - (u8*)mft), len);
 2379     printf ("attr %02X, len = 0x%02X\n", attrXX->type, attrXX->length);
 2380     printf ("bytes in use = 0x%02X\n", mft->bytes_in_use);
 2381     printf ("\n");
 2382 #endif
 2383 
 2384     memmove (dst, src, len);
 2385     //utils_dump_mem (mft, 0, mft->bytes_in_use, DM_DEFAULTS); printf ("\n");
 2386 
 2387     NInoSetDirty(inode);
 2388     return 0;
 2389 }
 2390 
 2391 /**
 2392  * ntfs_mft_add_attr
 2393  */
 2394 static ATTR_RECORD * ntfs_mft_add_attr (ntfs_inode *inode, ATTR_TYPES type, u8 *data, int data_len)
 2395 {
 2396     MFT_RECORD *mrec;
 2397     ATTR_RECORD *attr;
 2398     u8 *ptr;
 2399     u8 *src;
 2400     u8 *dst;
 2401     int len;
 2402     int attr_size;
 2403 
 2404     if (!inode)
 2405         return NULL;
 2406     if (!data)
 2407         return NULL;
 2408 
 2409     attr_size = ATTR_SIZE (data_len);
 2410 
 2411     mrec = inode->mrec;
 2412     if (!mrec)
 2413         return NULL;
 2414 
 2415     if ((mrec->bytes_in_use + attr_size + 0x18) > mrec->bytes_allocated) {
 2416         printf ("attribute is too big to fit in the record\n");
 2417         return NULL;
 2418     }
 2419 
 2420     ptr = (u8*) inode->mrec + mrec->attrs_offset;
 2421     while (1) {
 2422         attr = (ATTR_RECORD*) ptr;
 2423 
 2424         if (type < attr->type)
 2425             break;
 2426 
 2427         ptr += attr->length;
 2428     }
 2429 
 2430     //printf ("insert before attr 0x%02X\n", attr->type);
 2431 
 2432     len = ((u8*) mrec + mrec->bytes_in_use) - ((u8*) attr);
 2433     src = (u8*) attr;
 2434     dst = src + attr_size + 0x18;
 2435 
 2436     memmove (dst, src, len);
 2437 
 2438     src = data;
 2439     dst = (u8*) attr + 0x18;
 2440     len = data_len;
 2441 
 2442     // XXX wipe slack space after attr?
 2443 
 2444     memcpy (dst, src, len);
 2445 
 2446     mrec->bytes_in_use += attr_size + 0x18;
 2447 
 2448     memset (attr, 0, 0x18);
 2449     *(u32*)((u8*) attr + 0x00) = type;
 2450     *(u32*)((u8*) attr + 0x04) = attr_size + 0x18;
 2451     *(u16*)((u8*) attr + 0x0E) = mrec->next_attr_instance;
 2452     *(u32*)((u8*) attr + 0x10) = data_len;
 2453     *(u32*)((u8*) attr + 0x14) = 0x18;
 2454 
 2455     mrec->next_attr_instance++;
 2456 
 2457     return attr;
 2458 }
 2459 
 2460 /**
 2461  * ntfs_mft_resize_resident
 2462  */
 2463 static int ntfs_mft_resize_resident (ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len, u8 *data, int data_len)
 2464 {
 2465     int mft_size;
 2466     int mft_usage;
 2467     int mft_free;
 2468     int attr_orig;
 2469     int attr_new;
 2470     u8 *src;
 2471     u8 *dst;
 2472     u8 *end;
 2473     int len;
 2474     ntfs_attr_search_ctx *ctx = NULL;
 2475     ATTR_RECORD *arec = NULL;
 2476     MFT_RECORD *mrec = NULL;
 2477     int res = -1;
 2478 
 2479     // XXX only works when attr is in base inode
 2480 
 2481     if ((!inode) || (!inode->mrec))
 2482         return -1;
 2483     if ((!data) || (data_len < 0))
 2484         return -1;
 2485 
 2486     mrec = inode->mrec;
 2487 
 2488     mft_size  = mrec->bytes_allocated;
 2489     mft_usage = mrec->bytes_in_use;
 2490     mft_free  = mft_size - mft_usage;
 2491 
 2492     //printf ("mft_size  = %d\n", mft_size);
 2493     //printf ("mft_usage = %d\n", mft_usage);
 2494     //printf ("mft_free  = %d\n", mft_free);
 2495     //printf ("\n");
 2496 
 2497     ctx = ntfs_attr_get_search_ctx (inode, NULL);
 2498     if (!ctx)
 2499         goto done;
 2500 
 2501     if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0, ctx) != 0)
 2502         goto done;
 2503 
 2504     arec = ctx->attr;
 2505 
 2506     if (arec->non_resident) {
 2507         printf ("attribute isn't resident\n");
 2508         goto done;
 2509     }
 2510 
 2511     attr_orig = arec->value_length;
 2512     attr_new  = data_len;
 2513 
 2514     //printf ("attr orig = %d\n", attr_orig);
 2515     //printf ("attr new  = %d\n", attr_new);
 2516     //printf ("\n");
 2517 
 2518     if ((attr_new - attr_orig + mft_usage) > mft_size) {
 2519         printf ("attribute won't fit into mft record\n");
 2520         goto done;
 2521     }
 2522 
 2523     //printf ("new free space = %d\n", mft_size - (attr_new - attr_orig + mft_usage));
 2524 
 2525     src = (u8*)arec + arec->length;
 2526     dst = src + (attr_new - attr_orig);
 2527     end = (u8*)mrec + mft_usage;
 2528     len  = end - src;
 2529 
 2530     //printf ("src = %d\n", src - (u8*)mrec);
 2531     //printf ("dst = %d\n", dst - (u8*)mrec);
 2532     //printf ("end = %d\n", end - (u8*)mrec);
 2533     //printf ("len = %d\n", len);
 2534 
 2535     if (src != dst)
 2536         memmove (dst, src, len);
 2537 
 2538     memcpy ((u8*)arec + arec->value_offset, data, data_len);
 2539 
 2540     mrec->bytes_in_use += (attr_new - attr_orig);
 2541     arec->length       += (attr_new - attr_orig);
 2542     arec->value_length += (attr_new - attr_orig);
 2543 
 2544     memset ((u8*)mrec + mrec->bytes_in_use, 0, mft_size - mrec->bytes_in_use);
 2545 
 2546     mft_usage += (attr_new - attr_orig);
 2547     //utils_dump_mem (mrec, 0, mft_size, DM_DEFAULTS);
 2548     res = 0;
 2549 done:
 2550     ntfs_attr_put_search_ctx (ctx);
 2551     return res;
 2552 }
 2553 
 2554 /**
 2555  * ntfs_mft_free_space
 2556  */
 2557 static int ntfs_mft_free_space (struct ntfs_dir *dir)
 2558 {
 2559     int res = 0;
 2560     MFT_RECORD *mft;
 2561 
 2562     if ((!dir) || (!dir->inode))
 2563         return -1;
 2564 
 2565     mft = (MFT_RECORD*) dir->inode->mrec;
 2566 
 2567     res = mft->bytes_allocated - mft->bytes_in_use;
 2568 
 2569     return res;
 2570 }
 2571 
 2572 /**
 2573  * ntfs_mft_add_index
 2574  */
 2575 static int ntfs_mft_add_index (struct ntfs_dir *dir)
 2576 {
 2577     ntfs_volume *vol;
 2578     u8 *buffer = NULL;
 2579     ATTR_RECORD *attr = NULL;
 2580     struct ntfs_dt *dt = NULL;
 2581     INDEX_ENTRY *ie = NULL;
 2582 
 2583     if (!dir)
 2584         return 1;
 2585     if (dir->bitmap && dir->ialloc)
 2586         return 0;
 2587     if (dir->bitmap || dir->ialloc)
 2588         return 1;
 2589     if (dir->index_size < 512)
 2590         return 1;
 2591 
 2592     vol = dir->vol;
 2593     printf ("add two attrs to " YELLOW); ntfs_name_print (dir->name, dir->name_len); printf (END "\n");
 2594     printf ("index size = %d\n", dir->index_size);
 2595 
 2596     buffer = malloc (dir->index_size);
 2597     if (!buffer)
 2598         return 1;
 2599 
 2600     dt = ntfs_dt_create (dir, dir->index, -1);
 2601     if (!dt)
 2602         return 1;
 2603 
 2604     dt->vcn = 0;        // New alloc record
 2605 
 2606     ie = ntfs_ie_copy (dir->index->children[dir->index->child_count-1]);
 2607     ie = ntfs_ie_set_vcn (ie, dt->vcn);
 2608 
 2609     // can't replace ie yet, there may not be room
 2610     ntfs_ie_free (ie);
 2611 
 2612     ntfs_dt_transfer2 (dir->index, dt, 0, dir->index->child_count - 1);
 2613 
 2614     printf ("root has %d children\n", dir->index->child_count);
 2615     printf ("node has %d children\n", dt->child_count);
 2616 
 2617     ntfs_dt_free (dt);
 2618 
 2619     // create a new dt
 2620     // attach dt to dir
 2621     // move entries into alloc
 2622     // shrink root
 2623 
 2624     // transfer keys to new node
 2625     // hook up root & alloc dts
 2626 
 2627     // need disk allocation before here
 2628 
 2629     // Index Allocation
 2630     memset (buffer, 0, 128);
 2631     attr = ntfs_mft_add_attr (dir->inode, AT_INDEX_ALLOCATION, buffer, 0x48);
 2632 
 2633     // Bitmap
 2634     memset (buffer, 0, 8);
 2635     buffer[0] = 0x01;
 2636     //printf ("inode = %p\n", dir->inode);
 2637     attr = ntfs_mft_add_attr (dir->inode, AT_BITMAP, buffer, 8);
 2638 
 2639     // attach alloc and bitmap to dir
 2640     // need to create ntfs_attr's for them
 2641 
 2642     // one indx record
 2643     // 8 bits of bitmap
 2644 
 2645     if (0) ntfs_bmp_find_space (NULL, 0, 0);
 2646 
 2647     //printf ("m1 = %lld\n", vol->mft_zone_start);
 2648     //printf ("m2 = %lld\n", vol->mft_zone_end);
 2649     //printf ("m3 = %lld\n", vol->mft_zone_pos);
 2650     //printf ("z1 = %lld\n", vol->data1_zone_pos);
 2651     //printf ("z2 = %lld\n", vol->data2_zone_pos);
 2652 
 2653     free (buffer);
 2654     return 0;
 2655 }
 2656 
 2657 
 2658 /**
 2659  * ntfs_inode_open2
 2660  */
 2661 static ntfs_inode * ntfs_inode_open2 (ntfs_volume *vol, const MFT_REF mref)
 2662 {
 2663     ntfs_inode *ino = NULL;
 2664     struct ntfs_dir *dir;
 2665 
 2666     if (!vol)
 2667         return NULL;
 2668 
 2669     switch (mref) {
 2670         case FILE_Bitmap:  ino = vol->lcnbmp_ni;  break;
 2671         case FILE_MFT:     ino = vol->mft_ni;     break;
 2672         case FILE_MFTMirr: ino = vol->mftmirr_ni; break;
 2673         case FILE_root:
 2674             dir = vol->private_data;
 2675             if (dir)
 2676                 ino = dir->inode;
 2677             break;
 2678     }
 2679 
 2680     if (ino) {
 2681         //printf (BOLD YELLOW "inode reuse %lld\n" END, mref);
 2682         ino->ref_count++;
 2683         return ino;
 2684     }
 2685 
 2686     ino = ntfs_inode_open (vol, mref);
 2687     if (!ino)
 2688         return NULL;
 2689 
 2690     /*
 2691     if (mref != FILE_root)
 2692         ntfs_inode_dir_map (ino);
 2693     */
 2694 
 2695     // link
 2696     //   ino->private_data
 2697 
 2698     ino->private_data = NULL;
 2699     ino->ref_count = 1;
 2700 
 2701     //printf (BOLD YELLOW "inode open %lld\n" END, mref);
 2702     return ino;
 2703 }
 2704 
 2705 /**
 2706  * ntfs_inode_open3
 2707  * open a deleted inode
 2708  */
 2709 static ntfs_inode * ntfs_inode_open3 (ntfs_volume *vol, const MFT_REF mref)
 2710 {
 2711     ntfs_inode *ino = NULL;
 2712 
 2713     if (!vol)
 2714         return NULL;
 2715 
 2716     ino = calloc (1, sizeof (*ino));
 2717     if (!ino)
 2718         return NULL;
 2719 
 2720     ino->mrec = malloc (vol->mft_record_size);
 2721     if (!ino->mrec) {
 2722         free (ino);
 2723         return NULL;
 2724     }
 2725 
 2726     ino->mft_no = mref;
 2727     ino->vol = vol;
 2728 
 2729     ino->data_size = -1;
 2730     ino->allocated_size = -1;
 2731 
 2732     ino->private_data = NULL;
 2733     ino->ref_count = 1;
 2734 
 2735     if (1 != ntfs_attr_mst_pread (vol->mft_na, MREF(mref) * vol->mft_record_size, 1, vol->mft_record_size, ino->mrec)) {
 2736         //ntfs_inode_close2 (ino); ???
 2737         free (ino->mrec);
 2738         free (ino);
 2739         return NULL;
 2740     }
 2741 
 2742     NInoSetDirty (ino);
 2743     return ino;
 2744 }
 2745 
 2746 
 2747 /**
 2748  * ntfs_dt_root_replace
 2749  */
 2750 static int ntfs_dt_root_replace (struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie)
 2751 {
 2752     u8 *src;
 2753     u8 *dst;
 2754     u8 *attr;
 2755     int len;
 2756     int i;
 2757 
 2758     if (!del || !del_ie || !suc_ie)
 2759         return FALSE;
 2760 
 2761     //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
 2762     //printf ("\n");
 2763 
 2764     attr = malloc (del->data_len + suc_ie->length - del_ie->length);
 2765 
 2766     dst = attr;
 2767     src = del->data;
 2768     len = (u8*) del_ie - del->data;
 2769 
 2770     memcpy (dst, src, len);
 2771 
 2772     dst += len;
 2773     src = (u8*) suc_ie;
 2774     len = suc_ie->length;
 2775 
 2776     memcpy (dst, src, len);
 2777 
 2778     dst += len;
 2779     src = (u8*) del_ie + del_ie->length;
 2780     len = del->data_len + (del->data - (u8*) del_ie) - del_ie->length;
 2781 
 2782     memcpy (dst, src, len);
 2783 
 2784     src = (u8*) del->data;
 2785     dst = attr;
 2786 
 2787     len = suc_ie->length - del_ie->length;
 2788     free (del->data);
 2789     del->data = attr;
 2790     del->data_len += len;
 2791     del->header = (INDEX_HEADER*) (del->data + 0x10);
 2792     del->header->index_length   += len;
 2793     del->header->allocated_size += len;
 2794 
 2795     ntfs_mft_resize_resident (del->dir->inode, AT_INDEX_ROOT, I30, 4, del->data, del->data_len);
 2796 
 2797     //utils_dump_mem (attr, 0, del->data_len, DM_DEFAULTS);
 2798 
 2799     //printf ("\n");
 2800     //printf (BOLD YELLOW "Adjust children\n" END);
 2801     //for (i = 0; i < del->child_count; i++)
 2802     //  printf ("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags);
 2803     //printf ("\n");
 2804 
 2805     //printf ("src = %p, dst = %p, len = %d\n", src, dst, len); fflush (stdout);
 2806 
 2807     for (i = 0; i < del->child_count; i++)
 2808         del->children[i] = (INDEX_ENTRY*) (dst + ((u8*) del->children[i] - src));
 2809 
 2810     for (i = del_num+1; i < del->child_count; i++)
 2811         del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] + len);
 2812 
 2813     //for (i = 0; i < del->child_count; i++)
 2814     //  printf ("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags);
 2815     //printf ("\n");
 2816 
 2817     //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
 2818     //printf ("\n");
 2819 
 2820     del->changed = TRUE;
 2821 
 2822     printf (GREEN "Modified: inode %lld, $INDEX_ROOT\n" END, del->dir->inode->mft_no);
 2823     return TRUE;
 2824 }
 2825 
 2826 /**
 2827  * ntfs_dt_alloc_replace
 2828  */
 2829 static BOOL ntfs_dt_alloc_replace (struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie)
 2830 {
 2831     u8 *src;
 2832     u8 *dst;
 2833     int len;
 2834     int i;
 2835 
 2836     if (!del || !del_ie || !suc_ie)
 2837         return FALSE;
 2838 
 2839     //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
 2840 
 2841     src = (u8*) del_ie + del_ie->length;
 2842     dst = (u8*) del_ie + suc_ie->length;
 2843     len = del->header->index_length + 24 + (del->data - src);
 2844     //printf ("src = %d\n", src - del->data);
 2845     //printf ("dst = %d\n", dst - del->data);
 2846     //printf ("len = %d\n", len);
 2847 
 2848     if (src != dst)
 2849         memmove (dst, src, len);
 2850 
 2851     src = (u8*) suc_ie;
 2852     dst = (u8*) del_ie;
 2853     len = suc_ie->length;
 2854 
 2855     memcpy (dst, src, len);
 2856 
 2857     //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
 2858 
 2859     del->header->index_length += suc_ie->length - del_ie->length;
 2860 
 2861     dst = del->data + del->header->index_length + 24;
 2862     len = del->data_len - del->header->index_length - 24;
 2863 
 2864     memset (dst, 0, len);
 2865 
 2866     //for (i = 0; i < del->child_count; i++)
 2867     //  printf ("Child %d %p\n", i, del->children[i]);
 2868     //printf ("\n");
 2869 
 2870     len = suc_ie->length - del_ie->length;
 2871     //printf ("len = %d\n", len);
 2872 
 2873     for (i = del_num+1; i < del->child_count; i++)
 2874         del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] + len);
 2875 
 2876     //for (i = 0; i < del->child_count; i++)
 2877     //  printf ("Child %d %p\n", i, del->children[i]);
 2878     //printf ("\n");
 2879 
 2880     //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
 2881 
 2882     del->changed = TRUE;
 2883 
 2884     printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, del->dir->inode->mft_no, del->vcn, del->vcn + (del->dir->index_size>>9) - 1);
 2885     return TRUE;
 2886 }
 2887 
 2888 /**
 2889  * ntfs_dt_root_remove
 2890  */
 2891 static BOOL ntfs_dt_root_remove (struct ntfs_dt *del, int del_num)
 2892 {
 2893     INDEX_ENTRY *del_ie = NULL;
 2894     u8 *src;
 2895     u8 *dst;
 2896     u8 *old;
 2897     int len;
 2898     int del_len;
 2899     int i;
 2900     //int off;
 2901 
 2902     if (!del)
 2903         return FALSE;
 2904 
 2905     //utils_dump_mem (del->data, 0, del->header->index_length+16, DM_RED);
 2906     //printf ("\n");
 2907 
 2908 #if 0
 2909     off = (u8*) del->children[0] - del->data;
 2910     for (i = 0; i < del->child_count; i++) {
 2911         del_ie = del->children[i];
 2912 
 2913         printf ("%2d  %4d ", i+1, off);
 2914         off += del_ie->length;
 2915 
 2916         if (del_ie->flags & INDEX_ENTRY_END) {
 2917             printf ("END (%d)\n", del_ie->length);
 2918             break;
 2919         }
 2920 
 2921         ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length);
 2922         printf (" (%d)\n", del_ie->length);
 2923     }
 2924     printf ("total = %d\n", off);
 2925 #endif
 2926 
 2927     del_ie  = del->children[del_num];
 2928     del_len = del_ie->length;
 2929 
 2930     src = (u8*) del_ie + del_len;
 2931     dst = (u8*) del_ie;
 2932     len = del->header->index_length + 16 - (src - del->data);
 2933 
 2934     //printf ("src = %d\n", src - del->data);
 2935     //printf ("dst = %d\n", dst - del->data);
 2936     //printf ("len = %d\n", len);
 2937 
 2938     memmove (dst, src, len);
 2939 
 2940     del->data_len -= del_len;
 2941     del->child_count--;
 2942 
 2943     del->header->index_length   = del->data_len - 16;
 2944     del->header->allocated_size = del->data_len - 16;
 2945 
 2946     ntfs_mft_resize_resident (del->dir->inode, AT_INDEX_ROOT, I30, 4, del->data, del->data_len);
 2947     old = del->data;
 2948     del->data = realloc (del->data, del->data_len);
 2949     del->header = (INDEX_HEADER*) (del->data + 0x10);
 2950 
 2951     //utils_dump_mem (del->data, 0, del->data_len, DM_GREEN | DM_RED);
 2952 
 2953     src = (u8*) (&del->children[del_num+1]);
 2954     dst = (u8*) (&del->children[del_num]);
 2955     len = (del->child_count - del_num) * sizeof (INDEX_ENTRY*);
 2956 
 2957     //printf ("src = %d\n", src - (u8*) del->children);
 2958     //printf ("dst = %d\n", dst - (u8*) del->children);
 2959     //printf ("len = %d\n", len);
 2960 
 2961     memmove (dst, src, len);
 2962 
 2963     src = (u8*) (&del->sub_nodes[del_num+1]);
 2964     dst = (u8*) (&del->sub_nodes[del_num]);
 2965     len = (del->child_count - del_num) * sizeof (struct ntfs_dt*);
 2966 
 2967     //printf ("src = %d\n", src - (u8*) del->children);
 2968     //printf ("dst = %d\n", dst - (u8*) del->children);
 2969     //printf ("len = %d\n", len);
 2970 
 2971     memmove (dst, src, len);
 2972 
 2973     //printf ("del_num = %d\n", del_num);
 2974     for (i = 0; i < del->child_count; i++)
 2975         del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - old + del->data);
 2976     for (i = del_num; i < del->child_count; i++)
 2977         del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - del_len);
 2978 
 2979     if (!ntfs_dt_create_children2 (del, del->child_count))
 2980         return FALSE;
 2981 
 2982 #if 0
 2983     off = (u8*) del->children[0] - del->data;
 2984     for (i = 0; i < del->child_count; i++) {
 2985         del_ie = del->children[i];
 2986 
 2987         printf ("%2d  %4d ", i+1, off);
 2988         off += del_len;
 2989 
 2990         if (del_ie->flags & INDEX_ENTRY_END) {
 2991             printf ("END (%d)\n", del_len);
 2992             break;
 2993         }
 2994 
 2995         ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length);
 2996         printf (" (%d)\n", del_len);
 2997     }
 2998     printf ("total = %d\n", off);
 2999 #endif
 3000 
 3001     //utils_dump_mem (del->data, 0, del->header->index_length+16, DM_DEFAULTS);
 3002 
 3003     del->changed = TRUE;
 3004 
 3005     printf (GREEN "Modified: inode %lld, $INDEX_ROOT\n" END, del->dir->inode->mft_no);
 3006     return TRUE;
 3007 }
 3008 
 3009 /**
 3010  * ntfs_dt_alloc_remove
 3011  */
 3012 static BOOL ntfs_dt_alloc_remove (struct ntfs_dt *del, int del_num)
 3013 {
 3014     INDEX_ENTRY *del_ie = NULL;
 3015     u8 *dst;
 3016     u8 *src;
 3017     int len;
 3018     int i;
 3019     //int off;
 3020 
 3021     if (!del)
 3022         return FALSE;
 3023 
 3024 #if 0
 3025     off = (u8*)del->children[0] - del->data;
 3026     for (i = 0; i < del->child_count; i++) {
 3027         del_ie = del->children[i];
 3028 
 3029         printf ("%2d  %4d ", i, off);
 3030         off += del_ie->length;
 3031 
 3032         if (del_ie->flags & INDEX_ENTRY_END) {
 3033             printf ("END (%d)\n", del_ie->length);
 3034             break;
 3035         }
 3036 
 3037         ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length);
 3038         printf (" (%d)\n", del_ie->length);
 3039     }
 3040     printf ("total = %d\n", off);
 3041     printf ("\n");
 3042 #endif
 3043 
 3044     //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
 3045     //printf ("\n");
 3046 
 3047     del_ie = del->children[del_num];
 3048 
 3049     src = (u8*) del_ie + del_ie->length;
 3050     dst = (u8*) del_ie;
 3051     len = del->header->index_length + 24 - (src - del->data);
 3052 
 3053     //printf ("src = %d\n", src - del->data);
 3054     //printf ("dst = %d\n", dst - del->data);
 3055     //printf ("len = %d\n", len);
 3056 
 3057     memmove (dst, src, len);
 3058 
 3059     del->header->index_length -= src - dst;
 3060     del->child_count--;
 3061 
 3062     dst += len;
 3063     len = del->data_len - del->header->index_length - 24;
 3064 
 3065     //printf ("dst = %d\n", dst - del->data);
 3066     //printf ("len = %d\n", len);
 3067 
 3068     memset (dst, 0, len);
 3069 
 3070     src = (u8*) (&del->children[del_num+1]);
 3071     dst = (u8*) (&del->children[del_num]);
 3072     len = (del->child_count - del_num) * sizeof (INDEX_ENTRY*);
 3073 
 3074     //printf ("src = %d\n", src - (u8*) del->children);
 3075     //printf ("dst = %d\n", dst - (u8*) del->children);
 3076     //printf ("len = %d\n", len);
 3077 
 3078     memmove (dst, src, len);
 3079 
 3080     src = (u8*) (&del->sub_nodes[del_num+1]);
 3081     dst = (u8*) (&del->sub_nodes[del_num]);
 3082     len = (del->child_count - del_num) * sizeof (struct ntfs_dt*);
 3083 
 3084     //printf ("src = %d\n", src - (u8*) del->children);
 3085     //printf ("dst = %d\n", dst - (u8*) del->children);
 3086     //printf ("len = %d\n", len);
 3087 
 3088     memmove (dst, src, len);
 3089 
 3090     //printf ("del_num = %d\n", del_num);
 3091     for (i = del_num; i < del->child_count; i++)
 3092         del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - del_ie->length);
 3093 
 3094     if (!ntfs_dt_create_children2 (del, del->child_count))
 3095         return FALSE;
 3096 
 3097     //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS);
 3098 
 3099 #if 0
 3100     off = (u8*)del->children[0] - del->data;
 3101     for (i = 0; i < del->child_count; i++) {
 3102         del_ie = del->children[i];
 3103 
 3104         printf ("%2d  %4d ", i, off);
 3105         off += del_ie->length;
 3106 
 3107         if (del_ie->flags & INDEX_ENTRY_END) {
 3108             printf ("END (%d)\n", del_ie->length);
 3109             break;
 3110         }
 3111 
 3112         ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length);
 3113         printf (" (%d)\n", del_ie->length);
 3114     }
 3115     printf ("total = %d\n", off);
 3116     printf ("\n");
 3117 #endif
 3118 
 3119     del->changed = TRUE;
 3120 
 3121     printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, del->dir->inode->mft_no, del->vcn, del->vcn + (del->dir->index_size>>9) - 1);
 3122 
 3123     if (del->child_count < 2) {
 3124         printf ("indx is empty\n");
 3125         ntfs_bmp_set_range (del->dir->bitmap, del->vcn, 1, 0);
 3126     }
 3127 
 3128     return TRUE;
 3129 }
 3130 
 3131 /**
 3132  * ntfs_dt_alloc_add
 3133  */
 3134 static int ntfs_dt_alloc_add (struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child)
 3135 {
 3136     INDEX_BLOCK *block;
 3137     INDEX_ENTRY *entry;
 3138     int need;
 3139     int space;
 3140     u8 *src;
 3141     u8 *dst;
 3142     int len;
 3143 
 3144     if (!parent || !ie)
 3145         return 0;
 3146 
 3147     block = (INDEX_BLOCK*) parent->data;
 3148 
 3149     need  = ie->length;
 3150     space = parent->data_len - block->index.index_length - 24;
 3151 
 3152     printf ("need %d, have %d\n", need, space);
 3153     if (need > space) {
 3154         printf ("no room");
 3155         return 0;
 3156     }
 3157 
 3158     //utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS);
 3159     //printf ("\n");
 3160 
 3161     src = (u8*) parent->children[index_num];
 3162     dst = src + need;
 3163     len = parent->data + parent->data_len - src - space;
 3164     //printf ("src = %d\n", src - parent->data);
 3165     //printf ("dst = %d\n", dst - parent->data);
 3166     //printf ("len = %d\n", len);
 3167 
 3168     memmove (dst, src, len);
 3169 
 3170     dst = src;
 3171     src = (u8*) ie;
 3172     len = need;
 3173 
 3174     memcpy (dst, src, len);
 3175 
 3176     block->index.index_length += len;
 3177 
 3178     dst = parent->data + block->index.index_length + 24;
 3179     len = parent->data_len - block->index.index_length - 24;
 3180 
 3181     memset (dst, 0, len);
 3182 
 3183     //realloc children, sub_nodes
 3184     ntfs_dt_create_children2 (parent, parent->child_count + 1);
 3185 
 3186     // regen children pointers
 3187     parent->child_count = 0;
 3188 
 3189     src = parent->data     + 0x18 + parent->header->entries_offset;
 3190     len = parent->data_len - 0x18 - parent->header->entries_offset;
 3191 
 3192     while (src < (parent->data + parent->data_len)) {
 3193         entry = (INDEX_ENTRY*) src;
 3194 
 3195         parent->children[parent->child_count] = entry;
 3196         parent->child_count++;
 3197 
 3198         if (entry->flags & INDEX_ENTRY_END)
 3199             break;
 3200 
 3201         src += entry->length;
 3202     }
 3203     printf ("count = %d\n", parent->child_count);
 3204 
 3205     src = (u8*) &parent->sub_nodes[index_num+parent->child_count-1];
 3206     dst = (u8*) &parent->sub_nodes[index_num];
 3207     len = (parent->child_count - index_num - 1) * sizeof (struct ntfs_dt*);
 3208 
 3209     memmove (dst, src, len);
 3210 
 3211     //insert sub_node pointer
 3212     parent->sub_nodes[index_num] = child;
 3213 
 3214     //utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS);
 3215     //printf ("\n");
 3216     return 0;
 3217 }
 3218 
 3219 /**
 3220  * ntfs_dt_root_add
 3221  */
 3222 static int ntfs_dt_root_add (struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child)
 3223 {
 3224     INDEX_ROOT *root;
 3225     INDEX_ENTRY *entry;
 3226     int need;
 3227     int space;
 3228     u8 *attr;
 3229     u8 *src;
 3230     u8 *dst;
 3231     int len;
 3232 
 3233     if (!parent || !ie)
 3234         return 0;
 3235 
 3236     root = (INDEX_ROOT*) parent->data;
 3237 
 3238     utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS);
 3239     printf ("\n");
 3240 
 3241     need  = ie->length;
 3242     space = ntfs_mft_free_space (parent->dir);
 3243 
 3244     printf ("need %d, have %d\n", need, space);
 3245     if (need > space) {
 3246         printf ("no room");
 3247         return 0;
 3248     }
 3249 
 3250     attr = malloc (parent->data_len + need);
 3251 
 3252     src = parent->data;
 3253     dst = attr;
 3254     len = root->index.entries_offset + 16;
 3255 
 3256     memcpy (dst, src, len);
 3257 
 3258     dst += len;
 3259     src = (u8*) ie;
 3260     len = ie->length;
 3261 
 3262     memcpy (dst, src, len);
 3263 
 3264     dst += len;
 3265     src = (u8*) parent->children[index_num];
 3266     len = parent->data + parent->data_len - src;
 3267 
 3268     memcpy (dst, src, len);
 3269 
 3270     free (parent->data);
 3271     parent->data = attr;
 3272     parent->data_len += need;
 3273 
 3274     root = (INDEX_ROOT*) parent->data;
 3275     root->index.index_length   = parent->data_len - 16;
 3276     root->index.allocated_size = parent->data_len - 16;
 3277 
 3278     utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS);
 3279     printf ("\n");
 3280 
 3281     ntfs_mft_resize_resident (parent->dir->inode, AT_INDEX_ROOT, I30, 4, parent->data, parent->data_len);
 3282 
 3283     //realloc children, sub_nodes
 3284     ntfs_dt_create_children2 (parent, parent->child_count + 1);
 3285 
 3286     // regen children pointers
 3287     parent->child_count = 0;
 3288 
 3289     src = parent->data     + 0x18 + parent->header->entries_offset;
 3290     len = parent->data_len - 0x18 - parent->header->entries_offset;
 3291 
 3292     // XXX can we rebase the children more simply? (in alloc_add too)
 3293     while (src < (parent->data + parent->data_len)) {
 3294         entry = (INDEX_ENTRY*) src;
 3295 
 3296         parent->children[parent->child_count] = entry;
 3297         parent->child_count++;
 3298 
 3299         if (entry->flags & INDEX_ENTRY_END)
 3300             break;
 3301 
 3302         src += entry->length;
 3303     }
 3304     printf ("count = %d\n", parent->child_count);
 3305 
 3306     src = (u8*) &parent->sub_nodes[index_num+parent->child_count-1];
 3307     dst = (u8*) &parent->sub_nodes[index_num];
 3308     len = (parent->child_count - index_num - 1) * sizeof (struct ntfs_dt*);
 3309 
 3310     memmove (dst, src, len);
 3311 
 3312     //insert sub_node pointer
 3313     parent->sub_nodes[index_num] = child;
 3314 
 3315     return 0;
 3316 }
 3317 
 3318 /**
 3319  * ntfs_dt_add2
 3320  */
 3321 static int ntfs_dt_add2 (INDEX_ENTRY *ie, struct ntfs_dt *suc, int suc_num, struct ntfs_dt *ded)
 3322 {
 3323     int need;
 3324     int space;
 3325     int median;
 3326     struct ntfs_dt *new = NULL;
 3327     struct ntfs_dt *chl;
 3328     INDEX_ENTRY *med_ie = NULL;
 3329     //FILE_NAME_ATTR *file;
 3330     VCN vcn = 0;
 3331     //int i;
 3332 
 3333     if (!ie || !suc)
 3334         return -1;
 3335 
 3336     printf ("\n");
 3337     printf (BOLD YELLOW "Add key to leaf\n" END);
 3338 
 3339     //utils_dump_mem (suc->data, 0, suc->data_len, DM_DEFAULTS);
 3340 
 3341     chl = NULL;
 3342 ascend:
 3343     //XXX replace with while/break?
 3344 
 3345 #if 0
 3346     for (; ded; ded = ded->sub_nodes[0]) {
 3347         printf ("\tded vcn = %lld\n", ded->vcn);
 3348     }
 3349 #endif
 3350 
 3351     /*
 3352      * ADD
 3353      * room in current node?
 3354      *   yes, add, done
 3355      *   no, split, ascend
 3356      */
 3357     need = ie->length;
 3358 
 3359     if (ntfs_dt_isroot (suc))
 3360         space = ntfs_dt_root_freespace (suc);
 3361     else
 3362         space = ntfs_dt_alloc_freespace (suc);
 3363 
 3364     printf ("\tneed %d\n", need);
 3365     printf ("\tspace %d\n", space);
 3366 
 3367     if (space >= need) {
 3368         if (ntfs_dt_isroot (suc))
 3369             ntfs_dt_root_add (suc, suc_num, ie, chl);
 3370         else
 3371             ntfs_dt_alloc_add (suc, suc_num, ie, chl);
 3372         goto done;
 3373     }
 3374 
 3375     /*
 3376      * SPLIT
 3377      * any dead?
 3378      *   yes reuse
 3379      *   no alloc
 3380      */
 3381     if (ded) {
 3382         new = ded;
 3383         vcn = ded->vcn;
 3384         ded = ded->sub_nodes[0];
 3385         printf ("\treusing vcn %lld\n", new->vcn);
 3386     } else {
 3387         ntfs_mft_add_index (suc->dir);
 3388         /*
 3389          * ALLOC
 3390          * any unused records?
 3391          *   yes, enable first
 3392          *   no, extend
 3393          */
 3394         /*
 3395          * ENABLE
 3396          * modify bitmap
 3397          * init indx record
 3398          */
 3399         /*
 3400          * EXTEND
 3401          * room in bitmap
 3402          *   yes, do nothing
 3403          *   no, extend bitmap
 3404          * extend alloc
 3405          */
 3406         /*
 3407          * EXTEND BITMAP
 3408          * extend bitmap
 3409          * init bitmap
 3410          */
 3411     }
 3412 
 3413     //printf ("\tnode has %d children\n", suc->child_count);
 3414 
 3415     // initialise new node
 3416     // XXX ntfs_dt_initialise (new, vcn);
 3417 
 3418     goto done;
 3419 
 3420     // find median key
 3421     median = (suc->child_count+1) / 2;
 3422     med_ie = ntfs_ie_copy (suc->children[median]);
 3423     //file = &med_ie->key.file_name; printf ("\tmed name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 3424 
 3425     ntfs_ie_free (med_ie);
 3426     med_ie = NULL;
 3427 
 3428     //printf ("suc key count = %d\n", suc->child_count);
 3429     //printf ("new key count = %d\n", new->child_count);
 3430 
 3431     //printf ("median's child = %p\n", suc->sub_nodes[median]);
 3432     // need to pass the child when ascending
 3433     chl = suc->sub_nodes[median];
 3434 
 3435     // transfer keys
 3436     if (ntfs_dt_transfer (suc, new, 0, median-1) < 0)
 3437         goto done;
 3438 
 3439     //printf ("suc key count = %d\n", suc->child_count);
 3440     //printf ("new key count = %d\n", new->child_count);
 3441 
 3442     //file = &suc->children[0]->key.file_name; printf ("\tmed name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 3443 
 3444     // can this be a root node?
 3445     if (ntfs_dt_isroot (suc))
 3446         ntfs_dt_root_remove (suc, 0);
 3447     else
 3448         ntfs_dt_alloc_remove (suc, 0);
 3449 
 3450     //file = &suc->children[0]->key.file_name; printf ("\tmed name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 3451     //printf ("suc key count = %d\n", suc->child_count);
 3452     //printf ("new key count = %d\n", new->child_count);
 3453 
 3454     // remove the median key
 3455 
 3456     // split when median has children
 3457     // median child given to new !
 3458     // median child is new
 3459     // ascend
 3460 
 3461     med_ie = ntfs_ie_set_vcn (med_ie, new->vcn);
 3462     if (!med_ie)
 3463         goto done;
 3464 
 3465     //printf ("median child = %lld\n", ntfs_ie_get_vcn (med_ie));
 3466     //printf ("new's vcn    = %lld\n", new->vcn);
 3467 
 3468     // adjust parents
 3469     //  attach new to median
 3470     // escape clause for root node?
 3471     // goto ascend
 3472 
 3473     // ie = insert
 3474     // child = child
 3475     // suc = successor
 3476     // suc_num = insert point
 3477 
 3478     ie = med_ie;
 3479     suc = suc->parent;
 3480     suc_num = 0;
 3481 
 3482     printf ("\n");
 3483     printf (BOLD YELLOW "Ascend\n" END);
 3484     goto ascend;
 3485 done:
 3486     return 0;
 3487 }
 3488 
 3489 
 3490 /**
 3491  * ntfs_dir_rollback
 3492  */
 3493 static int ntfs_dir_rollback (struct ntfs_dir *dir)
 3494 {
 3495     int i;
 3496 
 3497     if (!dir)
 3498         return -1;
 3499 
 3500     if (ntfs_dt_rollback (dir->index) < 0)
 3501         return -1;
 3502 
 3503     if (ntfs_bmp_rollback (dir->bitmap) < 0)
 3504         return -1;
 3505 
 3506     for (i = 0; i < dir->child_count; i++) {
 3507         if (ntfs_dir_rollback (dir->children[i]) < 0)
 3508             return -1;
 3509     }
 3510 
 3511     return 0;
 3512 }
 3513 
 3514 /**
 3515  * ntfs_dir_truncate
 3516  */
 3517 static int ntfs_dir_truncate (ntfs_volume *vol, struct ntfs_dir *dir)
 3518 {
 3519     //int i;
 3520     //u8 *buffer;
 3521     //int buf_count;
 3522     s64 last_bit;
 3523     INDEX_ENTRY *ie;
 3524 
 3525     if (!vol || !dir)
 3526         return -1;
 3527 
 3528     if ((dir->ialloc == NULL) || (dir->bitmap == NULL))
 3529         return 0;
 3530 
 3531 #if 0
 3532     buf_count = ROUND_UP (dir->bitmap->attr->allocated_size, vol->cluster_size) >> vol->cluster_size_bits;
 3533     printf ("alloc = %lld bytes\n", dir->ialloc->allocated_size);
 3534     printf ("alloc = %lld clusters\n", dir->ialloc->allocated_size >> vol->cluster_size_bits);
 3535     printf ("bitmap bytes 0 to %lld\n", ((dir->ialloc->allocated_size >> vol->cluster_size_bits)-1)>>3);
 3536     printf ("bitmap = %p\n", dir->bitmap);
 3537     printf ("bitmap = %lld bytes\n", dir->bitmap->attr->allocated_size);
 3538     printf ("bitmap = %d buffers\n", buf_count);
 3539 #endif
 3540 
 3541     last_bit = ntfs_bmp_find_last_set (dir->bitmap);
 3542     if (dir->ialloc->allocated_size == (dir->index_size * (last_bit + 1))) {
 3543         //printf ("nothing to do\n");
 3544         return 0;
 3545     }
 3546 
 3547     printf (BOLD YELLOW "Truncation needed\n" END);
 3548 
 3549 #if 0
 3550     printf ("\tlast bit = %lld\n", last_bit);
 3551     printf ("\tactual IALLOC size = %lld\n", dir->ialloc->allocated_size);
 3552     printf ("\tshould IALLOC size = %lld\n", dir->index_size * (last_bit + 1));
 3553 #endif
 3554 
 3555     if ((dir->index_size * (last_bit + 1)) == 0) {
 3556         printf ("root dt %d, vcn = %lld\n", dir->index->changed, dir->index->vcn);
 3557         //rollback all dts
 3558         //ntfs_dt_rollback (dir->index);
 3559         //dir->index = NULL;
 3560         // What about the ROOT dt?
 3561 
 3562         ie = ntfs_ie_copy (dir->index->children[0]);
 3563         if (!ie) {
 3564             printf (RED "IE copy failed\n" END);
 3565             return -1;
 3566         }
 3567 
 3568         ie = ntfs_ie_remove_vcn (ie);
 3569         if (!ie) {
 3570             printf (RED "IE remove vcn failed\n" END);
 3571             return -1;
 3572         }
 3573 
 3574         //utils_dump_mem (dir->index->data, 0, dir->index->data_len, DM_DEFAULTS); printf ("\n");
 3575         //utils_dump_mem (ie, 0, ie->length, DM_DEFAULTS); printf ("\n");
 3576         ntfs_dt_root_replace (dir->index, 0, dir->index->children[0], ie);
 3577         //utils_dump_mem (dir->index->data, 0, dir->index->data_len, DM_DEFAULTS); printf ("\n");
 3578         //printf ("root dt %d, vcn = %lld\n", dir->index->changed, dir->index->vcn);
 3579 
 3580         ntfs_ie_free (ie);
 3581         ie = NULL;
 3582 
 3583         //index flags remove LARGE_INDEX
 3584         dir->index->header->flags = 0;
 3585 
 3586         //rollback dir's bmp
 3587         ntfs_bmp_free (dir->bitmap);
 3588         dir->bitmap = NULL;
 3589 
 3590         /*
 3591         for (i = 0; i < dir->index->child_count; i++) {
 3592             ntfs_dt_rollback (dir->index->sub_nodes[i]);
 3593             dir->index->sub_nodes[i] = NULL;
 3594         }
 3595         */
 3596 
 3597         //printf ("dir->index->inodes[0] = %p\n", dir->index->inodes[0]);
 3598 
 3599         //remove 0xA0 attribute
 3600         ntfs_mft_remove_attr (vol->private_bmp2, dir->inode, AT_INDEX_ALLOCATION);
 3601 
 3602         //remove 0xB0 attribute
 3603         ntfs_mft_remove_attr (vol->private_bmp2, dir->inode, AT_BITMAP);
 3604     } else {
 3605         printf (RED "Cannot shrink directory\n" END);
 3606         //ntfs_dir_shrink_alloc
 3607         //ntfs_dir_shrink_bitmap
 3608         //make bitmap resident?
 3609     }
 3610 
 3611     /*
 3612      * Remove
 3613      *   dt -> dead
 3614      *   bitmap updated
 3615      *   rollback dead dts
 3616      *   commit bitmap
 3617      *   commit dts
 3618      *   commit dir
 3619      */
 3620     /*
 3621      * Reuse
 3622      *   search for lowest dead
 3623      *   update bitmap
 3624      *   init dt
 3625      *   remove from dead
 3626      *   insert into tree
 3627      *   init INDX
 3628      */
 3629 
 3630 #if 0
 3631     buffer = ntfs_bmp_get_data (dir->bitmap, 0);
 3632     if (!buffer)
 3633         return -1;
 3634 
 3635     utils_dump_mem (buffer, 0, 8, DM_NO_ASCII);
 3636     for (i = buf_count-1; i >= 0; i--) {
 3637         if (buffer[i]) {
 3638             printf ("alloc in use\n");
 3639             return 0;
 3640         }
 3641     }
 3642 #endif
 3643 
 3644     // <dir>/$BITMAP($I30)
 3645     // <dir>/$INDEX_ALLOCATION($I30)
 3646     // $Bitmap
 3647 
 3648     // Find the highest set bit in the directory bitmap
 3649     // can we free any clusters of the alloc?
 3650     // if yes, resize attribute
 3651 
 3652     // Are *any* bits set?
 3653     // If not remove ialloc
 3654 
 3655     return 0;
 3656 }
 3657 
 3658 /**
 3659  * ntfs_dir_commit
 3660  */
 3661 static int ntfs_dir_commit (struct ntfs_dir *dir)
 3662 {
 3663     int i;
 3664 
 3665     if (!dir)
 3666         return 0;
 3667 
 3668     printf ("commit dir inode %llu\n", dir->inode->mft_no);
 3669     if (NInoDirty (dir->inode)) {
 3670 #ifdef RM_WRITE
 3671         ntfs_inode_sync (dir->inode);
 3672 #endif
 3673         printf (RED "\tntfs_inode_sync %llu\n" END, dir->inode->mft_no);
 3674     }
 3675 
 3676     if (ntfs_dt_commit (dir->index) < 0)
 3677         return -1;
 3678 
 3679     if (ntfs_bmp_commit (dir->bitmap) < 0)
 3680         return -1;
 3681 
 3682     for (i = 0; i < dir->child_count; i++) {
 3683         if (ntfs_dir_commit (dir->children[i]) < 0)
 3684             return -1;
 3685     }
 3686 
 3687     return 0;
 3688 }
 3689 
 3690 /**
 3691  * ntfs_dir_free
 3692  */
 3693 static void ntfs_dir_free (struct ntfs_dir *dir)
 3694 {
 3695     struct ntfs_dir *parent;
 3696     int i;
 3697 
 3698     if (!dir)
 3699         return;
 3700 
 3701     ntfs_dir_rollback (dir);
 3702 
 3703     parent = dir->parent;
 3704     if (parent) {
 3705         for (i = 0; i < parent->child_count; i++) {
 3706             if (parent->children[i] == dir) {
 3707                 parent->children[i] = NULL;
 3708             }
 3709         }
 3710     }
 3711 
 3712     ntfs_attr_close (dir->iroot);
 3713     ntfs_attr_close (dir->ialloc);
 3714     ntfs_inode_close2 (dir->inode);
 3715 
 3716     ntfs_dt_free  (dir->index);
 3717     ntfs_bmp_free (dir->bitmap);
 3718 
 3719     for (i = 0; i < dir->child_count; i++)
 3720         ntfs_dir_free (dir->children[i]);
 3721 
 3722     free (dir->name);
 3723     free (dir->children);
 3724     free (dir);
 3725 }
 3726 
 3727 /**
 3728  * ntfs_dir_create
 3729  */
 3730 static struct ntfs_dir * ntfs_dir_create (ntfs_volume *vol, MFT_REF mft_num)
 3731 {
 3732     struct ntfs_dir *dir   = NULL;
 3733     ntfs_inode      *inode = NULL;
 3734     ATTR_RECORD     *rec   = NULL;
 3735     INDEX_ROOT      *ir    = NULL;
 3736     FILE_NAME_ATTR  *name  = NULL;
 3737 
 3738     if (!vol)
 3739         return NULL;
 3740 
 3741     //printf ("ntfs_dir_create %lld\n", MREF (mft_num));
 3742     inode = ntfs_inode_open2 (vol, mft_num);
 3743     if (!inode)
 3744         return NULL;
 3745 
 3746     dir = calloc (1, sizeof (*dir));
 3747     if (!dir) {
 3748         ntfs_inode_close2 (inode);
 3749         return NULL;
 3750     }
 3751 
 3752     dir->inode  = inode;
 3753     dir->iroot  = ntfs_attr_open (inode, AT_INDEX_ROOT,       I30, 4);
 3754     dir->ialloc = ntfs_attr_open (inode, AT_INDEX_ALLOCATION, I30, 4);
 3755 
 3756     if (!dir->iroot) {
 3757         ntfs_dir_free (dir);
 3758         return NULL;
 3759     }
 3760 
 3761     dir->vol      = vol;
 3762     dir->parent   = NULL;
 3763     dir->name     = NULL;
 3764     dir->name_len     = 0;
 3765     dir->index    = NULL;
 3766     dir->children     = NULL;
 3767     dir->child_count  = 0;
 3768     dir->mft_num      = mft_num;
 3769 
 3770     // This may not exist
 3771     dir->bitmap = ntfs_bmp_create (inode, AT_BITMAP, I30, 4);
 3772 
 3773     if (dir->iroot) {
 3774         rec = find_first_attribute (AT_INDEX_ROOT, inode->mrec);
 3775         ir  = (INDEX_ROOT*) ((u8*)rec + rec->value_offset);
 3776         dir->index_size = ir->index_block_size;
 3777     } else {
 3778         // XXX !iroot?
 3779         dir->index_size = 0;
 3780     }
 3781 
 3782     // Finally, find the dir's name
 3783     rec = find_first_attribute (AT_FILE_NAME, inode->mrec);
 3784     name = (FILE_NAME_ATTR*) ((u8*)rec + rec->value_offset);
 3785 
 3786     dir->name_len = name->file_name_length;
 3787     dir->name = malloc (sizeof (ntfschar) * dir->name_len);
 3788     memcpy (dir->name, name->file_name, sizeof (ntfschar) * dir->name_len);
 3789 
 3790     return dir;
 3791 }
 3792 
 3793 /**
 3794  * ntfs_dir_add
 3795  */
 3796 static void ntfs_dir_add (struct ntfs_dir *parent, struct ntfs_dir *child)
 3797 {
 3798     if (!parent || !child)
 3799         return;
 3800 
 3801     parent->child_count++;
 3802     //printf ("child count = %d\n", parent->child_count);
 3803     parent->children = realloc (parent->children, parent->child_count * sizeof (struct ntfs_dir*));
 3804     child->parent = parent;
 3805 
 3806     parent->children[parent->child_count-1] = child;
 3807 }
 3808 
 3809 /**
 3810  * ntfs_dir_find2
 3811  */
 3812 static struct ntfs_dir * ntfs_dir_find2 (struct ntfs_dir *dir, ntfschar *name, int name_len)
 3813 {
 3814     int i;
 3815     struct ntfs_dir *child = NULL;
 3816     struct ntfs_dt *dt = NULL;
 3817     int dt_num = 0;
 3818     INDEX_ENTRY *ie;
 3819     MFT_REF mft_num;
 3820 
 3821     if (!dir || !name)
 3822         return NULL;
 3823 
 3824     if (!dir->index) {  // XXX when will this happen?
 3825         printf ("ntfs_dir_find2 - directory has no index\n");
 3826         return NULL;
 3827     }
 3828 
 3829     for (i = 0; i < dir->child_count; i++) {
 3830         if (0 == ntfs_names_collate (name, name_len,
 3831                     dir->children[i]->name,
 3832                     dir->children[i]->name_len,
 3833                     2, IGNORE_CASE,
 3834                     dir->vol->upcase,
 3835                     dir->vol->upcase_len))
 3836             return dir->children[i];
 3837     }
 3838 
 3839     dt = ntfs_dt_find2 (dir->index, name, name_len, &dt_num);
 3840     if (!dt) {
 3841         printf ("can't find name in dir\n");
 3842         return NULL;
 3843     }
 3844 
 3845     ie = dt->children[dt_num];
 3846 
 3847     mft_num = ie->indexed_file;
 3848 
 3849     child = ntfs_dir_create (dir->vol, mft_num);
 3850     if (!child)
 3851         return NULL;
 3852 
 3853     child->index = ntfs_dt_create (child, NULL, -1);
 3854 
 3855     ntfs_dir_add (dir, child);
 3856 
 3857     return child;
 3858 }
 3859 
 3860 
 3861 /**
 3862  * ntfs_volume_commit
 3863  */
 3864 static int ntfs_volume_commit (ntfs_volume *vol)
 3865 {
 3866     if (!vol)
 3867         return -1;
 3868 
 3869     printf ("commit volume\n");
 3870     if (ntfs_bmp_commit (vol->private_bmp1) < 0)
 3871         return -1;
 3872 
 3873     if (ntfs_bmp_commit (vol->private_bmp2) < 0)
 3874         return -1;
 3875 
 3876     if (ntfs_dir_commit (vol->private_data) < 0)
 3877         return -1;
 3878 
 3879     return 0;
 3880 }
 3881 
 3882 /**
 3883  * ntfs_volume_rollback
 3884  */
 3885 static int ntfs_volume_rollback (ntfs_volume *vol)
 3886 {
 3887     if (!vol)
 3888         return -1;
 3889 
 3890     if (ntfs_bmp_rollback (vol->private_bmp1) < 0)
 3891         return -1;
 3892 
 3893     if (ntfs_bmp_rollback (vol->private_bmp2) < 0)
 3894         return -1;
 3895 
 3896     if (ntfs_dir_rollback (vol->private_data) < 0)
 3897         return -1;
 3898 
 3899     return 0;
 3900 }
 3901 
 3902 /**
 3903  * ntfs_volume_umount2
 3904  */
 3905 static int ntfs_volume_umount2 (ntfs_volume *vol, const BOOL force)
 3906 {
 3907     struct ntfs_dir *dir;
 3908     struct ntfs_bmp *bmp;
 3909 
 3910     if (!vol)
 3911         return 0;
 3912 
 3913     ntfs_volume_rollback (vol);
 3914 
 3915     dir = (struct ntfs_dir *) vol->private_data;
 3916     vol->private_data = NULL;
 3917     ntfs_dir_free (dir);
 3918 
 3919     bmp = (struct ntfs_bmp *) vol->private_bmp1;
 3920     vol->private_bmp1 = NULL;
 3921     ntfs_bmp_free (bmp);
 3922 
 3923     bmp = (struct ntfs_bmp *) vol->private_bmp2;
 3924     vol->private_bmp2 = NULL;
 3925     ntfs_bmp_free (bmp);
 3926 
 3927     return ntfs_umount (vol, force);
 3928 }
 3929 
 3930 /**
 3931  * ntfs_volume_mount2
 3932  */
 3933 static ntfs_volume * ntfs_volume_mount2 (const char *device, unsigned long flags, BOOL force)
 3934 {
 3935     // XXX can we replace these and search by mft number?  Hmm... NO.
 3936     // unless I have a recursive search for an MFT number
 3937     static ntfschar bmp[8] = {
 3938         const_cpu_to_le16('$'),
 3939         const_cpu_to_le16('B'),
 3940         const_cpu_to_le16('i'),
 3941         const_cpu_to_le16('t'),
 3942         const_cpu_to_le16('m'),
 3943         const_cpu_to_le16('a'),
 3944         const_cpu_to_le16('p'),
 3945         const_cpu_to_le16(0)
 3946     };
 3947 
 3948     static ntfschar mft[5] = {
 3949         const_cpu_to_le16('$'),
 3950         const_cpu_to_le16('M'),
 3951         const_cpu_to_le16('F'),
 3952         const_cpu_to_le16('T'),
 3953         const_cpu_to_le16(0)
 3954     };
 3955 
 3956     static ntfschar mftmirr[9] = {
 3957         const_cpu_to_le16('$'),
 3958         const_cpu_to_le16('M'),
 3959         const_cpu_to_le16('F'),
 3960         const_cpu_to_le16('T'),
 3961         const_cpu_to_le16('M'),
 3962         const_cpu_to_le16('i'),
 3963         const_cpu_to_le16('r'),
 3964         const_cpu_to_le16('r'),
 3965         const_cpu_to_le16(0)
 3966     };
 3967 
 3968     static ntfschar dot[2] = {
 3969         const_cpu_to_le16('.'),
 3970         const_cpu_to_le16(0)
 3971     };
 3972 
 3973     ntfs_volume *vol;
 3974     struct ntfs_dir *dir;
 3975     struct ntfs_dt *root;
 3976     struct ntfs_dt *found;
 3977     int num;
 3978 
 3979     vol = utils_mount_volume (device, flags, force);
 3980     if (!vol)
 3981         return NULL;
 3982 
 3983     vol->lcnbmp_ni ->ref_count = 1;
 3984     vol->mft_ni    ->ref_count = 1;
 3985     vol->mftmirr_ni->ref_count = 1;
 3986 
 3987     vol->lcnbmp_ni ->private_data = NULL;
 3988     vol->mft_ni    ->private_data = NULL;
 3989     vol->mftmirr_ni->private_data = NULL;
 3990 
 3991     dir = ntfs_dir_create (vol, FILE_root);
 3992     if (!dir) {
 3993         ntfs_volume_umount2 (vol, FALSE);
 3994         vol = NULL;
 3995         goto done;
 3996     }
 3997 
 3998     dir->index = ntfs_dt_create (dir, NULL, -1);
 3999 
 4000     root = dir->index;
 4001 
 4002     //$Bitmap
 4003     num = -1;
 4004     found = ntfs_dt_find2 (root, bmp, sizeof (bmp) - 1, &num);
 4005     if ((!found) || (num < 0)) {
 4006         printf ("can't find $Bitmap\n");
 4007         ntfs_volume_umount2 (vol, FALSE);
 4008         vol = NULL;
 4009         goto done;
 4010     }
 4011     vol->lcnbmp_ni->ref_count++;
 4012     vol->lcnbmp_ni->private_data = found->dir;
 4013     found->inodes[num] = vol->lcnbmp_ni;
 4014 
 4015     //$MFT
 4016     num = -1;
 4017     found = ntfs_dt_find2 (root, mft, sizeof (mft) - 1, &num);
 4018     if ((!found) || (num < 0)) {
 4019         printf ("can't find $MFT\n");
 4020         ntfs_volume_umount2 (vol, FALSE);
 4021         vol = NULL;
 4022         goto done;
 4023     }
 4024     vol->mft_ni->ref_count++;
 4025     vol->mft_ni->private_data = found->dir;
 4026     found->inodes[num] = vol->mft_ni;
 4027 
 4028     //$MFTMirr
 4029     num = -1;
 4030     found = ntfs_dt_find2 (root, mftmirr, sizeof (mftmirr) - 1, &num);
 4031     if ((!found) || (num < 0)) {
 4032         printf ("can't find $MFTMirr\n");
 4033         ntfs_volume_umount2 (vol, FALSE);
 4034         vol = NULL;
 4035         goto done;
 4036     }
 4037     vol->mftmirr_ni->ref_count++;
 4038     vol->mftmirr_ni->private_data = found->dir;
 4039     found->inodes[num] = vol->mftmirr_ni;
 4040 
 4041     // root directory
 4042     num = -1;
 4043     found = ntfs_dt_find2 (root, dot, 1, &num);
 4044     if ((!found) || (num < 0)) {
 4045         printf ("can't find the root directory\n");
 4046         ntfs_volume_umount2 (vol, FALSE);
 4047         vol = NULL;
 4048         goto done;
 4049     }
 4050 
 4051     vol->private_data = found->dir;
 4052     found->inodes[num] = dir->inode;
 4053     dir->inode->private_data = found;
 4054     dir->inode->ref_count = 2;
 4055 
 4056     vol->private_bmp1 = ntfs_bmp_create (vol->mft_ni,    AT_BITMAP, NULL, 0);
 4057     vol->private_bmp2 = ntfs_bmp_create (vol->lcnbmp_ni, AT_DATA,   NULL, 0);
 4058 
 4059     if (!vol->private_bmp1 || !vol->private_bmp2) {
 4060         printf ("can't find the bitmaps\n");
 4061         ntfs_volume_umount2 (vol, FALSE);
 4062         vol = NULL;
 4063         goto done;
 4064     }
 4065 
 4066 done:
 4067     return vol;
 4068 }
 4069 
 4070 /**
 4071  * utils_pathname_to_inode2
 4072  */
 4073 static BOOL utils_pathname_to_inode2 (ntfs_volume *vol, struct ntfs_dir *parent, const char *pathname, struct ntfs_find *found)
 4074 {
 4075     int len;
 4076     char *p, *q;
 4077     ntfschar *unicode = NULL;
 4078     char *ascii = NULL;
 4079     struct ntfs_dir *dir = NULL;
 4080     struct ntfs_dir *child = NULL;
 4081     struct ntfs_dt *dt = NULL;
 4082     int dt_num;
 4083     BOOL result = FALSE;
 4084 
 4085     if (!vol || !pathname || !found) {
 4086         errno = EINVAL;
 4087         return FALSE;
 4088     }
 4089 
 4090     memset (found, 0, sizeof (*found));
 4091 
 4092     if (parent) {
 4093         dir = parent;
 4094     } else {
 4095         dir = (struct ntfs_dir *) vol->private_data;
 4096         if (!dir) {
 4097             Eprintf ("Couldn't open the inode of the root directory.\n");
 4098             goto close;
 4099         }
 4100     }
 4101 
 4102     unicode = malloc (MAX_PATH * sizeof (ntfschar));
 4103     ascii   = strdup (pathname);        // Work with a r/w copy
 4104     if (!unicode || !ascii) {
 4105         Eprintf ("Out of memory.\n");
 4106         goto close;
 4107     }
 4108 
 4109     p = ascii;
 4110     while (p && *p && *p == PATH_SEP)   // Remove leading /'s
 4111         p++;
 4112     while (p && *p) {
 4113         q = strchr (p, PATH_SEP);   // Find the end of the first token
 4114         if (q != NULL) {
 4115             *q = '\0';
 4116             q++;
 4117         }
 4118 
 4119         len = ntfs_mbstoucs (p, &unicode, MAX_PATH);
 4120         if (len < 0) {
 4121             Eprintf ("Couldn't convert name to Unicode: %s.\n", p);
 4122             goto close;
 4123         }
 4124 
 4125         //printf ("looking for %s in dir %lld\n", p, MREF (dir->mft_num));
 4126         //printf ("dir: index = %p, children = %p, inode = %p, iroot = %p, ialloc = %p, count = %d\n", dir->index, dir->children, dir->inode, dir->iroot, dir->ialloc, dir->child_count);
 4127         //if (dir->parent)
 4128         if (q) {
 4129             child = ntfs_dir_find2 (dir, unicode, len);
 4130             if (!child) {
 4131                 printf ("can't find %s in %s\n", p, pathname);
 4132                 goto close;
 4133             }
 4134         } else {
 4135             //printf ("file: %s\n", p);
 4136 
 4137             dt = ntfs_dt_find2 (dir->index, unicode, len, &dt_num);
 4138             if (!dt) {
 4139                 printf ("can't find %s in %s (2)\n", p, pathname);
 4140                 goto close;
 4141             }
 4142 
 4143             //printf ("dt's flags = 0x%08x\n", dt->children[dt_num]->key.file_name.file_attributes);
 4144             if (dt->children[dt_num]->key.file_name.file_attributes == FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT) {
 4145                 //printf ("DIR\n");
 4146                 child = ntfs_dir_create (dir->vol, dt->children[dt_num]->indexed_file);
 4147                 //printf ("child = %p (%lld)\n", child, MREF (dt->children[dt_num]->indexed_file));
 4148                 if (child) {
 4149                     child->index = ntfs_dt_create (child, NULL, -1);
 4150                     ntfs_dir_add (dir, child);
 4151                 }
 4152 
 4153             }
 4154 
 4155             if (dt->inodes[dt_num] == NULL) {
 4156                 dt->inodes[dt_num] = ntfs_inode_open (dir->vol, dt->children[dt_num]->indexed_file);
 4157                 if (!dt->inodes[dt_num]) {
 4158                     printf ("Can't open inode %lld\n", MREF (dt->children[dt_num]->indexed_file));
 4159                     goto close;
 4160                 }
 4161                 dt->inodes[dt_num]->ref_count = 2;
 4162                 dt->inodes[dt_num]->private_data = dt;
 4163             }
 4164 
 4165             //printf ("dt = %p,%d\n", dt, dt_num);
 4166             break;
 4167         }
 4168 
 4169         dir   = child;
 4170         child = NULL;
 4171         p = q;
 4172         while (p && *p && *p == PATH_SEP)
 4173             p++;
 4174     }
 4175 
 4176     found->dir      = dir;
 4177     found->dt       = dt;
 4178     found->dt_index = dt_num;
 4179     found->inode    = dt->inodes[dt_num];
 4180     found->mref     = found->inode->mft_no;
 4181     result = TRUE;
 4182     //printf ("dir %p, dt %p, num %d, ino %p, %lld\n", dir, dt, dt_num, dt->inodes[dt_num], MREF (found->inode->mft_no));
 4183 close:
 4184     free (ascii);   // from strdup
 4185     free (unicode);
 4186     return result;
 4187 }
 4188 
 4189 
 4190 /**
 4191  * ntfs_mft_find_free_entry
 4192  */
 4193 static s64 ntfs_mft_find_free_entry (ntfs_volume *vol)
 4194 {
 4195     MFT_REF i;
 4196     u64 recs;
 4197 
 4198     if (!vol)
 4199         return -1;
 4200 
 4201     recs = vol->mft_na->initialized_size >> vol->mft_record_size_bits;
 4202     //printf ("mft contains %lld records\n", recs);
 4203     for (i = 24; i < recs; i++) {
 4204         if (utils_mftrec_in_use (vol, i) == 0)
 4205             return i;
 4206     }
 4207     return -1;
 4208 }
 4209 
 4210 /**
 4211  * ntfs_mft_set_inuse6
 4212  */
 4213 static int ntfs_mft_set_inuse6 (ntfs_inode *inode, struct ntfs_bmp *bmp, BOOL inuse)
 4214 {
 4215     MFT_RECORD *rec;
 4216 
 4217     if (!inode)
 4218         return -1;
 4219 
 4220     if (ntfs_bmp_set_range (bmp, (VCN) MREF (inode->mft_no), 1, inuse) < 0)
 4221         return -1;
 4222 
 4223     rec = (MFT_RECORD*) inode->mrec;
 4224 
 4225     // XXX extent inodes?
 4226 
 4227     if (inuse)
 4228         rec->flags |= MFT_RECORD_IN_USE;
 4229     else
 4230         rec->flags &= ~MFT_RECORD_IN_USE;
 4231 
 4232     // XXX inc sequence number
 4233 
 4234     NInoSetDirty(inode);
 4235 
 4236     printf (GREEN "Modified: inode %lld MFT_RECORD header\n" END, inode->mft_no);
 4237     return 0;
 4238 }
 4239 
 4240 
 4241 /**
 4242  * ntfs_file_remove
 4243  */
 4244 static int ntfs_file_remove (ntfs_volume *vol, struct ntfs_dt *del, int del_num)
 4245 {
 4246     struct ntfs_dir *find_dir = NULL;
 4247     struct ntfs_dt *top = NULL;
 4248     struct ntfs_dt *suc = NULL;
 4249     struct ntfs_dt *old = NULL;
 4250     struct ntfs_dt *par = NULL;
 4251     struct ntfs_dt *ded = NULL;
 4252     ntfschar *uname;
 4253     int name_len;
 4254     int suc_num = 0;
 4255     int par_num = -1;
 4256     INDEX_ENTRY *del_ie = NULL;
 4257     INDEX_ENTRY *suc_ie = NULL;
 4258     INDEX_ENTRY *par_ie = NULL;
 4259     INDEX_ENTRY *add_ie = NULL;
 4260     int res;
 4261     VCN vcn;
 4262     FILE_NAME_ATTR *file = NULL;
 4263     //int i;
 4264 
 4265     if (!vol || !del) {
 4266         return 1;
 4267     }
 4268 
 4269     find_dir = del->dir;
 4270 
 4271     uname    = del->children[del_num]->key.file_name.file_name;
 4272     name_len = del->children[del_num]->key.file_name.file_name_length;
 4273 
 4274     top = del->dir->index;
 4275     //ntfs_dt_find_all (top);
 4276     //ntfs_dt_print (top, 0);
 4277 
 4278     del_ie = del->children[del_num];
 4279     //utils_dump_mem (del_ie, 0, del_ie->length, DM_DEFAULTS);
 4280     //printf ("\n");
 4281 
 4282     /*
 4283      * If the key is not in a leaf node, then replace it with its successor.
 4284      * Continue the delete as if the successor had been deleted.
 4285      */
 4286 
 4287     /*
 4288     for (i = 0; i < top->child_count; i++) {
 4289         par_ie = top->children[i];
 4290         file = &par_ie->key.file_name; printf ("\ttop node, key %d: ", i); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4291         printf ("\tvcn = %lld\n", ntfs_ie_get_vcn (par_ie));
 4292     }
 4293     */
 4294 
 4295     if (del->header->flags & INDEX_NODE) {
 4296         printf (BOLD YELLOW "Replace key with its successor:\n" END);
 4297 
 4298         vcn = ntfs_ie_get_vcn (del_ie);
 4299         //printf ("vcn = %lld\n", vcn);
 4300 
 4301         suc = ntfs_dt_find4 (find_dir->index, uname, name_len, &suc_num);
 4302         //printf ("succ = %p, index = %d\n", suc, suc_num);
 4303         //printf ("\n");
 4304 
 4305         suc_ie = ntfs_ie_copy (suc->children[suc_num]);
 4306         //utils_dump_mem (suc_ie, 0, suc_ie->length, DM_BLUE|DM_GREEN|DM_INDENT);
 4307         //printf ("\n");
 4308 
 4309         suc_ie = ntfs_ie_set_vcn (suc_ie, vcn);
 4310         //utils_dump_mem (suc_ie, 0, suc_ie->length, DM_BLUE|DM_GREEN|DM_INDENT);
 4311         //printf ("\n");
 4312 
 4313         file = &del_ie->key.file_name; printf ("\trep name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4314         file = &suc_ie->key.file_name; printf ("\tsuc name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4315 
 4316         //utils_dump_mem (del->data, 0, del->data_len, DM_BLUE|DM_GREEN|DM_INDENT);
 4317         if (ntfs_dt_isroot (del))
 4318             res = ntfs_dt_root_replace (del, del_num, del_ie, suc_ie);
 4319         else
 4320             res = ntfs_dt_alloc_replace (del, del_num, del_ie, suc_ie);
 4321         //printf ("\n");
 4322         //utils_dump_mem (del->data, 0, del->data_len, DM_BLUE|DM_GREEN|DM_INDENT);
 4323 
 4324         ntfs_ie_free (suc_ie);
 4325 
 4326         if (res == FALSE)
 4327             goto done;
 4328 
 4329         del     = suc;      // Continue delete with the successor
 4330         del_num = suc_num;
 4331         del_ie  = suc->children[suc_num];
 4332     }
 4333 
 4334     //ntfs_dt_print (top, 0);
 4335 
 4336     /*
 4337      * Now we have the simpler case of deleting from a leaf node.
 4338      * If this step creates an empty node, we have more to do.
 4339      */
 4340 
 4341     printf ("\n");
 4342     printf (BOLD YELLOW "Delete key:\n" END);
 4343 
 4344     file = &del->children[del_num]->key.file_name; printf ("\tdel name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4345 
 4346     //utils_dump_mem (del->data, 0, del->header->index_length+24, DM_BLUE|DM_GREEN|DM_INDENT);
 4347     // XXX if del->child_count == 2, we could skip this step
 4348     // no, if we combine with another node, we'll have to remember
 4349     if (ntfs_dt_isroot (del))
 4350         ntfs_dt_root_remove (del, del_num);
 4351     else
 4352         ntfs_dt_alloc_remove (del, del_num);
 4353     //printf ("\n");
 4354     //utils_dump_mem (del->data, 0, del->header->index_length+24, DM_BLUE|DM_GREEN|DM_INDENT);
 4355 
 4356     if (del->child_count > 1)   // XXX ntfs_dt_empty (dt),  ntfs_dt_full (dt, new)
 4357         goto commit;
 4358 
 4359     /*
 4360      * Ascend the tree until we find a node that is not empty.  Take the
 4361      * ancestor key and unhook it.  This will free up some space in the
 4362      * index allocation.  Finally add the ancestor to the node of its
 4363      * successor.
 4364      */
 4365 
 4366     // find the key nearest the root which has no descendants
 4367     printf ("\n");
 4368     printf (BOLD YELLOW "Find childless parent:\n" END);
 4369 #if 0
 4370     for (par = del->parent, old = par; par; old = par, par = par->parent) {
 4371         if (par->child_count > 1)
 4372             break;
 4373         par_num = ntfs_dt_find_parent (par);
 4374     }
 4375 #endif
 4376 
 4377     printf ("del = %p, parent = %p\n", del, del->parent);
 4378     par = del->parent;
 4379     par_num = ntfs_dt_find_parent (del);
 4380 
 4381     //utils_dump_mem (par->data, 0, par->data_len, DM_BLUE|DM_GREEN|DM_INDENT);
 4382 
 4383     printf ("par = %p, par->parent = %p, num = %d\n", par, par->parent, par_num);
 4384     par_num = 0; // TEMP
 4385 
 4386     if (par) {
 4387         file = &par->children[par_num]->key.file_name;
 4388         printf ("\tpar name: ");
 4389         ntfs_name_print (file->file_name, file->file_name_length);
 4390         printf ("\n");
 4391     }
 4392 
 4393     if (par == NULL) {
 4394         // unhook everything
 4395         goto freedts;
 4396     }
 4397 
 4398     //ntfs_dt_print (top, 0);
 4399     printf ("\n");
 4400 
 4401     //utils_dump_mem (par->data, 0, par->data_len, DM_BLUE|DM_GREEN|DM_INDENT);
 4402     //printf ("\n");
 4403 
 4404     /*
 4405     for (i = 0; i < top->child_count; i++) {
 4406         par_ie = top->children[i];
 4407         file = &par_ie->key.file_name; printf ("\ttop node, key %d: ", i); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4408         printf ("\tvcn = %lld\n", ntfs_ie_get_vcn (par_ie));
 4409     }
 4410     */
 4411 
 4412     // find if parent has left siblings
 4413     if (par->children[par_num]->flags & INDEX_ENTRY_END) {
 4414         printf (BOLD YELLOW "Swap the children of the parent and its left sibling\n" END);
 4415 
 4416         par_ie = par->children[par_num];
 4417         vcn = ntfs_ie_get_vcn (par_ie);
 4418         //printf ("\toffset = %d\n", (u8*)par_ie - par->data); printf ("\tflags = %d\n", par_ie->flags); printf ("\tvcn = %lld\n", vcn); printf ("\tlength = %d\n", par_ie->length);
 4419         //utils_dump_mem (par_ie, 0, par_ie->length, DM_DEFAULTS);
 4420         //printf ("\n");
 4421 
 4422         //printf ("\toffset = %d\n", (u8*)par_ie - par->data); printf ("\tflags = %d\n", par_ie->flags); printf ("\tvcn = %lld\n", vcn); printf ("\tlength = %d\n", par_ie->length);
 4423         //utils_dump_mem (par_ie, 0, par_ie->length, DM_DEFAULTS);
 4424         //printf ("\n");
 4425 
 4426         file = &par->children[par_num]  ->key.file_name; printf ("\tpar name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4427         file = &par->children[par_num-1]->key.file_name; printf ("\tsib name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4428 
 4429         old                       = par->sub_nodes[par_num];
 4430         par->sub_nodes[par_num]   = par->sub_nodes[par_num-1];
 4431         par->sub_nodes[par_num-1] = old;
 4432 
 4433         par_ie = par->children[par_num-1];
 4434         vcn = ntfs_ie_get_vcn (par_ie);
 4435 
 4436         par_ie = par->children[par_num];
 4437         ntfs_ie_set_vcn (par_ie, vcn);
 4438 
 4439         par_num--;
 4440 
 4441         if (ntfs_dt_isroot (par))
 4442             printf (GREEN "Modified: inode %lld, $INDEX_ROOT\n" END, par->dir->inode->mft_no);
 4443         else
 4444             printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, par->dir->inode->mft_no, par->vcn, par->vcn + (par->dir->index_size>>9) - 1);
 4445     }
 4446 
 4447     //ntfs_dt_print (top, 0);
 4448 
 4449     //printf ("\n");
 4450     //utils_dump_mem (par->data, 0, par->data_len, DM_DEFAULTS);
 4451 
 4452     // unhook and hold onto the ded dt's
 4453     printf ("\n");
 4454     printf (BOLD YELLOW "Remove parent\n" END);
 4455 
 4456     file = &par->children[par_num]->key.file_name; printf ("\tpar name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4457 
 4458     add_ie = ntfs_ie_copy (par->children[par_num]);
 4459     add_ie = ntfs_ie_remove_vcn (add_ie);
 4460     if (!add_ie)
 4461         goto done;
 4462 
 4463     //printf ("\n");
 4464     //utils_dump_mem (add_ie, 0, add_ie->length, DM_BLUE|DM_GREEN|DM_INDENT);
 4465 
 4466     ded = par->sub_nodes[par_num];
 4467     par->sub_nodes[par_num] = NULL;
 4468     //ntfs_dt_print (ded, 8);
 4469 
 4470 #if 0
 4471     for (i = 0; i < par->child_count; i++) {
 4472         par_ie = par->children[i];
 4473         file = &par_ie->key.file_name; printf ("\tdel node, key %d: ", i); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4474         printf ("\tvcn = %lld\n", ntfs_ie_get_vcn (par_ie));
 4475     }
 4476 #endif
 4477 
 4478 #if 1
 4479     //printf ("PAR: %p,%d\n", par, par_num);
 4480     if (ntfs_dt_isroot (par))
 4481         ntfs_dt_root_remove (par, par_num);
 4482     else
 4483         ntfs_dt_alloc_remove (par, par_num);
 4484 #endif
 4485     //printf ("count = %d\n", par->child_count);
 4486     //utils_dump_mem (par->data, 0, par->data_len, DM_DEFAULTS);
 4487     //printf ("0x%x\n", (u8*)par->children[0] - par->data);
 4488 
 4489 #if 0
 4490     for (i = 0; i < par->child_count; i++) {
 4491         par_ie = par->children[i];
 4492         file = &par_ie->key.file_name; printf ("\tadd node, key %d: ", i); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4493         printf ("\tvcn = %lld\n", ntfs_ie_get_vcn (par_ie));
 4494     }
 4495 #endif
 4496 
 4497     //ntfs_dt_print (top, 0);
 4498     printf ("\n");
 4499     printf (BOLD YELLOW "Add childless parent\n" END);
 4500 
 4501     file = &add_ie->key.file_name; printf ("\tadd name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4502     suc     = NULL;
 4503     suc_num = -1;
 4504     suc = ntfs_dt_find4 (top, file->file_name, file->file_name_length, &suc_num);
 4505     //printf ("SUC: %p, %d\n", suc, suc_num);
 4506 
 4507     if (!suc)
 4508         goto done;
 4509 
 4510     file = &suc->children[suc_num]->key.file_name; printf ("\tsuc name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n");
 4511 
 4512     // insert key into successor
 4513     // if any new nodes are needed, reuse the preserved nodes
 4514     if (!ntfs_dt_add2 (add_ie, suc, suc_num, ded))
 4515         goto done;
 4516 
 4517     // remove any unused nodes
 4518 
 4519     // XXX mark dts, dirs and inodes dirty
 4520     // XXX add freed dts to a list for immediate reuse (attach to dir?)
 4521     // XXX any ded dts means we may need to adjust alloc
 4522     // XXX commit will free list of spare dts
 4523     // XXX reduce size of alloc
 4524     // XXX if ded, don't write it back, just update bitmap
 4525 
 4526     printf ("empty\n");
 4527     goto done;
 4528 
 4529 freedts:
 4530     printf ("\twhole dir is empty\n");
 4531 
 4532 commit:
 4533     //printf ("commit\n");
 4534 
 4535 done:
 4536     return 0;
 4537 }
 4538 
 4539 /**
 4540  * ntfs_file_remove2
 4541  */
 4542 static int ntfs_file_remove2 (ntfs_volume *vol, struct ntfs_dt *dt, int dt_num)
 4543 {
 4544     INDEX_ENTRY *ie;
 4545     ntfs_inode *ino;
 4546     struct ntfs_bmp *bmp_mft;
 4547     struct ntfs_bmp *bmp_vol;
 4548     struct ntfs_dir *dir;
 4549 
 4550     if (!vol || !dt)
 4551         return -1;
 4552 
 4553     ie  = dt->children[dt_num];
 4554     ino = dt->inodes[dt_num];
 4555     dir = dt->dir;
 4556 
 4557     bmp_mft = vol->private_bmp1;
 4558     bmp_vol = vol->private_bmp2;
 4559 
 4560     if (1) ntfs_mft_set_inuse6 (ino, bmp_mft, FALSE);
 4561 
 4562     if (1) utils_free_non_residents2 (ino, bmp_vol);
 4563 
 4564     if (1) ntfs_file_remove (vol, dt, dt_num); // remove name from index
 4565 
 4566     if (1) ntfs_dir_truncate (vol, dt->dir);
 4567 
 4568     if (1) ntfs_volume_commit (vol);
 4569 
 4570     if (0) ntfs_volume_rollback (vol);
 4571 
 4572     if (0) printf ("last mft = %lld\n", ntfs_bmp_find_last_set (bmp_mft));
 4573     if (0) printf ("last vol = %lld\n", ntfs_bmp_find_last_set (bmp_vol));
 4574 
 4575     return 0;
 4576 }
 4577 
 4578 /**
 4579  * ntfs_file_add2
 4580  */
 4581 static int ntfs_file_add2 (ntfs_volume *vol, char *filename)
 4582 {
 4583     MFT_REF new_num;
 4584     char *ptr = NULL;
 4585     char *dirname = NULL;
 4586     struct ntfs_find find;
 4587     INDEX_ENTRY *ie;
 4588     ntfschar *uname = NULL;
 4589     int uname_len = 0;
 4590     ntfs_inode *ino = NULL;
 4591     u8 *tmp = NULL;
 4592     u8 *buffer = NULL;
 4593     s64 now = 0;
 4594     struct ntfs_dir *dir;
 4595     struct ntfs_dt *dt;
 4596     //int dt_index = 0;
 4597     int data_len = 0;
 4598     ATTR_RECORD *attr;
 4599     struct ntfs_dt *suc = NULL;
 4600     int suc_num = 0;
 4601 
 4602     new_num = ntfs_mft_find_free_entry (vol);
 4603     if (new_num == (MFT_REF) -1)
 4604         return 1;
 4605 
 4606     if (rindex (filename, PATH_SEP)) {
 4607         ptr = rindex (filename, PATH_SEP);
 4608         *ptr = 0;
 4609         dirname = filename;
 4610         filename = ptr + 1;
 4611     }
 4612 
 4613     printf ("looking for %s\n", dirname);
 4614     if (utils_pathname_to_inode2 (vol, NULL, dirname, &find) == FALSE) {
 4615         printf ("!inode\n");
 4616         return 0;
 4617     }
 4618 
 4619     dt  = find.dt;
 4620     dir = find.dir;
 4621 
 4622     uname_len = ntfs_mbstoucs(filename, &uname, 0);
 4623     if (uname_len < 0)
 4624         goto close;
 4625 
 4626     printf ("new inode %lld\n", new_num);
 4627     ino = ntfs_inode_open3 (vol, new_num);
 4628     if (!ino) {
 4629         printf ("!ino\n");
 4630         goto close;
 4631     }
 4632 
 4633     tmp = (u8*) ino->mrec;
 4634     now = utc2ntfs (time(NULL));
 4635 
 4636     // Wipe all the attributes
 4637     memset (tmp + ino->mrec->attrs_offset, 0, vol->mft_record_size - ino->mrec->attrs_offset);
 4638 
 4639     // Add new end marker
 4640     *(u32*) (tmp + ino->mrec->attrs_offset) = 0xFFFFFFFF;
 4641     ino->mrec->bytes_in_use = ino->mrec->attrs_offset + 8;
 4642 
 4643     // Reset headers...
 4644     ino->mrec->lsn = 0;
 4645     ino->mrec->link_count = 1;
 4646     ino->mrec->base_mft_record = 0;
 4647     ino->mrec->next_attr_instance = 0;
 4648     ino->mrec->flags = MFT_RECORD_IN_USE;
 4649 
 4650     ntfs_mft_set_inuse6 (ino, vol->private_bmp1, TRUE);
 4651 
 4652     buffer = malloc (128);
 4653     if (!buffer)
 4654         goto close;
 4655 
 4656     // Standard information
 4657     memset (buffer, 0, 128);
 4658     *(u64*)(buffer + 0x00) = now;       // Time
 4659     *(u64*)(buffer + 0x08) = now;       // Time
 4660     *(u64*)(buffer + 0x10) = now;       // Time
 4661     *(u64*)(buffer + 0x18) = now;       // Time
 4662     ino->creation_time         = time (NULL);
 4663     ino->last_data_change_time = time (NULL);
 4664     ino->last_mft_change_time  = time (NULL);
 4665     ino->last_access_time      = time (NULL);
 4666     attr = ntfs_mft_add_attr (ino, AT_STANDARD_INFORMATION, buffer, 0x48);
 4667 
 4668     // Data
 4669     memset (buffer, 0, 128);
 4670     data_len = sprintf ((char*)buffer, "Contents of file: %s\n", filename);
 4671     attr = ntfs_mft_add_attr (ino, AT_DATA, buffer, data_len);
 4672 
 4673     // File name
 4674     memset (buffer, 0, 128);
 4675     *(u64*)(buffer + 0x00) = MK_MREF (find.mref, 2);    // MFT Ref of parent dir
 4676     *(u64*)(buffer + 0x08) = now;               // Time
 4677     *(u64*)(buffer + 0x10) = now;               // Time
 4678     *(u64*)(buffer + 0x18) = now;               // Time
 4679     *(u64*)(buffer + 0x20) = now;               // Time
 4680     *(u64*)(buffer + 0x28) = ATTR_SIZE (data_len);      // Allocated size
 4681     *(u64*)(buffer + 0x30) = data_len;          // Initialised size
 4682     *(u32*)(buffer + 0x38) = 0;             // Flags
 4683     *(u32*)(buffer + 0x3C) = 0;             // Not relevant
 4684     *(u8* )(buffer + 0x40) = uname_len;         // Filename length
 4685     *(u8* )(buffer + 0x41) = FILE_NAME_POSIX;       // Filename namespace
 4686     memcpy (buffer + 0x42, uname, uname_len * sizeof (ntfschar));
 4687     attr = ntfs_mft_add_attr (ino, AT_FILE_NAME, buffer, ATTR_SIZE (0x42 + (uname_len * sizeof (ntfschar))));
 4688     attr->resident_flags = RESIDENT_ATTR_IS_INDEXED;
 4689     attr->name_offset = 0x18;
 4690 
 4691     ie = ntfs_ie_create();
 4692     ie = ntfs_ie_set_name (ie, uname, uname_len, FILE_NAME_POSIX);
 4693     if (!ie) {
 4694         printf ("!ie\n");
 4695         goto close;
 4696     }
 4697 
 4698     // These two NEED the sequence number in the top 8 bits
 4699     ie->key.file_name.parent_directory      = MK_MREF (find.mref, 2);// MFT Ref: parent dir
 4700     ie->indexed_file = MK_MREF (new_num, ino->mrec->sequence_number);
 4701 
 4702     ie->key.file_name.creation_time         = now;
 4703     ie->key.file_name.last_data_change_time = now;
 4704     ie->key.file_name.last_mft_change_time  = now;
 4705     ie->key.file_name.last_access_time      = now;
 4706     ie->key.file_name.allocated_size        = ATTR_SIZE (data_len);
 4707     ie->key.file_name.data_size             = data_len;
 4708 
 4709     dir = dt->dir->children[0];
 4710     dt = dir->index;
 4711 
 4712     suc = ntfs_dt_find3 (dt, uname, uname_len, &suc_num);
 4713 
 4714     ntfs_dt_add2 (ie, suc, suc_num, NULL);
 4715 
 4716     /*
 4717     dt_index = ntfs_dt_root_add (dt, ie);
 4718     if (dt_index >= 0) {
 4719         dt->inodes[dt_index] = ino;
 4720         ino->ref_count++;
 4721     }
 4722     */
 4723 
 4724 close:
 4725     free (buffer);
 4726     ntfs_inode_close2 (ino);
 4727     ntfs_ie_free (ie);
 4728     free (uname);
 4729     ntfs_inode_close2 (find.inode);
 4730     return 0;
 4731 }
 4732 
 4733 /**
 4734  * main - Begin here
 4735  *
 4736  * Start from here.
 4737  *
 4738  * Return:  0  Success, the program worked
 4739  *      1  Error, something went wrong
 4740  */
 4741 int main (int argc, char *argv[])
 4742 {
 4743     ntfs_volume *vol = NULL;
 4744     ntfs_inode *inode = NULL;
 4745     int flags = 0;
 4746     int result = 1;
 4747     struct ntfs_find find;
 4748 
 4749     if (!parse_options (argc, argv))
 4750         goto done;
 4751 
 4752     utils_set_locale();
 4753 
 4754 #if 0
 4755     printf ("sizeof (ntfs_bmp)   = %d\n", sizeof (struct ntfs_bmp));
 4756     printf ("sizeof (ntfs_dt)    = %d\n", sizeof (struct ntfs_dt));
 4757     printf ("sizeof (ntfs_dir)   = %d\n", sizeof (struct ntfs_dir));
 4758     printf ("\n");
 4759 #endif
 4760 
 4761     if (opts.noaction)
 4762         flags |= MS_RDONLY;
 4763 
 4764     vol = ntfs_volume_mount2 (opts.device, flags, opts.force);
 4765     if (!vol) {
 4766         printf ("!vol\n");
 4767         goto done;
 4768     }
 4769 
 4770 #if 0
 4771     if (utils_pathname_to_inode2 (vol, NULL, opts.file, &find) == FALSE) {
 4772         printf ("!inode\n");
 4773         goto done;
 4774     }
 4775 
 4776     inode = find.inode;
 4777 #endif
 4778 
 4779     //printf ("inode = %lld\n", inode->mft_no);
 4780 
 4781     if (0) result = ntfs_file_remove2 (vol, find.dt, find.dt_index);
 4782     if (1) result = ntfs_file_add2 (vol, opts.file);
 4783 
 4784 done:
 4785     if (1) ntfs_volume_commit (vol);
 4786     if (0) ntfs_volume_rollback (vol);
 4787     if (0) ntfs_inode_close2 (inode);
 4788     if (1) ntfs_volume_umount2 (vol, FALSE);
 4789 
 4790     if (0) utils_pathname_to_inode2 (NULL, NULL, NULL, NULL);
 4791     if (0) ntfs_ie_remove_name (NULL);
 4792     if (0) ntfs_dt_transfer2 (NULL, NULL, 0, 0);
 4793     if (0) utils_array_remove (NULL, 0, 0, 0);
 4794     if (0) utils_array_insert (NULL, 0, 0, 0);
 4795 
 4796     return result;
 4797 }
 4798