1987da915Sopenharmony_ci/** 2987da915Sopenharmony_ci * ntfsmove - Part of the Linux-NTFS project. 3987da915Sopenharmony_ci * 4987da915Sopenharmony_ci * Copyright (c) 2003 Richard Russon 5987da915Sopenharmony_ci * Copyright (c) 2003-2005 Anton Altaparmakov 6987da915Sopenharmony_ci * 7987da915Sopenharmony_ci * This utility will move files on an NTFS volume. 8987da915Sopenharmony_ci * 9987da915Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 10987da915Sopenharmony_ci * it under the terms of the GNU General Public License as published by 11987da915Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 12987da915Sopenharmony_ci * (at your option) any later version. 13987da915Sopenharmony_ci * 14987da915Sopenharmony_ci * This program is distributed in the hope that it will be useful, 15987da915Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 16987da915Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17987da915Sopenharmony_ci * GNU General Public License for more details. 18987da915Sopenharmony_ci * 19987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License 20987da915Sopenharmony_ci * along with this program (in the main directory of the Linux-NTFS 21987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software 22987da915Sopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23987da915Sopenharmony_ci */ 24987da915Sopenharmony_ci 25987da915Sopenharmony_ci#include "config.h" 26987da915Sopenharmony_ci 27987da915Sopenharmony_ci#ifdef HAVE_STDIO_H 28987da915Sopenharmony_ci#include <stdio.h> 29987da915Sopenharmony_ci#endif 30987da915Sopenharmony_ci#ifdef HAVE_GETOPT_H 31987da915Sopenharmony_ci#include <getopt.h> 32987da915Sopenharmony_ci#endif 33987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H 34987da915Sopenharmony_ci#include <stdlib.h> 35987da915Sopenharmony_ci#endif 36987da915Sopenharmony_ci#ifdef HAVE_STRING_H 37987da915Sopenharmony_ci#include <string.h> 38987da915Sopenharmony_ci#endif 39987da915Sopenharmony_ci#ifdef HAVE_LIMITS_H 40987da915Sopenharmony_ci#include <limits.h> 41987da915Sopenharmony_ci#endif 42987da915Sopenharmony_ci 43987da915Sopenharmony_ci#include "types.h" 44987da915Sopenharmony_ci#include "attrib.h" 45987da915Sopenharmony_ci#include "utils.h" 46987da915Sopenharmony_ci#include "volume.h" 47987da915Sopenharmony_ci#include "debug.h" 48987da915Sopenharmony_ci#include "dir.h" 49987da915Sopenharmony_ci#include "bitmap.h" 50987da915Sopenharmony_ci#include "ntfsmove.h" 51987da915Sopenharmony_ci/* #include "version.h" */ 52987da915Sopenharmony_ci#include "logging.h" 53987da915Sopenharmony_ci 54987da915Sopenharmony_cistatic const char *EXEC_NAME = "ntfsmove"; 55987da915Sopenharmony_cistatic struct options opts; 56987da915Sopenharmony_ci 57987da915Sopenharmony_ci/** 58987da915Sopenharmony_ci * version - Print version information about the program 59987da915Sopenharmony_ci * 60987da915Sopenharmony_ci * Print a copyright statement and a brief description of the program. 61987da915Sopenharmony_ci * 62987da915Sopenharmony_ci * Return: none 63987da915Sopenharmony_ci */ 64987da915Sopenharmony_cistatic void version(void) 65987da915Sopenharmony_ci{ 66987da915Sopenharmony_ci ntfs_log_info("\n%s v%s (libntfs-3g) - Move files and directories on an " 67987da915Sopenharmony_ci "NTFS volume.\n\n", EXEC_NAME, VERSION); 68987da915Sopenharmony_ci ntfs_log_info("Copyright (c) 2003 Richard Russon\n"); 69987da915Sopenharmony_ci ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); 70987da915Sopenharmony_ci} 71987da915Sopenharmony_ci 72987da915Sopenharmony_ci/** 73987da915Sopenharmony_ci * usage - Print a list of the parameters to the program 74987da915Sopenharmony_ci * 75987da915Sopenharmony_ci * Print a list of the parameters and options for the program. 76987da915Sopenharmony_ci * 77987da915Sopenharmony_ci * Return: none 78987da915Sopenharmony_ci */ 79987da915Sopenharmony_cistatic void usage(void) 80987da915Sopenharmony_ci{ 81987da915Sopenharmony_ci ntfs_log_info("\nUsage: %s [options] device file\n" 82987da915Sopenharmony_ci "\n" 83987da915Sopenharmony_ci " -S --start Move to the start of the volume\n" 84987da915Sopenharmony_ci " -B --best Move to the best place on the volume\n" 85987da915Sopenharmony_ci " -E --end Move to the end of the volume\n" 86987da915Sopenharmony_ci " -C num --cluster num Move to this cluster offset\n" 87987da915Sopenharmony_ci "\n" 88987da915Sopenharmony_ci " -D --no-dirty Do not mark volume dirty (require chkdsk)\n" 89987da915Sopenharmony_ci " -n --no-action Do not write to disk\n" 90987da915Sopenharmony_ci " -f --force Use less caution\n" 91987da915Sopenharmony_ci " -h --help Print this help\n" 92987da915Sopenharmony_ci " -q --quiet Less output\n" 93987da915Sopenharmony_ci " -V --version Version information\n" 94987da915Sopenharmony_ci " -v --verbose More output\n\n", 95987da915Sopenharmony_ci EXEC_NAME); 96987da915Sopenharmony_ci ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); 97987da915Sopenharmony_ci} 98987da915Sopenharmony_ci 99987da915Sopenharmony_ci/** 100987da915Sopenharmony_ci * parse_options - Read and validate the programs command line 101987da915Sopenharmony_ci * 102987da915Sopenharmony_ci * Read the command line, verify the syntax and parse the options. 103987da915Sopenharmony_ci * This function is very long, but quite simple. 104987da915Sopenharmony_ci * 105987da915Sopenharmony_ci * Return: 1 Success 106987da915Sopenharmony_ci * 0 Error, one or more problems 107987da915Sopenharmony_ci */ 108987da915Sopenharmony_cistatic int parse_options(int argc, char **argv) 109987da915Sopenharmony_ci{ 110987da915Sopenharmony_ci static const char *sopt = "-BC:DEfh?nqSVv"; 111987da915Sopenharmony_ci static const struct option lopt[] = { 112987da915Sopenharmony_ci { "best", no_argument, NULL, 'B' }, 113987da915Sopenharmony_ci { "cluster", required_argument, NULL, 'C' }, 114987da915Sopenharmony_ci { "end", no_argument, NULL, 'E' }, 115987da915Sopenharmony_ci { "force", no_argument, NULL, 'f' }, 116987da915Sopenharmony_ci { "help", no_argument, NULL, 'h' }, 117987da915Sopenharmony_ci { "no-action", no_argument, NULL, 'n' }, 118987da915Sopenharmony_ci { "no-dirty", no_argument, NULL, 'D' }, 119987da915Sopenharmony_ci { "quiet", no_argument, NULL, 'q' }, 120987da915Sopenharmony_ci { "start", no_argument, NULL, 'S' }, 121987da915Sopenharmony_ci { "verbose", no_argument, NULL, 'v' }, 122987da915Sopenharmony_ci { "version", no_argument, NULL, 'V' }, 123987da915Sopenharmony_ci { NULL, 0, NULL, 0 } 124987da915Sopenharmony_ci }; 125987da915Sopenharmony_ci 126987da915Sopenharmony_ci int c = -1; 127987da915Sopenharmony_ci int err = 0; 128987da915Sopenharmony_ci int ver = 0; 129987da915Sopenharmony_ci int help = 0; 130987da915Sopenharmony_ci int levels = 0; 131987da915Sopenharmony_ci char *end = NULL; 132987da915Sopenharmony_ci 133987da915Sopenharmony_ci opterr = 0; /* We'll handle the errors, thank you. */ 134987da915Sopenharmony_ci 135987da915Sopenharmony_ci while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { 136987da915Sopenharmony_ci switch (c) { 137987da915Sopenharmony_ci case 1: /* A non-option argument */ 138987da915Sopenharmony_ci if (!opts.device) { 139987da915Sopenharmony_ci opts.device = argv[optind-1]; 140987da915Sopenharmony_ci } else if (!opts.file) { 141987da915Sopenharmony_ci opts.file = argv[optind-1]; 142987da915Sopenharmony_ci } else { 143987da915Sopenharmony_ci opts.device = NULL; 144987da915Sopenharmony_ci opts.file = NULL; 145987da915Sopenharmony_ci err++; 146987da915Sopenharmony_ci } 147987da915Sopenharmony_ci break; 148987da915Sopenharmony_ci case 'B': 149987da915Sopenharmony_ci if (opts.location == 0) 150987da915Sopenharmony_ci opts.location = NTFS_MOVE_LOC_BEST; 151987da915Sopenharmony_ci else 152987da915Sopenharmony_ci opts.location = -1; 153987da915Sopenharmony_ci break; 154987da915Sopenharmony_ci case 'C': 155987da915Sopenharmony_ci if (opts.location == 0) { 156987da915Sopenharmony_ci opts.location = strtoll(optarg, &end, 0); 157987da915Sopenharmony_ci if (end && *end) 158987da915Sopenharmony_ci err++; 159987da915Sopenharmony_ci } else { 160987da915Sopenharmony_ci opts.location = -1; 161987da915Sopenharmony_ci } 162987da915Sopenharmony_ci break; 163987da915Sopenharmony_ci case 'D': 164987da915Sopenharmony_ci opts.nodirty++; 165987da915Sopenharmony_ci break; 166987da915Sopenharmony_ci case 'E': 167987da915Sopenharmony_ci if (opts.location == 0) 168987da915Sopenharmony_ci opts.location = NTFS_MOVE_LOC_END; 169987da915Sopenharmony_ci else 170987da915Sopenharmony_ci opts.location = -1; 171987da915Sopenharmony_ci break; 172987da915Sopenharmony_ci case 'f': 173987da915Sopenharmony_ci opts.force++; 174987da915Sopenharmony_ci break; 175987da915Sopenharmony_ci case 'h': 176987da915Sopenharmony_ci case '?': 177987da915Sopenharmony_ci if (strncmp (argv[optind-1], "--log-", 6) == 0) { 178987da915Sopenharmony_ci if (!ntfs_log_parse_option (argv[optind-1])) 179987da915Sopenharmony_ci err++; 180987da915Sopenharmony_ci break; 181987da915Sopenharmony_ci } 182987da915Sopenharmony_ci help++; 183987da915Sopenharmony_ci break; 184987da915Sopenharmony_ci case 'n': 185987da915Sopenharmony_ci opts.noaction++; 186987da915Sopenharmony_ci break; 187987da915Sopenharmony_ci case 'q': 188987da915Sopenharmony_ci opts.quiet++; 189987da915Sopenharmony_ci ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); 190987da915Sopenharmony_ci break; 191987da915Sopenharmony_ci case 'S': 192987da915Sopenharmony_ci if (opts.location == 0) 193987da915Sopenharmony_ci opts.location = NTFS_MOVE_LOC_START; 194987da915Sopenharmony_ci else 195987da915Sopenharmony_ci opts.location = -1; 196987da915Sopenharmony_ci break; 197987da915Sopenharmony_ci case 'V': 198987da915Sopenharmony_ci ver++; 199987da915Sopenharmony_ci break; 200987da915Sopenharmony_ci case 'v': 201987da915Sopenharmony_ci opts.verbose++; 202987da915Sopenharmony_ci ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); 203987da915Sopenharmony_ci break; 204987da915Sopenharmony_ci default: 205987da915Sopenharmony_ci ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]); 206987da915Sopenharmony_ci err++; 207987da915Sopenharmony_ci break; 208987da915Sopenharmony_ci } 209987da915Sopenharmony_ci } 210987da915Sopenharmony_ci 211987da915Sopenharmony_ci /* Make sure we're in sync with the log levels */ 212987da915Sopenharmony_ci levels = ntfs_log_get_levels(); 213987da915Sopenharmony_ci if (levels & NTFS_LOG_LEVEL_VERBOSE) 214987da915Sopenharmony_ci opts.verbose++; 215987da915Sopenharmony_ci if (!(levels & NTFS_LOG_LEVEL_QUIET)) 216987da915Sopenharmony_ci opts.quiet++; 217987da915Sopenharmony_ci 218987da915Sopenharmony_ci if (help || ver) { 219987da915Sopenharmony_ci opts.quiet = 0; 220987da915Sopenharmony_ci } else { 221987da915Sopenharmony_ci if ((opts.device == NULL) || 222987da915Sopenharmony_ci (opts.file == NULL)) { 223987da915Sopenharmony_ci if (argc > 1) 224987da915Sopenharmony_ci ntfs_log_error("You must specify one device and one file.\n"); 225987da915Sopenharmony_ci err++; 226987da915Sopenharmony_ci } 227987da915Sopenharmony_ci 228987da915Sopenharmony_ci if (opts.quiet && opts.verbose) { 229987da915Sopenharmony_ci ntfs_log_error("You may not use --quiet and --verbose at the " 230987da915Sopenharmony_ci "same time.\n"); 231987da915Sopenharmony_ci err++; 232987da915Sopenharmony_ci } 233987da915Sopenharmony_ci 234987da915Sopenharmony_ci if (opts.location == -1) { 235987da915Sopenharmony_ci ntfs_log_error("You may only specify one location option: " 236987da915Sopenharmony_ci "--start, --best, --end or --cluster\n"); 237987da915Sopenharmony_ci err++; 238987da915Sopenharmony_ci } else if (opts.location == 0) { 239987da915Sopenharmony_ci opts.location = NTFS_MOVE_LOC_BEST; 240987da915Sopenharmony_ci } 241987da915Sopenharmony_ci } 242987da915Sopenharmony_ci 243987da915Sopenharmony_ci if (ver) 244987da915Sopenharmony_ci version(); 245987da915Sopenharmony_ci if (help || err) 246987da915Sopenharmony_ci usage(); 247987da915Sopenharmony_ci 248987da915Sopenharmony_ci return (!err && !help && !ver); 249987da915Sopenharmony_ci} 250987da915Sopenharmony_ci 251987da915Sopenharmony_ci#if 0 252987da915Sopenharmony_ci 253987da915Sopenharmony_ci/** 254987da915Sopenharmony_ci * ntfs_debug_runlist_dump2 - Dump a runlist. 255987da915Sopenharmony_ci */ 256987da915Sopenharmony_cistatic int ntfs_debug_runlist_dump2(const runlist *rl, int abbr, char *prefix) 257987da915Sopenharmony_ci{ 258987da915Sopenharmony_ci //int abbr = 3; /* abbreviate long lists */ 259987da915Sopenharmony_ci int len = 0; 260987da915Sopenharmony_ci int i; 261987da915Sopenharmony_ci int res = 0; 262987da915Sopenharmony_ci u64 total = 0; 263987da915Sopenharmony_ci const char *lcn_str[5] = { "HOLE", "NOTMAP", "ENOENT", "EINVAL", "XXXX" }; 264987da915Sopenharmony_ci 265987da915Sopenharmony_ci if (!rl) { 266987da915Sopenharmony_ci ntfs_log_info(" Run list not present.\n"); 267987da915Sopenharmony_ci return 0; 268987da915Sopenharmony_ci } 269987da915Sopenharmony_ci 270987da915Sopenharmony_ci if (!prefix) 271987da915Sopenharmony_ci prefix = ""; 272987da915Sopenharmony_ci 273987da915Sopenharmony_ci if (abbr) 274987da915Sopenharmony_ci for (len = 0; rl[len].length; len++) ; 275987da915Sopenharmony_ci 276987da915Sopenharmony_ci ntfs_log_info("%s VCN LCN len\n", prefix); 277987da915Sopenharmony_ci for (i = 0; rl->length; i++, rl++) { 278987da915Sopenharmony_ci LCN lcn = rl->lcn; 279987da915Sopenharmony_ci 280987da915Sopenharmony_ci total += rl->length; 281987da915Sopenharmony_ci if (abbr) 282987da915Sopenharmony_ci if (len > 20) { 283987da915Sopenharmony_ci if ((i == abbr) && (len > (abbr*2))) 284987da915Sopenharmony_ci ntfs_log_info("%s ... ... ...\n", prefix); 285987da915Sopenharmony_ci if ((i > (abbr-1)) && (i < (len - (abbr-1)))) 286987da915Sopenharmony_ci continue; 287987da915Sopenharmony_ci } 288987da915Sopenharmony_ci 289987da915Sopenharmony_ci if (rl->vcn < -1) 290987da915Sopenharmony_ci res = -1; 291987da915Sopenharmony_ci 292987da915Sopenharmony_ci if (lcn < (LCN)0) { 293987da915Sopenharmony_ci int j = -lcn - 1; 294987da915Sopenharmony_ci 295987da915Sopenharmony_ci if ((j < 0) || (j > 4)) { 296987da915Sopenharmony_ci j = 4; 297987da915Sopenharmony_ci res = -1; 298987da915Sopenharmony_ci } 299987da915Sopenharmony_ci ntfs_log_info("%s%8lld %8s %8lld\n", prefix, 300987da915Sopenharmony_ci rl->vcn, lcn_str[j], rl->length); 301987da915Sopenharmony_ci } else 302987da915Sopenharmony_ci ntfs_log_info("%s%8lld %8lld %8lld\n", prefix, 303987da915Sopenharmony_ci rl->vcn, rl->lcn, rl->length); 304987da915Sopenharmony_ci } 305987da915Sopenharmony_ci ntfs_log_info("%s --------\n", prefix); 306987da915Sopenharmony_ci ntfs_log_info("%s %8lld\n", prefix, total); 307987da915Sopenharmony_ci ntfs_log_info("\n"); 308987da915Sopenharmony_ci return res; 309987da915Sopenharmony_ci} 310987da915Sopenharmony_ci 311987da915Sopenharmony_ci#endif /* if 0 */ 312987da915Sopenharmony_ci 313987da915Sopenharmony_ci/** 314987da915Sopenharmony_ci * resize_nonres_attr 315987da915Sopenharmony_ci */ 316987da915Sopenharmony_cistatic int resize_nonres_attr(MFT_RECORD *m, ATTR_RECORD *a, const u32 new_size) 317987da915Sopenharmony_ci{ 318987da915Sopenharmony_ci int this_attr; 319987da915Sopenharmony_ci int next_attr; 320987da915Sopenharmony_ci int tail_size; 321987da915Sopenharmony_ci int file_size; 322987da915Sopenharmony_ci int old_size; 323987da915Sopenharmony_ci u8 *ptr; 324987da915Sopenharmony_ci 325987da915Sopenharmony_ci old_size = le32_to_cpu(a->length); 326987da915Sopenharmony_ci file_size = le32_to_cpu(m->bytes_in_use); 327987da915Sopenharmony_ci this_attr = p2n(a)-p2n(m); 328987da915Sopenharmony_ci next_attr = this_attr + le32_to_cpu(a->length); 329987da915Sopenharmony_ci tail_size = file_size - next_attr; 330987da915Sopenharmony_ci ptr = (u8*) m; 331987da915Sopenharmony_ci 332987da915Sopenharmony_ci /* 333987da915Sopenharmony_ci ntfs_log_info("old_size = %d\n", old_size); 334987da915Sopenharmony_ci ntfs_log_info("new_size = %d\n", new_size); 335987da915Sopenharmony_ci ntfs_log_info("file_size = %d\n", file_size); 336987da915Sopenharmony_ci ntfs_log_info("this_attr = %d\n", this_attr); 337987da915Sopenharmony_ci ntfs_log_info("next_attr = %d\n", next_attr); 338987da915Sopenharmony_ci ntfs_log_info("tail_size = %d\n", tail_size); 339987da915Sopenharmony_ci */ 340987da915Sopenharmony_ci 341987da915Sopenharmony_ci memmove(ptr + this_attr + new_size, ptr + next_attr, tail_size); 342987da915Sopenharmony_ci 343987da915Sopenharmony_ci a->length = cpu_to_le32(new_size); 344987da915Sopenharmony_ci m->bytes_in_use = cpu_to_le32(le32_to_cpu(m->bytes_in_use) + (new_size - old_size)); 345987da915Sopenharmony_ci 346987da915Sopenharmony_ci return 0; 347987da915Sopenharmony_ci} 348987da915Sopenharmony_ci 349987da915Sopenharmony_ci/** 350987da915Sopenharmony_ci * calc_attr_length 351987da915Sopenharmony_ci */ 352987da915Sopenharmony_cistatic int calc_attr_length(ATTR_RECORD *rec, int runlength) 353987da915Sopenharmony_ci{ 354987da915Sopenharmony_ci int size; 355987da915Sopenharmony_ci 356987da915Sopenharmony_ci if (!rec) 357987da915Sopenharmony_ci return -1; 358987da915Sopenharmony_ci if (!rec->non_resident) 359987da915Sopenharmony_ci return -1; 360987da915Sopenharmony_ci 361987da915Sopenharmony_ci size = le16_to_cpu(rec->mapping_pairs_offset) + runlength + 7; 362987da915Sopenharmony_ci size &= 0xFFF8; 363987da915Sopenharmony_ci return size; 364987da915Sopenharmony_ci} 365987da915Sopenharmony_ci 366987da915Sopenharmony_ci#if 0 367987da915Sopenharmony_ci 368987da915Sopenharmony_ci/** 369987da915Sopenharmony_ci * dump_runs 370987da915Sopenharmony_ci */ 371987da915Sopenharmony_cistatic void dump_runs(u8 *buffer, int len) 372987da915Sopenharmony_ci{ 373987da915Sopenharmony_ci int i; 374987da915Sopenharmony_ci ntfs_log_info("RUN: \e[01;31m"); 375987da915Sopenharmony_ci 376987da915Sopenharmony_ci for (i = 0; i < len; i++) { 377987da915Sopenharmony_ci ntfs_log_info(" %02x", buffer[i]); 378987da915Sopenharmony_ci } 379987da915Sopenharmony_ci ntfs_log_info("\e[0m\n"); 380987da915Sopenharmony_ci} 381987da915Sopenharmony_ci 382987da915Sopenharmony_ci#endif /* if 0 */ 383987da915Sopenharmony_ci 384987da915Sopenharmony_ci/** 385987da915Sopenharmony_ci * find_unused 386987da915Sopenharmony_ci */ 387987da915Sopenharmony_cistatic runlist * find_unused(ntfs_volume *vol, s64 size, u64 loc 388987da915Sopenharmony_ci __attribute__((unused)), int flags __attribute__((unused))) 389987da915Sopenharmony_ci{ 390987da915Sopenharmony_ci const int bufsize = 8192; 391987da915Sopenharmony_ci u8 *buffer; 392987da915Sopenharmony_ci int clus; 393987da915Sopenharmony_ci int i; 394987da915Sopenharmony_ci int curr = 0; 395987da915Sopenharmony_ci int count = 0; 396987da915Sopenharmony_ci s64 start = 0; 397987da915Sopenharmony_ci int bit = 0; 398987da915Sopenharmony_ci runlist *res = NULL; 399987da915Sopenharmony_ci 400987da915Sopenharmony_ci //ntfs_log_info("find_unused\n"); 401987da915Sopenharmony_ci buffer = malloc(bufsize); 402987da915Sopenharmony_ci if (!buffer) { 403987da915Sopenharmony_ci ntfs_log_info("!buffer\n"); 404987da915Sopenharmony_ci return NULL; 405987da915Sopenharmony_ci } 406987da915Sopenharmony_ci 407987da915Sopenharmony_ci //ntfs_log_info("looking for space for %lld clusters\n", size); 408987da915Sopenharmony_ci 409987da915Sopenharmony_ci clus = vol->lcnbmp_na->allocated_size / bufsize; 410987da915Sopenharmony_ci //ntfs_log_info("clus = %d\n", clus); 411987da915Sopenharmony_ci 412987da915Sopenharmony_ci for (i = 0; i < clus; i++) { 413987da915Sopenharmony_ci int bytes_read, j; 414987da915Sopenharmony_ci 415987da915Sopenharmony_ci bytes_read = ntfs_attr_pread(vol->lcnbmp_na, i*bufsize, 416987da915Sopenharmony_ci bufsize, buffer); 417987da915Sopenharmony_ci if (bytes_read != bufsize) { 418987da915Sopenharmony_ci ntfs_log_info("!read\n"); 419987da915Sopenharmony_ci return NULL; 420987da915Sopenharmony_ci } 421987da915Sopenharmony_ci for (j = 0; j < bufsize*8; j++) { 422987da915Sopenharmony_ci bit = !!test_bit(j & 7, buffer[j>>3]); 423987da915Sopenharmony_ci if (curr == bit) { 424987da915Sopenharmony_ci count++; 425987da915Sopenharmony_ci if ((!bit) && (count >= size)) { 426987da915Sopenharmony_ci //res = calloc(2, sizeof(*res)); 427987da915Sopenharmony_ci res = calloc(1, 4096); 428987da915Sopenharmony_ci if (res) { 429987da915Sopenharmony_ci res[0].vcn = 0; 430987da915Sopenharmony_ci res[0].lcn = start; 431987da915Sopenharmony_ci res[0].length = size; 432987da915Sopenharmony_ci res[1].lcn = LCN_ENOENT; 433987da915Sopenharmony_ci } 434987da915Sopenharmony_ci goto done; 435987da915Sopenharmony_ci } 436987da915Sopenharmony_ci } else { 437987da915Sopenharmony_ci //ntfs_log_info("%d * %d\n", curr, count); 438987da915Sopenharmony_ci curr = bit; 439987da915Sopenharmony_ci count = 1; 440987da915Sopenharmony_ci start = i*bufsize*8 + j; 441987da915Sopenharmony_ci } 442987da915Sopenharmony_ci } 443987da915Sopenharmony_ci } 444987da915Sopenharmony_cidone: 445987da915Sopenharmony_ci //ntfs_log_info("%d * %d\n", curr, count); 446987da915Sopenharmony_ci 447987da915Sopenharmony_ci free(buffer); 448987da915Sopenharmony_ci 449987da915Sopenharmony_ci if (res) { 450987da915Sopenharmony_ci for (i = 0; i < size; i++) { 451987da915Sopenharmony_ci if (utils_cluster_in_use(vol, res->lcn + i)) { 452987da915Sopenharmony_ci ntfs_log_info("ERROR cluster %lld in use\n", 453987da915Sopenharmony_ci (long long)res->lcn + i); 454987da915Sopenharmony_ci } 455987da915Sopenharmony_ci } 456987da915Sopenharmony_ci } else { 457987da915Sopenharmony_ci ntfs_log_info("failed\n"); 458987da915Sopenharmony_ci } 459987da915Sopenharmony_ci 460987da915Sopenharmony_ci return res; 461987da915Sopenharmony_ci} 462987da915Sopenharmony_ci 463987da915Sopenharmony_ci/** 464987da915Sopenharmony_ci * dont_move 465987da915Sopenharmony_ci * 466987da915Sopenharmony_ci * Don't let the user move: 467987da915Sopenharmony_ci * ANY metadata 468987da915Sopenharmony_ci * Any fragmented MFT records 469987da915Sopenharmony_ci * The boot file 'ntldr' 470987da915Sopenharmony_ci */ 471987da915Sopenharmony_cistatic int dont_move(ntfs_inode *ino) 472987da915Sopenharmony_ci{ 473987da915Sopenharmony_ci static const ntfschar ntldr[6] = { 474987da915Sopenharmony_ci const_cpu_to_le16('n'), const_cpu_to_le16('t'), const_cpu_to_le16('l'), 475987da915Sopenharmony_ci const_cpu_to_le16('d'), const_cpu_to_le16('r'), const_cpu_to_le16('\0') 476987da915Sopenharmony_ci }; 477987da915Sopenharmony_ci 478987da915Sopenharmony_ci ATTR_RECORD *rec; 479987da915Sopenharmony_ci FILE_NAME_ATTR *name; 480987da915Sopenharmony_ci 481987da915Sopenharmony_ci if (utils_is_metadata(ino)) { 482987da915Sopenharmony_ci ntfs_log_error("metadata\n"); 483987da915Sopenharmony_ci return 1; 484987da915Sopenharmony_ci } 485987da915Sopenharmony_ci 486987da915Sopenharmony_ci rec = find_first_attribute(AT_ATTRIBUTE_LIST, ino->mrec); 487987da915Sopenharmony_ci if (rec) { 488987da915Sopenharmony_ci ntfs_log_error("attribute list\n"); 489987da915Sopenharmony_ci return 1; 490987da915Sopenharmony_ci } 491987da915Sopenharmony_ci 492987da915Sopenharmony_ci rec = find_first_attribute(AT_FILE_NAME, ino->mrec); 493987da915Sopenharmony_ci if (!rec) { 494987da915Sopenharmony_ci ntfs_log_error("extend inode\n"); 495987da915Sopenharmony_ci return 1; 496987da915Sopenharmony_ci } 497987da915Sopenharmony_ci 498987da915Sopenharmony_ci name = (FILE_NAME_ATTR*) ((u8*)rec + le16_to_cpu(rec->value_offset)); 499987da915Sopenharmony_ci if (ntfs_names_are_equal(ntldr, 5, name->file_name, name->file_name_length, 500987da915Sopenharmony_ci IGNORE_CASE, ino->vol->upcase, ino->vol->upcase_len)) { 501987da915Sopenharmony_ci ntfs_log_error("ntldr\n"); 502987da915Sopenharmony_ci return 1; 503987da915Sopenharmony_ci } 504987da915Sopenharmony_ci 505987da915Sopenharmony_ci return 0; 506987da915Sopenharmony_ci} 507987da915Sopenharmony_ci 508987da915Sopenharmony_ci 509987da915Sopenharmony_ci/** 510987da915Sopenharmony_ci * bitmap_alloc 511987da915Sopenharmony_ci */ 512987da915Sopenharmony_cistatic int bitmap_alloc(ntfs_volume *vol, runlist_element *rl) 513987da915Sopenharmony_ci{ 514987da915Sopenharmony_ci int res; 515987da915Sopenharmony_ci 516987da915Sopenharmony_ci if (!rl) 517987da915Sopenharmony_ci return -1; 518987da915Sopenharmony_ci 519987da915Sopenharmony_ci res = ntfs_bitmap_set_run(vol->lcnbmp_na, rl->lcn, rl->length); 520987da915Sopenharmony_ci if (res < 0) { 521987da915Sopenharmony_ci ntfs_log_error("bitmap alloc returns %d\n", res); 522987da915Sopenharmony_ci } 523987da915Sopenharmony_ci 524987da915Sopenharmony_ci return res; 525987da915Sopenharmony_ci} 526987da915Sopenharmony_ci 527987da915Sopenharmony_ci/** 528987da915Sopenharmony_ci * bitmap_free 529987da915Sopenharmony_ci */ 530987da915Sopenharmony_cistatic int bitmap_free(ntfs_volume *vol, runlist_element *rl) 531987da915Sopenharmony_ci{ 532987da915Sopenharmony_ci int res; 533987da915Sopenharmony_ci 534987da915Sopenharmony_ci if (!rl) 535987da915Sopenharmony_ci return -1; 536987da915Sopenharmony_ci 537987da915Sopenharmony_ci res = ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn, rl->length); 538987da915Sopenharmony_ci if (res < 0) { 539987da915Sopenharmony_ci ntfs_log_error("bitmap free returns %d\n", res); 540987da915Sopenharmony_ci } 541987da915Sopenharmony_ci 542987da915Sopenharmony_ci return res; 543987da915Sopenharmony_ci} 544987da915Sopenharmony_ci 545987da915Sopenharmony_ci/** 546987da915Sopenharmony_ci * data_copy 547987da915Sopenharmony_ci */ 548987da915Sopenharmony_cistatic int data_copy(ntfs_volume *vol, runlist_element *from, runlist_element *to) 549987da915Sopenharmony_ci{ 550987da915Sopenharmony_ci int i; 551987da915Sopenharmony_ci u8 *buffer; 552987da915Sopenharmony_ci s64 res = 0; 553987da915Sopenharmony_ci 554987da915Sopenharmony_ci if (!vol || !from || !to) 555987da915Sopenharmony_ci return -1; 556987da915Sopenharmony_ci if ((from->length != to->length) || (from->lcn < 0) || (to->lcn < 0)) 557987da915Sopenharmony_ci return -1; 558987da915Sopenharmony_ci 559987da915Sopenharmony_ci //ntfs_log_info("data_copy: from 0x%llx to 0x%llx\n", from->lcn, to->lcn); 560987da915Sopenharmony_ci buffer = malloc(vol->cluster_size); 561987da915Sopenharmony_ci if (!buffer) { 562987da915Sopenharmony_ci ntfs_log_info("!buffer\n"); 563987da915Sopenharmony_ci return -1; 564987da915Sopenharmony_ci } 565987da915Sopenharmony_ci 566987da915Sopenharmony_ci for (i = 0; i < from->length; i++) { 567987da915Sopenharmony_ci //ntfs_log_info("read cluster at %8lld\n", from->lcn+i); 568987da915Sopenharmony_ci res = ntfs_pread(vol->dev, (from->lcn+i) * vol->cluster_size, 569987da915Sopenharmony_ci vol->cluster_size, buffer); 570987da915Sopenharmony_ci if (res != vol->cluster_size) { 571987da915Sopenharmony_ci ntfs_log_error("!read\n"); 572987da915Sopenharmony_ci res = -1; 573987da915Sopenharmony_ci break; 574987da915Sopenharmony_ci } 575987da915Sopenharmony_ci 576987da915Sopenharmony_ci //ntfs_log_info("write cluster to %8lld\n", to->lcn+i); 577987da915Sopenharmony_ci res = ntfs_pwrite(vol->dev, (to->lcn+i) * vol->cluster_size, 578987da915Sopenharmony_ci vol->cluster_size, buffer); 579987da915Sopenharmony_ci if (res != vol->cluster_size) { 580987da915Sopenharmony_ci ntfs_log_error("!write %lld\n", (long long)res); 581987da915Sopenharmony_ci res = -1; 582987da915Sopenharmony_ci break; 583987da915Sopenharmony_ci } 584987da915Sopenharmony_ci } 585987da915Sopenharmony_ci 586987da915Sopenharmony_ci free(buffer); 587987da915Sopenharmony_ci return res; 588987da915Sopenharmony_ci} 589987da915Sopenharmony_ci 590987da915Sopenharmony_ci/** 591987da915Sopenharmony_ci * move_runlist 592987da915Sopenharmony_ci * 593987da915Sopenharmony_ci * validate: 594987da915Sopenharmony_ci * runlists are the same size 595987da915Sopenharmony_ci * from in use 596987da915Sopenharmony_ci * to not in use 597987da915Sopenharmony_ci * allocate new space 598987da915Sopenharmony_ci * copy data 599987da915Sopenharmony_ci * deallocate old space 600987da915Sopenharmony_ci */ 601987da915Sopenharmony_cistatic s64 move_runlist(ntfs_volume *vol, runlist_element *from, 602987da915Sopenharmony_ci runlist_element *to) 603987da915Sopenharmony_ci{ 604987da915Sopenharmony_ci int i; 605987da915Sopenharmony_ci 606987da915Sopenharmony_ci if (!vol || !from || !to) 607987da915Sopenharmony_ci return -1; 608987da915Sopenharmony_ci if (from->length != to->length) { 609987da915Sopenharmony_ci ntfs_log_error("diffsizes\n"); 610987da915Sopenharmony_ci return -1; 611987da915Sopenharmony_ci } 612987da915Sopenharmony_ci 613987da915Sopenharmony_ci if ((from->lcn < 0) || (to->lcn < 0)) { 614987da915Sopenharmony_ci ntfs_log_error("invalid runs\n"); 615987da915Sopenharmony_ci return -1; 616987da915Sopenharmony_ci } 617987da915Sopenharmony_ci 618987da915Sopenharmony_ci for (i = 0; i < from->length; i++) { 619987da915Sopenharmony_ci if (!utils_cluster_in_use(vol, from->lcn+i)) { 620987da915Sopenharmony_ci ntfs_log_error("from not in use\n"); 621987da915Sopenharmony_ci return -1; 622987da915Sopenharmony_ci } 623987da915Sopenharmony_ci } 624987da915Sopenharmony_ci 625987da915Sopenharmony_ci for (i = 0; i < to->length; i++) { 626987da915Sopenharmony_ci if (utils_cluster_in_use(vol, to->lcn+i)) { 627987da915Sopenharmony_ci ntfs_log_error("to is in use\n"); 628987da915Sopenharmony_ci return -1; 629987da915Sopenharmony_ci } 630987da915Sopenharmony_ci } 631987da915Sopenharmony_ci 632987da915Sopenharmony_ci if (bitmap_alloc(vol, to) < 0) { 633987da915Sopenharmony_ci ntfs_log_error("cannot bitmap_alloc\n"); 634987da915Sopenharmony_ci return -1; 635987da915Sopenharmony_ci } 636987da915Sopenharmony_ci 637987da915Sopenharmony_ci if (data_copy(vol, from, to) < 0) { 638987da915Sopenharmony_ci ntfs_log_error("cannot data_copy\n"); 639987da915Sopenharmony_ci return -1; 640987da915Sopenharmony_ci } 641987da915Sopenharmony_ci 642987da915Sopenharmony_ci if (bitmap_free(vol, from) < 0) { 643987da915Sopenharmony_ci ntfs_log_error("cannot bitmap_free\n"); 644987da915Sopenharmony_ci return -1; 645987da915Sopenharmony_ci } 646987da915Sopenharmony_ci 647987da915Sopenharmony_ci return 0; 648987da915Sopenharmony_ci} 649987da915Sopenharmony_ci 650987da915Sopenharmony_ci 651987da915Sopenharmony_ci/**original 652987da915Sopenharmony_ci * move_datarun 653987da915Sopenharmony_ci * > 0 Bytes moved / size to be moved 654987da915Sopenharmony_ci * = 0 Nothing to do 655987da915Sopenharmony_ci * < 0 Error 656987da915Sopenharmony_ci */ 657987da915Sopenharmony_ci 658987da915Sopenharmony_ci// get size of runlist 659987da915Sopenharmony_ci// find somewhere to put data 660987da915Sopenharmony_ci// backup original runlist 661987da915Sopenharmony_ci// move the data 662987da915Sopenharmony_ci 663987da915Sopenharmony_ci// got to get the runlist out of this function 664987da915Sopenharmony_ci// requires a mrec arg, not an ino (ino->mrec will do for now) 665987da915Sopenharmony_ci// check size of new runlist before allocating / moving 666987da915Sopenharmony_ci// replace one datarun with another (by hand) 667987da915Sopenharmony_cistatic s64 move_datarun(ntfs_volume *vol, ntfs_inode *ino, ATTR_RECORD *rec, 668987da915Sopenharmony_ci runlist_element *run, u64 loc, int flags) 669987da915Sopenharmony_ci{ 670987da915Sopenharmony_ci runlist *from; 671987da915Sopenharmony_ci runlist *to; 672987da915Sopenharmony_ci int need_from; 673987da915Sopenharmony_ci int need_to; 674987da915Sopenharmony_ci int i; 675987da915Sopenharmony_ci s64 res = -1; 676987da915Sopenharmony_ci 677987da915Sopenharmony_ci // find empty space 678987da915Sopenharmony_ci to = find_unused(vol, run->length, loc, flags); 679987da915Sopenharmony_ci if (!to) { 680987da915Sopenharmony_ci ntfs_log_error("!to\n"); 681987da915Sopenharmony_ci return -1; 682987da915Sopenharmony_ci } 683987da915Sopenharmony_ci 684987da915Sopenharmony_ci to->vcn = run->vcn; 685987da915Sopenharmony_ci 686987da915Sopenharmony_ci // copy original runlist 687987da915Sopenharmony_ci from = ntfs_mapping_pairs_decompress(vol, rec, NULL); 688987da915Sopenharmony_ci if (!from) { 689987da915Sopenharmony_ci ntfs_log_info("!from\n"); 690987da915Sopenharmony_ci return -1; 691987da915Sopenharmony_ci } 692987da915Sopenharmony_ci 693987da915Sopenharmony_ci ntfs_log_info("move %lld,%lld,%lld to %lld,%lld,%lld\n", 694987da915Sopenharmony_ci (long long)run->vcn, (long long)run->lcn, (long long)run->length, 695987da915Sopenharmony_ci (long long)to->vcn, (long long)to->lcn, (long long)to->length); 696987da915Sopenharmony_ci 697987da915Sopenharmony_ci need_from = ntfs_get_size_for_mapping_pairs(vol, from, 0, INT_MAX); 698987da915Sopenharmony_ci ntfs_log_info("orig data run = %d bytes\n", need_from); 699987da915Sopenharmony_ci 700987da915Sopenharmony_ci //ntfs_debug_runlist_dump2(from, 5, "\t"); 701987da915Sopenharmony_ci 702987da915Sopenharmony_ci for (i = 0; to[i].length > 0; i++) { 703987da915Sopenharmony_ci if (from[i].vcn == run->vcn) { 704987da915Sopenharmony_ci from[i].lcn = to->lcn; 705987da915Sopenharmony_ci break; 706987da915Sopenharmony_ci } 707987da915Sopenharmony_ci } 708987da915Sopenharmony_ci 709987da915Sopenharmony_ci //ntfs_debug_runlist_dump2(from, 5, "\t"); 710987da915Sopenharmony_ci 711987da915Sopenharmony_ci need_to = ntfs_get_size_for_mapping_pairs(vol, from, 0, INT_MAX); 712987da915Sopenharmony_ci ntfs_log_info("new data run = %d bytes\n", need_to); 713987da915Sopenharmony_ci 714987da915Sopenharmony_ci need_from = calc_attr_length(rec, need_from); 715987da915Sopenharmony_ci need_to = calc_attr_length(rec, need_to); 716987da915Sopenharmony_ci 717987da915Sopenharmony_ci ntfs_log_info("Before %d, after %d\n", need_from, need_to); 718987da915Sopenharmony_ci 719987da915Sopenharmony_ci if (need_from != need_to) { 720987da915Sopenharmony_ci if (resize_nonres_attr(ino->mrec, rec, need_to) < 0) { 721987da915Sopenharmony_ci ntfs_log_info("!resize\n"); 722987da915Sopenharmony_ci return -1; 723987da915Sopenharmony_ci } 724987da915Sopenharmony_ci } 725987da915Sopenharmony_ci 726987da915Sopenharmony_ci res = move_runlist(vol, run, to); 727987da915Sopenharmony_ci if (res < 0) { 728987da915Sopenharmony_ci ntfs_log_error("!move_runlist\n"); 729987da915Sopenharmony_ci return -1; 730987da915Sopenharmony_ci } 731987da915Sopenharmony_ci 732987da915Sopenharmony_ci // wipe orig runs 733987da915Sopenharmony_ci memset(((u8*)rec) + le16_to_cpu(rec->mapping_pairs_offset), 0, need_to - le16_to_cpu(rec->mapping_pairs_offset)); 734987da915Sopenharmony_ci 735987da915Sopenharmony_ci // update data runs 736987da915Sopenharmony_ci ntfs_mapping_pairs_build(vol, ((u8*)rec) + le16_to_cpu(rec->mapping_pairs_offset), 737987da915Sopenharmony_ci need_to, from, 0, NULL); 738987da915Sopenharmony_ci 739987da915Sopenharmony_ci // commit 740987da915Sopenharmony_ci ntfs_inode_mark_dirty(ino); 741987da915Sopenharmony_ci 742987da915Sopenharmony_ci if (ntfs_inode_sync(ino) < 0) { 743987da915Sopenharmony_ci ntfs_log_info("!sync\n"); 744987da915Sopenharmony_ci return -1; 745987da915Sopenharmony_ci } 746987da915Sopenharmony_ci 747987da915Sopenharmony_ci free(from); 748987da915Sopenharmony_ci free(to); 749987da915Sopenharmony_ci return res; 750987da915Sopenharmony_ci} 751987da915Sopenharmony_ci 752987da915Sopenharmony_ci/** 753987da915Sopenharmony_ci * move_attribute - 754987da915Sopenharmony_ci * 755987da915Sopenharmony_ci * > 0 Bytes moved / size to be moved 756987da915Sopenharmony_ci * = 0 Nothing to do 757987da915Sopenharmony_ci * < 0 Error 758987da915Sopenharmony_ci */ 759987da915Sopenharmony_cistatic s64 move_attribute(ntfs_volume *vol, ntfs_inode *ino, ATTR_RECORD *rec, 760987da915Sopenharmony_ci u64 loc, int flags) 761987da915Sopenharmony_ci{ 762987da915Sopenharmony_ci int i; 763987da915Sopenharmony_ci s64 res; 764987da915Sopenharmony_ci s64 count = 0; 765987da915Sopenharmony_ci runlist *runs; 766987da915Sopenharmony_ci 767987da915Sopenharmony_ci // NTFS_MOVE_LOC_BEST : assess how much space this attribute will need, 768987da915Sopenharmony_ci // find that space and pass the location to our children. 769987da915Sopenharmony_ci // Anything else we pass directly to move_datarun. 770987da915Sopenharmony_ci 771987da915Sopenharmony_ci runs = ntfs_mapping_pairs_decompress(vol, rec, NULL); 772987da915Sopenharmony_ci if (!runs) { 773987da915Sopenharmony_ci ntfs_log_error("!runs\n"); 774987da915Sopenharmony_ci return -1; 775987da915Sopenharmony_ci } 776987da915Sopenharmony_ci 777987da915Sopenharmony_ci //ntfs_debug_runlist_dump2(runs, 5, "\t"); 778987da915Sopenharmony_ci 779987da915Sopenharmony_ci //ntfs_log_info(" VCN LCN Length\n"); 780987da915Sopenharmony_ci for (i = 0; runs[i].length > 0; i++) { 781987da915Sopenharmony_ci if (runs[i].lcn == LCN_RL_NOT_MAPPED) { 782987da915Sopenharmony_ci continue; 783987da915Sopenharmony_ci } 784987da915Sopenharmony_ci 785987da915Sopenharmony_ci res = move_datarun(vol, ino, rec, runs+i, loc, flags); 786987da915Sopenharmony_ci //ntfs_log_info(" %8lld %8lld %8lld\n", runs[i].vcn, runs[i].lcn, runs[i].length); 787987da915Sopenharmony_ci if (res < 0) { 788987da915Sopenharmony_ci ntfs_log_error("!move_datarun\n"); 789987da915Sopenharmony_ci count = res; 790987da915Sopenharmony_ci break; 791987da915Sopenharmony_ci } 792987da915Sopenharmony_ci count += res; 793987da915Sopenharmony_ci } 794987da915Sopenharmony_ci 795987da915Sopenharmony_ci return count; 796987da915Sopenharmony_ci} 797987da915Sopenharmony_ci 798987da915Sopenharmony_ci/** 799987da915Sopenharmony_ci * move_file - 800987da915Sopenharmony_ci * 801987da915Sopenharmony_ci * > 0 Bytes moved / size to be moved 802987da915Sopenharmony_ci * = 0 Nothing to do 803987da915Sopenharmony_ci * < 0 Error 804987da915Sopenharmony_ci */ 805987da915Sopenharmony_cistatic s64 move_file(ntfs_volume *vol, ntfs_inode *ino, u64 loc, int flags) 806987da915Sopenharmony_ci{ 807987da915Sopenharmony_ci char *buffer; 808987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 809987da915Sopenharmony_ci ATTR_RECORD *rec; 810987da915Sopenharmony_ci s64 res; 811987da915Sopenharmony_ci s64 count = 0; 812987da915Sopenharmony_ci 813987da915Sopenharmony_ci buffer = malloc(MAX_PATH); 814987da915Sopenharmony_ci if (!buffer) { 815987da915Sopenharmony_ci ntfs_log_error("Out of memory\n"); 816987da915Sopenharmony_ci return -1; 817987da915Sopenharmony_ci } 818987da915Sopenharmony_ci 819987da915Sopenharmony_ci utils_inode_get_name(ino, buffer, MAX_PATH); 820987da915Sopenharmony_ci 821987da915Sopenharmony_ci if (dont_move(ino)) { 822987da915Sopenharmony_ci ntfs_log_error("can't move\n"); 823987da915Sopenharmony_ci return -1; 824987da915Sopenharmony_ci } 825987da915Sopenharmony_ci 826987da915Sopenharmony_ci ntfs_log_info("Moving %s\n", buffer); 827987da915Sopenharmony_ci 828987da915Sopenharmony_ci // NTFS_MOVE_LOC_BEST : assess how much space all the attributes will need, 829987da915Sopenharmony_ci // find that space and pass the location to our children. 830987da915Sopenharmony_ci // Anything else we pass directly to move_attribute. 831987da915Sopenharmony_ci 832987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(ino, NULL); 833987da915Sopenharmony_ci 834987da915Sopenharmony_ci while ((rec = find_attribute(AT_UNUSED, ctx))) { 835987da915Sopenharmony_ci utils_attr_get_name(vol, rec, buffer, MAX_PATH); 836987da915Sopenharmony_ci ntfs_log_info("\tAttribute 0x%02x %s is ", le32_to_cpu(rec->type), buffer); 837987da915Sopenharmony_ci 838987da915Sopenharmony_ci if (rec->non_resident) { 839987da915Sopenharmony_ci ntfs_log_info("non-resident. Moving it.\n"); 840987da915Sopenharmony_ci 841987da915Sopenharmony_ci res = move_attribute(vol, ino, rec, loc, flags); 842987da915Sopenharmony_ci if (res < 0) { 843987da915Sopenharmony_ci count = res; 844987da915Sopenharmony_ci break; 845987da915Sopenharmony_ci } 846987da915Sopenharmony_ci count += res; 847987da915Sopenharmony_ci } else { 848987da915Sopenharmony_ci ntfs_log_info("resident.\n\t\tSkipping it.\n"); 849987da915Sopenharmony_ci } 850987da915Sopenharmony_ci } 851987da915Sopenharmony_ci 852987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 853987da915Sopenharmony_ci free(buffer); 854987da915Sopenharmony_ci return count; 855987da915Sopenharmony_ci} 856987da915Sopenharmony_ci 857987da915Sopenharmony_ci 858987da915Sopenharmony_ci/** 859987da915Sopenharmony_ci * main - Begin here 860987da915Sopenharmony_ci * 861987da915Sopenharmony_ci * Start from here. 862987da915Sopenharmony_ci * 863987da915Sopenharmony_ci * Return: 0 Success, the program worked 864987da915Sopenharmony_ci * 1 Error, something went wrong 865987da915Sopenharmony_ci */ 866987da915Sopenharmony_ciint main(int argc, char *argv[]) 867987da915Sopenharmony_ci{ 868987da915Sopenharmony_ci ntfs_volume *vol; 869987da915Sopenharmony_ci ntfs_inode *inode; 870987da915Sopenharmony_ci int flags = 0; 871987da915Sopenharmony_ci int result = 1; 872987da915Sopenharmony_ci s64 count; 873987da915Sopenharmony_ci 874987da915Sopenharmony_ci ntfs_log_set_handler(ntfs_log_handler_outerr); 875987da915Sopenharmony_ci 876987da915Sopenharmony_ci if (!parse_options(argc, argv)) 877987da915Sopenharmony_ci return 1; 878987da915Sopenharmony_ci 879987da915Sopenharmony_ci utils_set_locale(); 880987da915Sopenharmony_ci 881987da915Sopenharmony_ci if (opts.noaction) 882987da915Sopenharmony_ci flags |= NTFS_MNT_RDONLY; 883987da915Sopenharmony_ci if (opts.force) 884987da915Sopenharmony_ci flags |= NTFS_MNT_RECOVER; 885987da915Sopenharmony_ci 886987da915Sopenharmony_ci vol = utils_mount_volume(opts.device, flags); 887987da915Sopenharmony_ci if (!vol) { 888987da915Sopenharmony_ci ntfs_log_info("!vol\n"); 889987da915Sopenharmony_ci return 1; 890987da915Sopenharmony_ci } 891987da915Sopenharmony_ci 892987da915Sopenharmony_ci inode = ntfs_pathname_to_inode(vol, NULL, opts.file); 893987da915Sopenharmony_ci if (!inode) { 894987da915Sopenharmony_ci ntfs_log_info("!inode\n"); 895987da915Sopenharmony_ci return 1; 896987da915Sopenharmony_ci } 897987da915Sopenharmony_ci 898987da915Sopenharmony_ci count = move_file(vol, inode, opts.location, 0); 899987da915Sopenharmony_ci if ((count > 0) && (!opts.nodirty)) { 900987da915Sopenharmony_ci 901987da915Sopenharmony_ci /* Porting note: libntfs-3g does not automatically set or clear 902987da915Sopenharmony_ci * dirty flags on mount/unmount. It always preserves them until 903987da915Sopenharmony_ci * they are explicitly changed with ntfs_volume_write_flags. 904987da915Sopenharmony_ci * This means that the dirty flag is possibly not set, but 905987da915Sopenharmony_ci * should be set. So we explicitly set it with a call to 906987da915Sopenharmony_ci * ntfs_volume_write_flags. */ 907987da915Sopenharmony_ci if(!(vol->flags & VOLUME_IS_DIRTY) && ntfs_volume_write_flags( 908987da915Sopenharmony_ci vol, vol->flags | VOLUME_IS_DIRTY)) { 909987da915Sopenharmony_ci ntfs_log_error("Error: Failed to set volume dirty " 910987da915Sopenharmony_ci "flag (%d (%s))!\n", errno, strerror(errno)); 911987da915Sopenharmony_ci } 912987da915Sopenharmony_ci 913987da915Sopenharmony_ci ntfs_log_info("Relocated %lld bytes\n", (long long)count); 914987da915Sopenharmony_ci } 915987da915Sopenharmony_ci if (count >= 0) 916987da915Sopenharmony_ci result = 0; 917987da915Sopenharmony_ci 918987da915Sopenharmony_ci if (result) 919987da915Sopenharmony_ci ntfs_log_info("failed\n"); 920987da915Sopenharmony_ci else 921987da915Sopenharmony_ci ntfs_log_info("success\n"); 922987da915Sopenharmony_ci 923987da915Sopenharmony_ci ntfs_inode_close(inode); 924987da915Sopenharmony_ci ntfs_umount(vol, FALSE); 925987da915Sopenharmony_ci return result; 926987da915Sopenharmony_ci} 927