1987da915Sopenharmony_ci/** 2987da915Sopenharmony_ci * mkntfs - Part of the Linux-NTFS project. 3987da915Sopenharmony_ci * 4987da915Sopenharmony_ci * Copyright (c) 2000-2011 Anton Altaparmakov 5987da915Sopenharmony_ci * Copyright (c) 2001-2005 Richard Russon 6987da915Sopenharmony_ci * Copyright (c) 2002-2006 Szabolcs Szakacsits 7987da915Sopenharmony_ci * Copyright (c) 2005 Erik Sornes 8987da915Sopenharmony_ci * Copyright (c) 2007 Yura Pakhuchiy 9987da915Sopenharmony_ci * Copyright (c) 2010-2018 Jean-Pierre Andre 10987da915Sopenharmony_ci * 11987da915Sopenharmony_ci * This utility will create an NTFS 1.2 or 3.1 volume on a user 12987da915Sopenharmony_ci * specified (block) device. 13987da915Sopenharmony_ci * 14987da915Sopenharmony_ci * Some things (option handling and determination of mount status) have been 15987da915Sopenharmony_ci * adapted from e2fsprogs-1.19 and lib/ext2fs/ismounted.c and misc/mke2fs.c in 16987da915Sopenharmony_ci * particular. 17987da915Sopenharmony_ci * 18987da915Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 19987da915Sopenharmony_ci * it under the terms of the GNU General Public License as published by 20987da915Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 21987da915Sopenharmony_ci * (at your option) any later version. 22987da915Sopenharmony_ci * 23987da915Sopenharmony_ci * This program is distributed in the hope that it will be useful, 24987da915Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 25987da915Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26987da915Sopenharmony_ci * GNU General Public License for more details. 27987da915Sopenharmony_ci * 28987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License 29987da915Sopenharmony_ci * along with this program (in the main directory of the Linux-NTFS source 30987da915Sopenharmony_ci * in the file COPYING); if not, write to the Free Software Foundation, 31987da915Sopenharmony_ci * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 32987da915Sopenharmony_ci */ 33987da915Sopenharmony_ci 34987da915Sopenharmony_ci#ifdef HAVE_CONFIG_H 35987da915Sopenharmony_ci#include "config.h" 36987da915Sopenharmony_ci#endif 37987da915Sopenharmony_ci 38987da915Sopenharmony_ci#ifdef HAVE_UNISTD_H 39987da915Sopenharmony_ci#include <unistd.h> 40987da915Sopenharmony_ci#endif 41987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H 42987da915Sopenharmony_ci#include <stdlib.h> 43987da915Sopenharmony_ci#endif 44987da915Sopenharmony_ci#ifdef HAVE_STDIO_H 45987da915Sopenharmony_ci#include <stdio.h> 46987da915Sopenharmony_ci#endif 47987da915Sopenharmony_ci#ifdef HAVE_STDARG_H 48987da915Sopenharmony_ci#include <stdarg.h> 49987da915Sopenharmony_ci#endif 50987da915Sopenharmony_ci#ifdef HAVE_STRING_H 51987da915Sopenharmony_ci#include <string.h> 52987da915Sopenharmony_ci#endif 53987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H 54987da915Sopenharmony_ci#include <errno.h> 55987da915Sopenharmony_ci#endif 56987da915Sopenharmony_ci#ifdef HAVE_TIME_H 57987da915Sopenharmony_ci#include <time.h> 58987da915Sopenharmony_ci#endif 59987da915Sopenharmony_ci#ifdef HAVE_SYS_STAT_H 60987da915Sopenharmony_ci#include <sys/stat.h> 61987da915Sopenharmony_ci#endif 62987da915Sopenharmony_ci#ifdef HAVE_FCNTL_H 63987da915Sopenharmony_ci#include <fcntl.h> 64987da915Sopenharmony_ci#endif 65987da915Sopenharmony_ci#ifdef HAVE_LIMITS_H 66987da915Sopenharmony_ci#include <limits.h> 67987da915Sopenharmony_ci#endif 68987da915Sopenharmony_ci#ifdef HAVE_LIBGEN_H 69987da915Sopenharmony_ci#include <libgen.h> 70987da915Sopenharmony_ci#endif 71987da915Sopenharmony_ci#ifdef ENABLE_UUID 72987da915Sopenharmony_ci#include <uuid/uuid.h> 73987da915Sopenharmony_ci#endif 74987da915Sopenharmony_ci 75987da915Sopenharmony_ci 76987da915Sopenharmony_ci#ifdef HAVE_GETOPT_H 77987da915Sopenharmony_ci#include <getopt.h> 78987da915Sopenharmony_ci#else 79987da915Sopenharmony_ci extern char *optarg; 80987da915Sopenharmony_ci extern int optind; 81987da915Sopenharmony_ci#endif 82987da915Sopenharmony_ci 83987da915Sopenharmony_ci#ifdef HAVE_LINUX_MAJOR_H 84987da915Sopenharmony_ci# include <linux/major.h> 85987da915Sopenharmony_ci# ifndef MAJOR 86987da915Sopenharmony_ci# define MAJOR(dev) ((dev) >> 8) 87987da915Sopenharmony_ci# define MINOR(dev) ((dev) & 0xff) 88987da915Sopenharmony_ci# endif 89987da915Sopenharmony_ci# ifndef IDE_DISK_MAJOR 90987da915Sopenharmony_ci# ifndef IDE0_MAJOR 91987da915Sopenharmony_ci# define IDE0_MAJOR 3 92987da915Sopenharmony_ci# define IDE1_MAJOR 22 93987da915Sopenharmony_ci# define IDE2_MAJOR 33 94987da915Sopenharmony_ci# define IDE3_MAJOR 34 95987da915Sopenharmony_ci# define IDE4_MAJOR 56 96987da915Sopenharmony_ci# define IDE5_MAJOR 57 97987da915Sopenharmony_ci# define IDE6_MAJOR 88 98987da915Sopenharmony_ci# define IDE7_MAJOR 89 99987da915Sopenharmony_ci# define IDE8_MAJOR 90 100987da915Sopenharmony_ci# define IDE9_MAJOR 91 101987da915Sopenharmony_ci# endif 102987da915Sopenharmony_ci# define IDE_DISK_MAJOR(M) \ 103987da915Sopenharmony_ci ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \ 104987da915Sopenharmony_ci (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \ 105987da915Sopenharmony_ci (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \ 106987da915Sopenharmony_ci (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \ 107987da915Sopenharmony_ci (M) == IDE8_MAJOR || (M) == IDE9_MAJOR) 108987da915Sopenharmony_ci# endif 109987da915Sopenharmony_ci# ifndef SCSI_DISK_MAJOR 110987da915Sopenharmony_ci# ifndef SCSI_DISK0_MAJOR 111987da915Sopenharmony_ci# define SCSI_DISK0_MAJOR 8 112987da915Sopenharmony_ci# define SCSI_DISK1_MAJOR 65 113987da915Sopenharmony_ci# define SCSI_DISK7_MAJOR 71 114987da915Sopenharmony_ci# endif 115987da915Sopenharmony_ci# define SCSI_DISK_MAJOR(M) \ 116987da915Sopenharmony_ci ((M) == SCSI_DISK0_MAJOR || \ 117987da915Sopenharmony_ci ((M) >= SCSI_DISK1_MAJOR && \ 118987da915Sopenharmony_ci (M) <= SCSI_DISK7_MAJOR)) 119987da915Sopenharmony_ci# endif 120987da915Sopenharmony_ci#endif 121987da915Sopenharmony_ci 122987da915Sopenharmony_ci#include "param.h" 123987da915Sopenharmony_ci#include "security.h" 124987da915Sopenharmony_ci#include "types.h" 125987da915Sopenharmony_ci#include "attrib.h" 126987da915Sopenharmony_ci#include "bitmap.h" 127987da915Sopenharmony_ci#include "bootsect.h" 128987da915Sopenharmony_ci#include "device.h" 129987da915Sopenharmony_ci#include "dir.h" 130987da915Sopenharmony_ci#include "mft.h" 131987da915Sopenharmony_ci#include "mst.h" 132987da915Sopenharmony_ci#include "runlist.h" 133987da915Sopenharmony_ci#include "utils.h" 134987da915Sopenharmony_ci#include "ntfstime.h" 135987da915Sopenharmony_ci#include "sd.h" 136987da915Sopenharmony_ci#include "boot.h" 137987da915Sopenharmony_ci#include "attrdef.h" 138987da915Sopenharmony_ci/* #include "version.h" */ 139987da915Sopenharmony_ci#include "logging.h" 140987da915Sopenharmony_ci#include "support.h" 141987da915Sopenharmony_ci#include "unistr.h" 142987da915Sopenharmony_ci#include "misc.h" 143987da915Sopenharmony_ci 144987da915Sopenharmony_ci#if defined(__sun) && defined (__SVR4) 145987da915Sopenharmony_ci#undef basename 146987da915Sopenharmony_ci#define basename(name) name 147987da915Sopenharmony_ci#endif 148987da915Sopenharmony_ci 149987da915Sopenharmony_citypedef enum { WRITE_STANDARD, WRITE_BITMAP, WRITE_LOGFILE } WRITE_TYPE; 150987da915Sopenharmony_ci 151987da915Sopenharmony_ci#ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS 152987da915Sopenharmony_ci#error "No default device io operations! Cannot build mkntfs. \ 153987da915Sopenharmony_ciYou need to run ./configure without the --disable-default-device-io-ops \ 154987da915Sopenharmony_ciswitch if you want to be able to build the NTFS utilities." 155987da915Sopenharmony_ci#endif 156987da915Sopenharmony_ci 157987da915Sopenharmony_ci/* Page size on ia32. Can change to 8192 on Alpha. */ 158987da915Sopenharmony_ci#define NTFS_PAGE_SIZE 4096 159987da915Sopenharmony_ci 160987da915Sopenharmony_cistatic char EXEC_NAME[] = "mkntfs"; 161987da915Sopenharmony_ci 162987da915Sopenharmony_cistruct BITMAP_ALLOCATION { 163987da915Sopenharmony_ci struct BITMAP_ALLOCATION *next; 164987da915Sopenharmony_ci LCN lcn; /* first allocated cluster */ 165987da915Sopenharmony_ci s64 length; /* count of consecutive clusters */ 166987da915Sopenharmony_ci} ; 167987da915Sopenharmony_ci 168987da915Sopenharmony_ci /* Upcase $Info, used since Windows 8 */ 169987da915Sopenharmony_cistruct UPCASEINFO { 170987da915Sopenharmony_ci le32 len; 171987da915Sopenharmony_ci le32 filler; 172987da915Sopenharmony_ci le64 crc; 173987da915Sopenharmony_ci le32 osmajor; 174987da915Sopenharmony_ci le32 osminor; 175987da915Sopenharmony_ci le32 build; 176987da915Sopenharmony_ci le16 packmajor; 177987da915Sopenharmony_ci le16 packminor; 178987da915Sopenharmony_ci} ; 179987da915Sopenharmony_ci 180987da915Sopenharmony_ci/** 181987da915Sopenharmony_ci * global variables 182987da915Sopenharmony_ci */ 183987da915Sopenharmony_cistatic u8 *g_buf = NULL; 184987da915Sopenharmony_cistatic int g_mft_bitmap_byte_size = 0; 185987da915Sopenharmony_cistatic u8 *g_mft_bitmap = NULL; 186987da915Sopenharmony_cistatic int g_lcn_bitmap_byte_size = 0; 187987da915Sopenharmony_cistatic int g_dynamic_buf_size = 0; 188987da915Sopenharmony_cistatic u8 *g_dynamic_buf = NULL; 189987da915Sopenharmony_cistatic struct UPCASEINFO *g_upcaseinfo = NULL; 190987da915Sopenharmony_cistatic runlist *g_rl_mft = NULL; 191987da915Sopenharmony_cistatic runlist *g_rl_mft_bmp = NULL; 192987da915Sopenharmony_cistatic runlist *g_rl_mftmirr = NULL; 193987da915Sopenharmony_cistatic runlist *g_rl_logfile = NULL; 194987da915Sopenharmony_cistatic runlist *g_rl_boot = NULL; 195987da915Sopenharmony_cistatic runlist *g_rl_bad = NULL; 196987da915Sopenharmony_cistatic INDEX_ALLOCATION *g_index_block = NULL; 197987da915Sopenharmony_cistatic ntfs_volume *g_vol = NULL; 198987da915Sopenharmony_cistatic int g_mft_size = 0; 199987da915Sopenharmony_cistatic long long g_mft_lcn = 0; /* lcn of $MFT, $DATA attribute */ 200987da915Sopenharmony_cistatic long long g_mftmirr_lcn = 0; /* lcn of $MFTMirr, $DATA */ 201987da915Sopenharmony_cistatic long long g_logfile_lcn = 0; /* lcn of $LogFile, $DATA */ 202987da915Sopenharmony_cistatic int g_logfile_size = 0; /* in bytes, determined from volume_size */ 203987da915Sopenharmony_cistatic long long g_mft_zone_end = 0; /* Determined from volume_size and mft_zone_multiplier, in clusters */ 204987da915Sopenharmony_cistatic long long g_num_bad_blocks = 0; /* Number of bad clusters */ 205987da915Sopenharmony_cistatic long long *g_bad_blocks = NULL; /* Array of bad clusters */ 206987da915Sopenharmony_ci 207987da915Sopenharmony_cistatic struct BITMAP_ALLOCATION *g_allocation = NULL; /* Head of cluster allocations */ 208987da915Sopenharmony_ci 209987da915Sopenharmony_ci/** 210987da915Sopenharmony_ci * struct mkntfs_options 211987da915Sopenharmony_ci */ 212987da915Sopenharmony_cistatic struct mkntfs_options { 213987da915Sopenharmony_ci char *dev_name; /* Name of the device, or file, to use */ 214987da915Sopenharmony_ci BOOL enable_compression; /* -C, enables compression of all files on the volume by default. */ 215987da915Sopenharmony_ci BOOL quick_format; /* -f or -Q, fast format, don't zero the volume first. */ 216987da915Sopenharmony_ci BOOL force; /* -F, force fs creation. */ 217987da915Sopenharmony_ci long heads; /* -H, number of heads on device */ 218987da915Sopenharmony_ci BOOL disable_indexing; /* -I, disables indexing of file contents on the volume by default. */ 219987da915Sopenharmony_ci BOOL no_action; /* -n, do not write to device, only display what would be done. */ 220987da915Sopenharmony_ci long long part_start_sect; /* -p, start sector of partition on parent device */ 221987da915Sopenharmony_ci long sector_size; /* -s, in bytes, power of 2, default is 512 bytes. */ 222987da915Sopenharmony_ci long sectors_per_track; /* -S, number of sectors per track on device */ 223987da915Sopenharmony_ci BOOL use_epoch_time; /* -T, fake the time to be 00:00:00 UTC, Jan 1, 1970. */ 224987da915Sopenharmony_ci long mft_zone_multiplier; /* -z, value from 1 to 4. Default is 1. */ 225987da915Sopenharmony_ci long long num_sectors; /* size of device in sectors */ 226987da915Sopenharmony_ci long cluster_size; /* -c, format with this cluster-size */ 227987da915Sopenharmony_ci BOOL with_uuid; /* -U, request setting an uuid */ 228987da915Sopenharmony_ci char *label; /* -L, volume label */ 229987da915Sopenharmony_ci} opts; 230987da915Sopenharmony_ci 231987da915Sopenharmony_ci 232987da915Sopenharmony_ci/** 233987da915Sopenharmony_ci * mkntfs_license 234987da915Sopenharmony_ci */ 235987da915Sopenharmony_cistatic void mkntfs_license(void) 236987da915Sopenharmony_ci{ 237987da915Sopenharmony_ci ntfs_log_info("%s", ntfs_gpl); 238987da915Sopenharmony_ci} 239987da915Sopenharmony_ci 240987da915Sopenharmony_ci/** 241987da915Sopenharmony_ci * mkntfs_usage 242987da915Sopenharmony_ci */ 243987da915Sopenharmony_cistatic void mkntfs_usage(void) 244987da915Sopenharmony_ci{ 245987da915Sopenharmony_ci ntfs_log_info("\nUsage: %s [options] device [number-of-sectors]\n" 246987da915Sopenharmony_ci"\n" 247987da915Sopenharmony_ci"Basic options:\n" 248987da915Sopenharmony_ci" -f, --fast Perform a quick format\n" 249987da915Sopenharmony_ci" -Q, --quick Perform a quick format\n" 250987da915Sopenharmony_ci" -L, --label STRING Set the volume label\n" 251987da915Sopenharmony_ci" -C, --enable-compression Enable compression on the volume\n" 252987da915Sopenharmony_ci" -I, --no-indexing Disable indexing on the volume\n" 253987da915Sopenharmony_ci" -n, --no-action Do not write to disk\n" 254987da915Sopenharmony_ci"\n" 255987da915Sopenharmony_ci"Advanced options:\n" 256987da915Sopenharmony_ci" -c, --cluster-size BYTES Specify the cluster size for the volume\n" 257987da915Sopenharmony_ci" -s, --sector-size BYTES Specify the sector size for the device\n" 258987da915Sopenharmony_ci" -p, --partition-start SECTOR Specify the partition start sector\n" 259987da915Sopenharmony_ci" -H, --heads NUM Specify the number of heads\n" 260987da915Sopenharmony_ci" -S, --sectors-per-track NUM Specify the number of sectors per track\n" 261987da915Sopenharmony_ci" -z, --mft-zone-multiplier NUM Set the MFT zone multiplier\n" 262987da915Sopenharmony_ci" -T, --zero-time Fake the time to be 00:00 UTC, Jan 1, 1970\n" 263987da915Sopenharmony_ci" -F, --force Force execution despite errors\n" 264987da915Sopenharmony_ci"\n" 265987da915Sopenharmony_ci"Output options:\n" 266987da915Sopenharmony_ci" -q, --quiet Quiet execution\n" 267987da915Sopenharmony_ci" -v, --verbose Verbose execution\n" 268987da915Sopenharmony_ci" --debug Very verbose execution\n" 269987da915Sopenharmony_ci"\n" 270987da915Sopenharmony_ci"Help options:\n" 271987da915Sopenharmony_ci" -V, --version Display version\n" 272987da915Sopenharmony_ci" -l, --license Display licensing information\n" 273987da915Sopenharmony_ci" -h, --help Display this help\n" 274987da915Sopenharmony_ci"\n", basename(EXEC_NAME)); 275987da915Sopenharmony_ci ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); 276987da915Sopenharmony_ci} 277987da915Sopenharmony_ci 278987da915Sopenharmony_ci/** 279987da915Sopenharmony_ci * mkntfs_version 280987da915Sopenharmony_ci */ 281987da915Sopenharmony_cistatic void mkntfs_version(void) 282987da915Sopenharmony_ci{ 283987da915Sopenharmony_ci ntfs_log_info("\n%s v%s (libntfs-3g)\n\n", EXEC_NAME, VERSION); 284987da915Sopenharmony_ci ntfs_log_info("Create an NTFS volume on a user specified (block) " 285987da915Sopenharmony_ci "device.\n\n"); 286987da915Sopenharmony_ci ntfs_log_info("Copyright (c) 2000-2007 Anton Altaparmakov\n"); 287987da915Sopenharmony_ci ntfs_log_info("Copyright (c) 2001-2005 Richard Russon\n"); 288987da915Sopenharmony_ci ntfs_log_info("Copyright (c) 2002-2006 Szabolcs Szakacsits\n"); 289987da915Sopenharmony_ci ntfs_log_info("Copyright (c) 2005 Erik Sornes\n"); 290987da915Sopenharmony_ci ntfs_log_info("Copyright (c) 2007 Yura Pakhuchiy\n"); 291987da915Sopenharmony_ci ntfs_log_info("Copyright (c) 2010-2018 Jean-Pierre Andre\n"); 292987da915Sopenharmony_ci ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); 293987da915Sopenharmony_ci} 294987da915Sopenharmony_ci 295987da915Sopenharmony_ci/* 296987da915Sopenharmony_ci * crc64, adapted from http://rpm5.org/docs/api/digest_8c-source.html 297987da915Sopenharmony_ci * ECMA-182 polynomial, see 298987da915Sopenharmony_ci * http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-182.pdf 299987da915Sopenharmony_ci */ 300987da915Sopenharmony_ci /* make sure the needed types are defined */ 301987da915Sopenharmony_ci#undef byte 302987da915Sopenharmony_ci#undef uint32_t 303987da915Sopenharmony_ci#undef uint64_t 304987da915Sopenharmony_ci#define byte u8 305987da915Sopenharmony_ci#define uint32_t u32 306987da915Sopenharmony_ci#define uint64_t u64 307987da915Sopenharmony_cistatic uint64_t crc64(uint64_t crc, const byte * data, size_t size) 308987da915Sopenharmony_ci /*@*/ 309987da915Sopenharmony_ci{ 310987da915Sopenharmony_ci static uint64_t polynomial = 0x9a6c9329ac4bc9b5ULL; 311987da915Sopenharmony_ci static uint64_t xorout = 0xffffffffffffffffULL; 312987da915Sopenharmony_ci static uint64_t table[256]; 313987da915Sopenharmony_ci 314987da915Sopenharmony_ci crc ^= xorout; 315987da915Sopenharmony_ci 316987da915Sopenharmony_ci if (data == NULL) { 317987da915Sopenharmony_ci /* generate the table of CRC remainders for all possible bytes */ 318987da915Sopenharmony_ci uint64_t c; 319987da915Sopenharmony_ci uint32_t i, j; 320987da915Sopenharmony_ci for (i = 0; i < 256; i++) { 321987da915Sopenharmony_ci c = i; 322987da915Sopenharmony_ci for (j = 0; j < 8; j++) { 323987da915Sopenharmony_ci if (c & 1) 324987da915Sopenharmony_ci c = polynomial ^ (c >> 1); 325987da915Sopenharmony_ci else 326987da915Sopenharmony_ci c = (c >> 1); 327987da915Sopenharmony_ci } 328987da915Sopenharmony_ci table[i] = c; 329987da915Sopenharmony_ci } 330987da915Sopenharmony_ci } else 331987da915Sopenharmony_ci while (size) { 332987da915Sopenharmony_ci crc = table[(crc ^ *data) & 0xff] ^ (crc >> 8); 333987da915Sopenharmony_ci size--; 334987da915Sopenharmony_ci data++; 335987da915Sopenharmony_ci } 336987da915Sopenharmony_ci 337987da915Sopenharmony_ci crc ^= xorout; 338987da915Sopenharmony_ci 339987da915Sopenharmony_ci return crc; 340987da915Sopenharmony_ci} 341987da915Sopenharmony_ci 342987da915Sopenharmony_ci/* 343987da915Sopenharmony_ci * Mark a run of clusters as allocated 344987da915Sopenharmony_ci * 345987da915Sopenharmony_ci * Returns FALSE if unsuccessful 346987da915Sopenharmony_ci */ 347987da915Sopenharmony_ci 348987da915Sopenharmony_cistatic BOOL bitmap_allocate(LCN lcn, s64 length) 349987da915Sopenharmony_ci{ 350987da915Sopenharmony_ci BOOL done; 351987da915Sopenharmony_ci struct BITMAP_ALLOCATION *p; 352987da915Sopenharmony_ci struct BITMAP_ALLOCATION *q; 353987da915Sopenharmony_ci struct BITMAP_ALLOCATION *newall; 354987da915Sopenharmony_ci 355987da915Sopenharmony_ci done = TRUE; 356987da915Sopenharmony_ci if (length) { 357987da915Sopenharmony_ci p = g_allocation; 358987da915Sopenharmony_ci q = (struct BITMAP_ALLOCATION*)NULL; 359987da915Sopenharmony_ci /* locate the first run which starts beyond the requested lcn */ 360987da915Sopenharmony_ci while (p && (p->lcn <= lcn)) { 361987da915Sopenharmony_ci q = p; 362987da915Sopenharmony_ci p = p->next; 363987da915Sopenharmony_ci } 364987da915Sopenharmony_ci /* make sure the requested lcns were not allocated */ 365987da915Sopenharmony_ci if ((q && ((q->lcn + q->length) > lcn)) 366987da915Sopenharmony_ci || (p && ((lcn + length) > p->lcn))) { 367987da915Sopenharmony_ci ntfs_log_error("Bitmap allocation error\n"); 368987da915Sopenharmony_ci done = FALSE; 369987da915Sopenharmony_ci } 370987da915Sopenharmony_ci if (q && ((q->lcn + q->length) == lcn)) { 371987da915Sopenharmony_ci /* extend current run, no overlapping possible */ 372987da915Sopenharmony_ci q->length += length; 373987da915Sopenharmony_ci } else { 374987da915Sopenharmony_ci newall = (struct BITMAP_ALLOCATION*) 375987da915Sopenharmony_ci ntfs_malloc(sizeof(struct BITMAP_ALLOCATION)); 376987da915Sopenharmony_ci if (newall) { 377987da915Sopenharmony_ci newall->lcn = lcn; 378987da915Sopenharmony_ci newall->length = length; 379987da915Sopenharmony_ci newall->next = p; 380987da915Sopenharmony_ci if (q) q->next = newall; 381987da915Sopenharmony_ci else g_allocation = newall; 382987da915Sopenharmony_ci } else { 383987da915Sopenharmony_ci done = FALSE; 384987da915Sopenharmony_ci ntfs_log_perror("Not enough memory"); 385987da915Sopenharmony_ci } 386987da915Sopenharmony_ci } 387987da915Sopenharmony_ci } 388987da915Sopenharmony_ci return (done); 389987da915Sopenharmony_ci} 390987da915Sopenharmony_ci 391987da915Sopenharmony_ci/* 392987da915Sopenharmony_ci * Mark a run of cluster as not allocated 393987da915Sopenharmony_ci * 394987da915Sopenharmony_ci * Returns FALSE if unsuccessful 395987da915Sopenharmony_ci * (freeing free clusters is not considered as an error) 396987da915Sopenharmony_ci */ 397987da915Sopenharmony_ci 398987da915Sopenharmony_cistatic BOOL bitmap_deallocate(LCN lcn, s64 length) 399987da915Sopenharmony_ci{ 400987da915Sopenharmony_ci BOOL done; 401987da915Sopenharmony_ci struct BITMAP_ALLOCATION *p; 402987da915Sopenharmony_ci struct BITMAP_ALLOCATION *q; 403987da915Sopenharmony_ci LCN first, last; 404987da915Sopenharmony_ci s64 begin_length, end_length; 405987da915Sopenharmony_ci 406987da915Sopenharmony_ci done = TRUE; 407987da915Sopenharmony_ci if (length) { 408987da915Sopenharmony_ci p = g_allocation; 409987da915Sopenharmony_ci q = (struct BITMAP_ALLOCATION*)NULL; 410987da915Sopenharmony_ci /* locate a run which has a common portion */ 411987da915Sopenharmony_ci while (p) { 412987da915Sopenharmony_ci first = (p->lcn > lcn ? p->lcn : lcn); 413987da915Sopenharmony_ci last = ((p->lcn + p->length) < (lcn + length) 414987da915Sopenharmony_ci ? p->lcn + p->length : lcn + length); 415987da915Sopenharmony_ci if (first < last) { 416987da915Sopenharmony_ci /* get the parts which must be kept */ 417987da915Sopenharmony_ci begin_length = first - p->lcn; 418987da915Sopenharmony_ci end_length = p->lcn + p->length - last; 419987da915Sopenharmony_ci /* delete the entry */ 420987da915Sopenharmony_ci if (q) 421987da915Sopenharmony_ci q->next = p->next; 422987da915Sopenharmony_ci else 423987da915Sopenharmony_ci g_allocation = p->next; 424987da915Sopenharmony_ci free(p); 425987da915Sopenharmony_ci /* reallocate the beginning and the end */ 426987da915Sopenharmony_ci if (begin_length 427987da915Sopenharmony_ci && !bitmap_allocate(first - begin_length, 428987da915Sopenharmony_ci begin_length)) 429987da915Sopenharmony_ci done = FALSE; 430987da915Sopenharmony_ci if (end_length 431987da915Sopenharmony_ci && !bitmap_allocate(last, end_length)) 432987da915Sopenharmony_ci done = FALSE; 433987da915Sopenharmony_ci /* restart a full search */ 434987da915Sopenharmony_ci p = g_allocation; 435987da915Sopenharmony_ci q = (struct BITMAP_ALLOCATION*)NULL; 436987da915Sopenharmony_ci } else { 437987da915Sopenharmony_ci q = p; 438987da915Sopenharmony_ci p = p->next; 439987da915Sopenharmony_ci } 440987da915Sopenharmony_ci } 441987da915Sopenharmony_ci } 442987da915Sopenharmony_ci return (done); 443987da915Sopenharmony_ci} 444987da915Sopenharmony_ci 445987da915Sopenharmony_ci/* 446987da915Sopenharmony_ci * Get the allocation status of a single cluster 447987da915Sopenharmony_ci * and mark as allocated 448987da915Sopenharmony_ci * 449987da915Sopenharmony_ci * Returns 1 if the cluster was previously allocated 450987da915Sopenharmony_ci */ 451987da915Sopenharmony_ci 452987da915Sopenharmony_cistatic int bitmap_get_and_set(LCN lcn, unsigned long length) 453987da915Sopenharmony_ci{ 454987da915Sopenharmony_ci struct BITMAP_ALLOCATION *p; 455987da915Sopenharmony_ci struct BITMAP_ALLOCATION *q; 456987da915Sopenharmony_ci int bit; 457987da915Sopenharmony_ci 458987da915Sopenharmony_ci if (length == 1) { 459987da915Sopenharmony_ci p = g_allocation; 460987da915Sopenharmony_ci q = (struct BITMAP_ALLOCATION*)NULL; 461987da915Sopenharmony_ci /* locate the first run which starts beyond the requested lcn */ 462987da915Sopenharmony_ci while (p && (p->lcn <= lcn)) { 463987da915Sopenharmony_ci q = p; 464987da915Sopenharmony_ci p = p->next; 465987da915Sopenharmony_ci } 466987da915Sopenharmony_ci if (q && (q->lcn <= lcn) && ((q->lcn + q->length) > lcn)) 467987da915Sopenharmony_ci bit = 1; /* was allocated */ 468987da915Sopenharmony_ci else { 469987da915Sopenharmony_ci bitmap_allocate(lcn, length); 470987da915Sopenharmony_ci bit = 0; 471987da915Sopenharmony_ci } 472987da915Sopenharmony_ci } else { 473987da915Sopenharmony_ci ntfs_log_error("Can only allocate a single cluster at a time\n"); 474987da915Sopenharmony_ci bit = 0; 475987da915Sopenharmony_ci } 476987da915Sopenharmony_ci return (bit); 477987da915Sopenharmony_ci} 478987da915Sopenharmony_ci 479987da915Sopenharmony_ci/* 480987da915Sopenharmony_ci * Build a section of the bitmap according to allocation 481987da915Sopenharmony_ci */ 482987da915Sopenharmony_ci 483987da915Sopenharmony_cistatic void bitmap_build(u8 *buf, LCN lcn, s64 length) 484987da915Sopenharmony_ci{ 485987da915Sopenharmony_ci struct BITMAP_ALLOCATION *p; 486987da915Sopenharmony_ci LCN first, last; 487987da915Sopenharmony_ci int j; /* byte number */ 488987da915Sopenharmony_ci int bn; /* bit number */ 489987da915Sopenharmony_ci 490987da915Sopenharmony_ci for (j=0; (8*j)<length; j++) 491987da915Sopenharmony_ci buf[j] = 0; 492987da915Sopenharmony_ci for (p=g_allocation; p; p=p->next) { 493987da915Sopenharmony_ci first = (p->lcn > lcn ? p->lcn : lcn); 494987da915Sopenharmony_ci last = ((p->lcn + p->length) < (lcn + length) 495987da915Sopenharmony_ci ? p->lcn + p->length : lcn + length); 496987da915Sopenharmony_ci if (first < last) { 497987da915Sopenharmony_ci bn = first - lcn; 498987da915Sopenharmony_ci /* initial partial byte, if any */ 499987da915Sopenharmony_ci while ((bn < (last - lcn)) && (bn & 7)) { 500987da915Sopenharmony_ci buf[bn >> 3] |= 1 << (bn & 7); 501987da915Sopenharmony_ci bn++; 502987da915Sopenharmony_ci } 503987da915Sopenharmony_ci /* full bytes */ 504987da915Sopenharmony_ci while (bn < (last - lcn - 7)) { 505987da915Sopenharmony_ci buf[bn >> 3] = 255; 506987da915Sopenharmony_ci bn += 8; 507987da915Sopenharmony_ci } 508987da915Sopenharmony_ci /* final partial byte, if any */ 509987da915Sopenharmony_ci while (bn < (last - lcn)) { 510987da915Sopenharmony_ci buf[bn >> 3] |= 1 << (bn & 7); 511987da915Sopenharmony_ci bn++; 512987da915Sopenharmony_ci } 513987da915Sopenharmony_ci } 514987da915Sopenharmony_ci } 515987da915Sopenharmony_ci} 516987da915Sopenharmony_ci 517987da915Sopenharmony_ci/** 518987da915Sopenharmony_ci * mkntfs_parse_long 519987da915Sopenharmony_ci */ 520987da915Sopenharmony_cistatic BOOL mkntfs_parse_long(const char *string, const char *name, long *num) 521987da915Sopenharmony_ci{ 522987da915Sopenharmony_ci char *end = NULL; 523987da915Sopenharmony_ci long tmp; 524987da915Sopenharmony_ci 525987da915Sopenharmony_ci if (!string || !name || !num) 526987da915Sopenharmony_ci return FALSE; 527987da915Sopenharmony_ci 528987da915Sopenharmony_ci if (*num >= 0) { 529987da915Sopenharmony_ci ntfs_log_error("You may only specify the %s once.\n", name); 530987da915Sopenharmony_ci return FALSE; 531987da915Sopenharmony_ci } 532987da915Sopenharmony_ci 533987da915Sopenharmony_ci tmp = strtol(string, &end, 0); 534987da915Sopenharmony_ci if (end && *end) { 535987da915Sopenharmony_ci ntfs_log_error("Cannot understand the %s '%s'.\n", name, string); 536987da915Sopenharmony_ci return FALSE; 537987da915Sopenharmony_ci } else { 538987da915Sopenharmony_ci *num = tmp; 539987da915Sopenharmony_ci return TRUE; 540987da915Sopenharmony_ci } 541987da915Sopenharmony_ci} 542987da915Sopenharmony_ci 543987da915Sopenharmony_ci/** 544987da915Sopenharmony_ci * mkntfs_parse_llong 545987da915Sopenharmony_ci */ 546987da915Sopenharmony_cistatic BOOL mkntfs_parse_llong(const char *string, const char *name, 547987da915Sopenharmony_ci long long *num) 548987da915Sopenharmony_ci{ 549987da915Sopenharmony_ci char *end = NULL; 550987da915Sopenharmony_ci long long tmp; 551987da915Sopenharmony_ci 552987da915Sopenharmony_ci if (!string || !name || !num) 553987da915Sopenharmony_ci return FALSE; 554987da915Sopenharmony_ci 555987da915Sopenharmony_ci if (*num >= 0) { 556987da915Sopenharmony_ci ntfs_log_error("You may only specify the %s once.\n", name); 557987da915Sopenharmony_ci return FALSE; 558987da915Sopenharmony_ci } 559987da915Sopenharmony_ci 560987da915Sopenharmony_ci tmp = strtoll(string, &end, 0); 561987da915Sopenharmony_ci if (end && *end) { 562987da915Sopenharmony_ci ntfs_log_error("Cannot understand the %s '%s'.\n", name, 563987da915Sopenharmony_ci string); 564987da915Sopenharmony_ci return FALSE; 565987da915Sopenharmony_ci } else { 566987da915Sopenharmony_ci *num = tmp; 567987da915Sopenharmony_ci return TRUE; 568987da915Sopenharmony_ci } 569987da915Sopenharmony_ci} 570987da915Sopenharmony_ci 571987da915Sopenharmony_ci/** 572987da915Sopenharmony_ci * mkntfs_init_options 573987da915Sopenharmony_ci */ 574987da915Sopenharmony_cistatic void mkntfs_init_options(struct mkntfs_options *opts2) 575987da915Sopenharmony_ci{ 576987da915Sopenharmony_ci if (!opts2) 577987da915Sopenharmony_ci return; 578987da915Sopenharmony_ci 579987da915Sopenharmony_ci memset(opts2, 0, sizeof(*opts2)); 580987da915Sopenharmony_ci 581987da915Sopenharmony_ci /* Mark all the numeric options as "unset". */ 582987da915Sopenharmony_ci opts2->cluster_size = -1; 583987da915Sopenharmony_ci opts2->heads = -1; 584987da915Sopenharmony_ci opts2->mft_zone_multiplier = -1; 585987da915Sopenharmony_ci opts2->num_sectors = -1; 586987da915Sopenharmony_ci opts2->part_start_sect = -1; 587987da915Sopenharmony_ci opts2->sector_size = -1; 588987da915Sopenharmony_ci opts2->sectors_per_track = -1; 589987da915Sopenharmony_ci} 590987da915Sopenharmony_ci 591987da915Sopenharmony_ci/** 592987da915Sopenharmony_ci * mkntfs_parse_options 593987da915Sopenharmony_ci */ 594987da915Sopenharmony_cistatic int mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options *opts2) 595987da915Sopenharmony_ci{ 596987da915Sopenharmony_ci static const char *sopt = "-c:CfFhH:IlL:np:qQs:S:TUvVz:"; 597987da915Sopenharmony_ci static const struct option lopt[] = { 598987da915Sopenharmony_ci { "cluster-size", required_argument, NULL, 'c' }, 599987da915Sopenharmony_ci { "debug", no_argument, NULL, 'Z' }, 600987da915Sopenharmony_ci { "enable-compression", no_argument, NULL, 'C' }, 601987da915Sopenharmony_ci { "fast", no_argument, NULL, 'f' }, 602987da915Sopenharmony_ci { "force", no_argument, NULL, 'F' }, 603987da915Sopenharmony_ci { "heads", required_argument, NULL, 'H' }, 604987da915Sopenharmony_ci { "help", no_argument, NULL, 'h' }, 605987da915Sopenharmony_ci { "label", required_argument, NULL, 'L' }, 606987da915Sopenharmony_ci { "license", no_argument, NULL, 'l' }, 607987da915Sopenharmony_ci { "mft-zone-multiplier",required_argument, NULL, 'z' }, 608987da915Sopenharmony_ci { "no-action", no_argument, NULL, 'n' }, 609987da915Sopenharmony_ci { "no-indexing", no_argument, NULL, 'I' }, 610987da915Sopenharmony_ci { "partition-start", required_argument, NULL, 'p' }, 611987da915Sopenharmony_ci { "quick", no_argument, NULL, 'Q' }, 612987da915Sopenharmony_ci { "quiet", no_argument, NULL, 'q' }, 613987da915Sopenharmony_ci { "sector-size", required_argument, NULL, 's' }, 614987da915Sopenharmony_ci { "sectors-per-track", required_argument, NULL, 'S' }, 615987da915Sopenharmony_ci { "with-uuid", no_argument, NULL, 'U' }, 616987da915Sopenharmony_ci { "verbose", no_argument, NULL, 'v' }, 617987da915Sopenharmony_ci { "version", no_argument, NULL, 'V' }, 618987da915Sopenharmony_ci { "zero-time", no_argument, NULL, 'T' }, 619987da915Sopenharmony_ci { NULL, 0, NULL, 0 } 620987da915Sopenharmony_ci }; 621987da915Sopenharmony_ci 622987da915Sopenharmony_ci int c = -1; 623987da915Sopenharmony_ci int lic = 0; 624987da915Sopenharmony_ci int help = 0; 625987da915Sopenharmony_ci int err = 0; 626987da915Sopenharmony_ci int ver = 0; 627987da915Sopenharmony_ci 628987da915Sopenharmony_ci if (!argv || !opts2) { 629987da915Sopenharmony_ci ntfs_log_error("Internal error: invalid parameters to " 630987da915Sopenharmony_ci "mkntfs_options.\n"); 631987da915Sopenharmony_ci return FALSE; 632987da915Sopenharmony_ci } 633987da915Sopenharmony_ci 634987da915Sopenharmony_ci opterr = 0; /* We'll handle the errors, thank you. */ 635987da915Sopenharmony_ci 636987da915Sopenharmony_ci while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { 637987da915Sopenharmony_ci switch (c) { 638987da915Sopenharmony_ci case 1: /* A device, or a number of sectors */ 639987da915Sopenharmony_ci if (!opts2->dev_name) 640987da915Sopenharmony_ci opts2->dev_name = argv[optind - 1]; 641987da915Sopenharmony_ci else if (!mkntfs_parse_llong(optarg, 642987da915Sopenharmony_ci "number of sectors", 643987da915Sopenharmony_ci &opts2->num_sectors)) 644987da915Sopenharmony_ci err++; 645987da915Sopenharmony_ci break; 646987da915Sopenharmony_ci case 'C': 647987da915Sopenharmony_ci opts2->enable_compression = TRUE; 648987da915Sopenharmony_ci break; 649987da915Sopenharmony_ci case 'c': 650987da915Sopenharmony_ci if (!mkntfs_parse_long(optarg, "cluster size", 651987da915Sopenharmony_ci &opts2->cluster_size)) 652987da915Sopenharmony_ci err++; 653987da915Sopenharmony_ci break; 654987da915Sopenharmony_ci case 'F': 655987da915Sopenharmony_ci opts2->force = TRUE; 656987da915Sopenharmony_ci break; 657987da915Sopenharmony_ci case 'f': /* fast */ 658987da915Sopenharmony_ci case 'Q': /* quick */ 659987da915Sopenharmony_ci opts2->quick_format = TRUE; 660987da915Sopenharmony_ci break; 661987da915Sopenharmony_ci case 'H': 662987da915Sopenharmony_ci if (!mkntfs_parse_long(optarg, "heads", &opts2->heads)) 663987da915Sopenharmony_ci err++; 664987da915Sopenharmony_ci break; 665987da915Sopenharmony_ci case 'h': 666987da915Sopenharmony_ci help++; /* display help */ 667987da915Sopenharmony_ci break; 668987da915Sopenharmony_ci case 'I': 669987da915Sopenharmony_ci opts2->disable_indexing = TRUE; 670987da915Sopenharmony_ci break; 671987da915Sopenharmony_ci case 'L': 672987da915Sopenharmony_ci if (!opts2->label) { 673987da915Sopenharmony_ci opts2->label = optarg; 674987da915Sopenharmony_ci } else { 675987da915Sopenharmony_ci ntfs_log_error("You may only specify the label " 676987da915Sopenharmony_ci "once.\n"); 677987da915Sopenharmony_ci err++; 678987da915Sopenharmony_ci } 679987da915Sopenharmony_ci break; 680987da915Sopenharmony_ci case 'l': 681987da915Sopenharmony_ci lic++; /* display the license */ 682987da915Sopenharmony_ci break; 683987da915Sopenharmony_ci case 'n': 684987da915Sopenharmony_ci opts2->no_action = TRUE; 685987da915Sopenharmony_ci break; 686987da915Sopenharmony_ci case 'p': 687987da915Sopenharmony_ci if (!mkntfs_parse_llong(optarg, "partition start", 688987da915Sopenharmony_ci &opts2->part_start_sect)) 689987da915Sopenharmony_ci err++; 690987da915Sopenharmony_ci break; 691987da915Sopenharmony_ci case 'q': 692987da915Sopenharmony_ci ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET | 693987da915Sopenharmony_ci NTFS_LOG_LEVEL_VERBOSE | 694987da915Sopenharmony_ci NTFS_LOG_LEVEL_PROGRESS); 695987da915Sopenharmony_ci break; 696987da915Sopenharmony_ci case 's': 697987da915Sopenharmony_ci if (!mkntfs_parse_long(optarg, "sector size", 698987da915Sopenharmony_ci &opts2->sector_size)) 699987da915Sopenharmony_ci err++; 700987da915Sopenharmony_ci break; 701987da915Sopenharmony_ci case 'S': 702987da915Sopenharmony_ci if (!mkntfs_parse_long(optarg, "sectors per track", 703987da915Sopenharmony_ci &opts2->sectors_per_track)) 704987da915Sopenharmony_ci err++; 705987da915Sopenharmony_ci break; 706987da915Sopenharmony_ci case 'T': 707987da915Sopenharmony_ci opts2->use_epoch_time = TRUE; 708987da915Sopenharmony_ci break; 709987da915Sopenharmony_ci case 'U': 710987da915Sopenharmony_ci opts2->with_uuid = TRUE; 711987da915Sopenharmony_ci break; 712987da915Sopenharmony_ci case 'v': 713987da915Sopenharmony_ci ntfs_log_set_levels(NTFS_LOG_LEVEL_QUIET | 714987da915Sopenharmony_ci NTFS_LOG_LEVEL_VERBOSE | 715987da915Sopenharmony_ci NTFS_LOG_LEVEL_PROGRESS); 716987da915Sopenharmony_ci break; 717987da915Sopenharmony_ci case 'V': 718987da915Sopenharmony_ci ver++; /* display version info */ 719987da915Sopenharmony_ci break; 720987da915Sopenharmony_ci case 'Z': /* debug - turn on everything */ 721987da915Sopenharmony_ci ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | 722987da915Sopenharmony_ci NTFS_LOG_LEVEL_TRACE | 723987da915Sopenharmony_ci NTFS_LOG_LEVEL_VERBOSE | 724987da915Sopenharmony_ci NTFS_LOG_LEVEL_QUIET); 725987da915Sopenharmony_ci break; 726987da915Sopenharmony_ci case 'z': 727987da915Sopenharmony_ci if (!mkntfs_parse_long(optarg, "mft zone multiplier", 728987da915Sopenharmony_ci &opts2->mft_zone_multiplier)) 729987da915Sopenharmony_ci err++; 730987da915Sopenharmony_ci break; 731987da915Sopenharmony_ci default: 732987da915Sopenharmony_ci if (ntfs_log_parse_option (argv[optind-1])) 733987da915Sopenharmony_ci break; 734987da915Sopenharmony_ci if (((optopt == 'c') || (optopt == 'H') || 735987da915Sopenharmony_ci (optopt == 'L') || (optopt == 'p') || 736987da915Sopenharmony_ci (optopt == 's') || (optopt == 'S') || 737987da915Sopenharmony_ci (optopt == 'N') || (optopt == 'z')) && 738987da915Sopenharmony_ci (!optarg)) { 739987da915Sopenharmony_ci ntfs_log_error("Option '%s' requires an " 740987da915Sopenharmony_ci "argument.\n", argv[optind-1]); 741987da915Sopenharmony_ci } else if (optopt != '?') { 742987da915Sopenharmony_ci ntfs_log_error("Unknown option '%s'.\n", 743987da915Sopenharmony_ci argv[optind - 1]); 744987da915Sopenharmony_ci } 745987da915Sopenharmony_ci err++; 746987da915Sopenharmony_ci break; 747987da915Sopenharmony_ci } 748987da915Sopenharmony_ci } 749987da915Sopenharmony_ci 750987da915Sopenharmony_ci if (!err && !help && !ver && !lic) { 751987da915Sopenharmony_ci if (opts2->dev_name == NULL) { 752987da915Sopenharmony_ci if (argc > 1) 753987da915Sopenharmony_ci ntfs_log_error("You must specify a device.\n"); 754987da915Sopenharmony_ci err++; 755987da915Sopenharmony_ci } 756987da915Sopenharmony_ci } 757987da915Sopenharmony_ci 758987da915Sopenharmony_ci if (ver) 759987da915Sopenharmony_ci mkntfs_version(); 760987da915Sopenharmony_ci if (lic) 761987da915Sopenharmony_ci mkntfs_license(); 762987da915Sopenharmony_ci if (err || help) 763987da915Sopenharmony_ci mkntfs_usage(); 764987da915Sopenharmony_ci 765987da915Sopenharmony_ci /* tri-state 0 : done, 1 : error, -1 : proceed */ 766987da915Sopenharmony_ci return (err ? 1 : (help || ver || lic ? 0 : -1)); 767987da915Sopenharmony_ci} 768987da915Sopenharmony_ci 769987da915Sopenharmony_ci 770987da915Sopenharmony_ci/** 771987da915Sopenharmony_ci * mkntfs_time 772987da915Sopenharmony_ci */ 773987da915Sopenharmony_cistatic ntfs_time mkntfs_time(void) 774987da915Sopenharmony_ci{ 775987da915Sopenharmony_ci struct timespec ts; 776987da915Sopenharmony_ci 777987da915Sopenharmony_ci ts.tv_sec = 0; 778987da915Sopenharmony_ci ts.tv_nsec = 0; 779987da915Sopenharmony_ci if (!opts.use_epoch_time) 780987da915Sopenharmony_ci ts.tv_sec = time(NULL); 781987da915Sopenharmony_ci return timespec2ntfs(ts); 782987da915Sopenharmony_ci} 783987da915Sopenharmony_ci 784987da915Sopenharmony_ci/** 785987da915Sopenharmony_ci * append_to_bad_blocks 786987da915Sopenharmony_ci */ 787987da915Sopenharmony_cistatic BOOL append_to_bad_blocks(unsigned long long block) 788987da915Sopenharmony_ci{ 789987da915Sopenharmony_ci long long *new_buf; 790987da915Sopenharmony_ci 791987da915Sopenharmony_ci if (!(g_num_bad_blocks & 15)) { 792987da915Sopenharmony_ci new_buf = realloc(g_bad_blocks, (g_num_bad_blocks + 16) * 793987da915Sopenharmony_ci sizeof(long long)); 794987da915Sopenharmony_ci if (!new_buf) { 795987da915Sopenharmony_ci ntfs_log_perror("Reallocating memory for bad blocks " 796987da915Sopenharmony_ci "list failed"); 797987da915Sopenharmony_ci return FALSE; 798987da915Sopenharmony_ci } 799987da915Sopenharmony_ci g_bad_blocks = new_buf; 800987da915Sopenharmony_ci } 801987da915Sopenharmony_ci g_bad_blocks[g_num_bad_blocks++] = block; 802987da915Sopenharmony_ci return TRUE; 803987da915Sopenharmony_ci} 804987da915Sopenharmony_ci 805987da915Sopenharmony_ci/** 806987da915Sopenharmony_ci * mkntfs_write 807987da915Sopenharmony_ci */ 808987da915Sopenharmony_cistatic long long mkntfs_write(struct ntfs_device *dev, 809987da915Sopenharmony_ci const void *b, long long count) 810987da915Sopenharmony_ci{ 811987da915Sopenharmony_ci long long bytes_written, total; 812987da915Sopenharmony_ci int retry; 813987da915Sopenharmony_ci 814987da915Sopenharmony_ci if (opts.no_action) 815987da915Sopenharmony_ci return count; 816987da915Sopenharmony_ci total = 0LL; 817987da915Sopenharmony_ci retry = 0; 818987da915Sopenharmony_ci do { 819987da915Sopenharmony_ci bytes_written = dev->d_ops->write(dev, b, count); 820987da915Sopenharmony_ci if (bytes_written == -1LL) { 821987da915Sopenharmony_ci retry = errno; 822987da915Sopenharmony_ci ntfs_log_perror("Error writing to %s", dev->d_name); 823987da915Sopenharmony_ci errno = retry; 824987da915Sopenharmony_ci return bytes_written; 825987da915Sopenharmony_ci } else if (!bytes_written) { 826987da915Sopenharmony_ci retry++; 827987da915Sopenharmony_ci } else { 828987da915Sopenharmony_ci count -= bytes_written; 829987da915Sopenharmony_ci total += bytes_written; 830987da915Sopenharmony_ci } 831987da915Sopenharmony_ci } while (count && retry < 3); 832987da915Sopenharmony_ci if (count) 833987da915Sopenharmony_ci ntfs_log_error("Failed to complete writing to %s after three retries." 834987da915Sopenharmony_ci "\n", dev->d_name); 835987da915Sopenharmony_ci return total; 836987da915Sopenharmony_ci} 837987da915Sopenharmony_ci 838987da915Sopenharmony_ci/** 839987da915Sopenharmony_ci * Build and write a part of the global bitmap 840987da915Sopenharmony_ci * without overflowing from the allocated buffer 841987da915Sopenharmony_ci * 842987da915Sopenharmony_ci * mkntfs_bitmap_write 843987da915Sopenharmony_ci */ 844987da915Sopenharmony_cistatic s64 mkntfs_bitmap_write(struct ntfs_device *dev, 845987da915Sopenharmony_ci s64 offset, s64 length) 846987da915Sopenharmony_ci{ 847987da915Sopenharmony_ci s64 partial_length; 848987da915Sopenharmony_ci s64 written; 849987da915Sopenharmony_ci 850987da915Sopenharmony_ci partial_length = length; 851987da915Sopenharmony_ci if (partial_length > g_dynamic_buf_size) 852987da915Sopenharmony_ci partial_length = g_dynamic_buf_size; 853987da915Sopenharmony_ci /* create a partial bitmap section, and write it */ 854987da915Sopenharmony_ci bitmap_build(g_dynamic_buf,offset << 3,partial_length << 3); 855987da915Sopenharmony_ci written = dev->d_ops->write(dev, g_dynamic_buf, partial_length); 856987da915Sopenharmony_ci return (written); 857987da915Sopenharmony_ci} 858987da915Sopenharmony_ci 859987da915Sopenharmony_ci/** 860987da915Sopenharmony_ci * Build and write a part of the log file 861987da915Sopenharmony_ci * without overflowing from the allocated buffer 862987da915Sopenharmony_ci * 863987da915Sopenharmony_ci * mkntfs_logfile_write 864987da915Sopenharmony_ci */ 865987da915Sopenharmony_cistatic s64 mkntfs_logfile_write(struct ntfs_device *dev, 866987da915Sopenharmony_ci s64 offset __attribute__((unused)), s64 length) 867987da915Sopenharmony_ci{ 868987da915Sopenharmony_ci s64 partial_length; 869987da915Sopenharmony_ci s64 written; 870987da915Sopenharmony_ci 871987da915Sopenharmony_ci partial_length = length; 872987da915Sopenharmony_ci if (partial_length > g_dynamic_buf_size) 873987da915Sopenharmony_ci partial_length = g_dynamic_buf_size; 874987da915Sopenharmony_ci /* create a partial bad cluster section, and write it */ 875987da915Sopenharmony_ci memset(g_dynamic_buf, -1, partial_length); 876987da915Sopenharmony_ci written = dev->d_ops->write(dev, g_dynamic_buf, partial_length); 877987da915Sopenharmony_ci return (written); 878987da915Sopenharmony_ci} 879987da915Sopenharmony_ci 880987da915Sopenharmony_ci/** 881987da915Sopenharmony_ci * ntfs_rlwrite - Write to disk the clusters contained in the runlist @rl 882987da915Sopenharmony_ci * taking the data from @val. Take @val_len bytes from @val and pad the 883987da915Sopenharmony_ci * rest with zeroes. 884987da915Sopenharmony_ci * 885987da915Sopenharmony_ci * If the @rl specifies a completely sparse file, @val is allowed to be NULL. 886987da915Sopenharmony_ci * 887987da915Sopenharmony_ci * @inited_size if not NULL points to an output variable which will contain 888987da915Sopenharmony_ci * the actual number of bytes written to disk. I.e. this will not include 889987da915Sopenharmony_ci * sparse bytes for example. 890987da915Sopenharmony_ci * 891987da915Sopenharmony_ci * Return the number of bytes written (minus padding) or -1 on error. Errno 892987da915Sopenharmony_ci * will be set to the error code. 893987da915Sopenharmony_ci */ 894987da915Sopenharmony_cistatic s64 ntfs_rlwrite(struct ntfs_device *dev, const runlist *rl, 895987da915Sopenharmony_ci const u8 *val, const s64 val_len, s64 *inited_size, 896987da915Sopenharmony_ci WRITE_TYPE write_type) 897987da915Sopenharmony_ci{ 898987da915Sopenharmony_ci s64 bytes_written, total, length, delta; 899987da915Sopenharmony_ci int retry, i; 900987da915Sopenharmony_ci 901987da915Sopenharmony_ci if (inited_size) 902987da915Sopenharmony_ci *inited_size = 0LL; 903987da915Sopenharmony_ci if (opts.no_action) 904987da915Sopenharmony_ci return val_len; 905987da915Sopenharmony_ci total = 0LL; 906987da915Sopenharmony_ci delta = 0LL; 907987da915Sopenharmony_ci for (i = 0; rl[i].length; i++) { 908987da915Sopenharmony_ci length = rl[i].length * g_vol->cluster_size; 909987da915Sopenharmony_ci /* Don't write sparse runs. */ 910987da915Sopenharmony_ci if (rl[i].lcn == -1) { 911987da915Sopenharmony_ci total += length; 912987da915Sopenharmony_ci if (!val) 913987da915Sopenharmony_ci continue; 914987da915Sopenharmony_ci /* TODO: Check that *val is really zero at pos and len. */ 915987da915Sopenharmony_ci continue; 916987da915Sopenharmony_ci } 917987da915Sopenharmony_ci /* 918987da915Sopenharmony_ci * Break up the write into the real data write and then a write 919987da915Sopenharmony_ci * of zeroes between the end of the real data and the end of 920987da915Sopenharmony_ci * the (last) run. 921987da915Sopenharmony_ci */ 922987da915Sopenharmony_ci if (total + length > val_len) { 923987da915Sopenharmony_ci delta = length; 924987da915Sopenharmony_ci length = val_len - total; 925987da915Sopenharmony_ci delta -= length; 926987da915Sopenharmony_ci } 927987da915Sopenharmony_ci if (dev->d_ops->seek(dev, rl[i].lcn * g_vol->cluster_size, 928987da915Sopenharmony_ci SEEK_SET) == (off_t)-1) 929987da915Sopenharmony_ci return -1LL; 930987da915Sopenharmony_ci retry = 0; 931987da915Sopenharmony_ci do { 932987da915Sopenharmony_ci /* use specific functions if buffer is not prefilled */ 933987da915Sopenharmony_ci switch (write_type) { 934987da915Sopenharmony_ci case WRITE_BITMAP : 935987da915Sopenharmony_ci bytes_written = mkntfs_bitmap_write(dev, 936987da915Sopenharmony_ci total, length); 937987da915Sopenharmony_ci break; 938987da915Sopenharmony_ci case WRITE_LOGFILE : 939987da915Sopenharmony_ci bytes_written = mkntfs_logfile_write(dev, 940987da915Sopenharmony_ci total, length); 941987da915Sopenharmony_ci break; 942987da915Sopenharmony_ci default : 943987da915Sopenharmony_ci bytes_written = dev->d_ops->write(dev, 944987da915Sopenharmony_ci val + total, length); 945987da915Sopenharmony_ci break; 946987da915Sopenharmony_ci } 947987da915Sopenharmony_ci if (bytes_written == -1LL) { 948987da915Sopenharmony_ci retry = errno; 949987da915Sopenharmony_ci ntfs_log_perror("Error writing to %s", 950987da915Sopenharmony_ci dev->d_name); 951987da915Sopenharmony_ci errno = retry; 952987da915Sopenharmony_ci return bytes_written; 953987da915Sopenharmony_ci } 954987da915Sopenharmony_ci if (bytes_written) { 955987da915Sopenharmony_ci length -= bytes_written; 956987da915Sopenharmony_ci total += bytes_written; 957987da915Sopenharmony_ci if (inited_size) 958987da915Sopenharmony_ci *inited_size += bytes_written; 959987da915Sopenharmony_ci } else { 960987da915Sopenharmony_ci retry++; 961987da915Sopenharmony_ci } 962987da915Sopenharmony_ci } while (length && retry < 3); 963987da915Sopenharmony_ci if (length) { 964987da915Sopenharmony_ci ntfs_log_error("Failed to complete writing to %s after three " 965987da915Sopenharmony_ci "retries.\n", dev->d_name); 966987da915Sopenharmony_ci return total; 967987da915Sopenharmony_ci } 968987da915Sopenharmony_ci } 969987da915Sopenharmony_ci if (delta) { 970987da915Sopenharmony_ci int eo; 971987da915Sopenharmony_ci char *b = ntfs_calloc(delta); 972987da915Sopenharmony_ci if (!b) 973987da915Sopenharmony_ci return -1; 974987da915Sopenharmony_ci bytes_written = mkntfs_write(dev, b, delta); 975987da915Sopenharmony_ci eo = errno; 976987da915Sopenharmony_ci free(b); 977987da915Sopenharmony_ci errno = eo; 978987da915Sopenharmony_ci if (bytes_written == -1LL) 979987da915Sopenharmony_ci return bytes_written; 980987da915Sopenharmony_ci } 981987da915Sopenharmony_ci return total; 982987da915Sopenharmony_ci} 983987da915Sopenharmony_ci 984987da915Sopenharmony_ci/** 985987da915Sopenharmony_ci * make_room_for_attribute - make room for an attribute inside an mft record 986987da915Sopenharmony_ci * @m: mft record 987987da915Sopenharmony_ci * @pos: position at which to make space 988987da915Sopenharmony_ci * @size: byte size to make available at this position 989987da915Sopenharmony_ci * 990987da915Sopenharmony_ci * @pos points to the attribute in front of which we want to make space. 991987da915Sopenharmony_ci * 992987da915Sopenharmony_ci * Return 0 on success or -errno on error. Possible error codes are: 993987da915Sopenharmony_ci * 994987da915Sopenharmony_ci * -ENOSPC There is not enough space available to complete 995987da915Sopenharmony_ci * operation. The caller has to make space before calling 996987da915Sopenharmony_ci * this. 997987da915Sopenharmony_ci * -EINVAL Can only occur if mkntfs was compiled with -DDEBUG. Means 998987da915Sopenharmony_ci * the input parameters were faulty. 999987da915Sopenharmony_ci */ 1000987da915Sopenharmony_cistatic int make_room_for_attribute(MFT_RECORD *m, char *pos, const u32 size) 1001987da915Sopenharmony_ci{ 1002987da915Sopenharmony_ci u32 biu; 1003987da915Sopenharmony_ci 1004987da915Sopenharmony_ci if (!size) 1005987da915Sopenharmony_ci return 0; 1006987da915Sopenharmony_ci#ifdef DEBUG 1007987da915Sopenharmony_ci /* 1008987da915Sopenharmony_ci * Rigorous consistency checks. Always return -EINVAL even if more 1009987da915Sopenharmony_ci * appropriate codes exist for simplicity of parsing the return value. 1010987da915Sopenharmony_ci */ 1011987da915Sopenharmony_ci if (size != ((size + 7) & ~7)) { 1012987da915Sopenharmony_ci ntfs_log_error("make_room_for_attribute() received non 8-byte aligned " 1013987da915Sopenharmony_ci "size.\n"); 1014987da915Sopenharmony_ci return -EINVAL; 1015987da915Sopenharmony_ci } 1016987da915Sopenharmony_ci if (!m || !pos) 1017987da915Sopenharmony_ci return -EINVAL; 1018987da915Sopenharmony_ci if (pos < (char*)m || pos + size < (char*)m || 1019987da915Sopenharmony_ci pos > (char*)m + le32_to_cpu(m->bytes_allocated) || 1020987da915Sopenharmony_ci pos + size > (char*)m + le32_to_cpu(m->bytes_allocated)) 1021987da915Sopenharmony_ci return -EINVAL; 1022987da915Sopenharmony_ci /* The -8 is for the attribute terminator. */ 1023987da915Sopenharmony_ci if (pos - (char*)m > (int)le32_to_cpu(m->bytes_in_use) - 8) 1024987da915Sopenharmony_ci return -EINVAL; 1025987da915Sopenharmony_ci#endif 1026987da915Sopenharmony_ci biu = le32_to_cpu(m->bytes_in_use); 1027987da915Sopenharmony_ci /* Do we have enough space? */ 1028987da915Sopenharmony_ci if (biu + size > le32_to_cpu(m->bytes_allocated)) 1029987da915Sopenharmony_ci return -ENOSPC; 1030987da915Sopenharmony_ci /* Move everything after pos to pos + size. */ 1031987da915Sopenharmony_ci memmove(pos + size, pos, biu - (pos - (char*)m)); 1032987da915Sopenharmony_ci /* Update mft record. */ 1033987da915Sopenharmony_ci m->bytes_in_use = cpu_to_le32(biu + size); 1034987da915Sopenharmony_ci return 0; 1035987da915Sopenharmony_ci} 1036987da915Sopenharmony_ci 1037987da915Sopenharmony_ci/** 1038987da915Sopenharmony_ci * deallocate_scattered_clusters 1039987da915Sopenharmony_ci */ 1040987da915Sopenharmony_cistatic void deallocate_scattered_clusters(const runlist *rl) 1041987da915Sopenharmony_ci{ 1042987da915Sopenharmony_ci int i; 1043987da915Sopenharmony_ci 1044987da915Sopenharmony_ci if (!rl) 1045987da915Sopenharmony_ci return; 1046987da915Sopenharmony_ci /* Iterate over all runs in the runlist @rl. */ 1047987da915Sopenharmony_ci for (i = 0; rl[i].length; i++) { 1048987da915Sopenharmony_ci /* Skip sparse runs. */ 1049987da915Sopenharmony_ci if (rl[i].lcn == -1LL) 1050987da915Sopenharmony_ci continue; 1051987da915Sopenharmony_ci /* Deallocate the current run. */ 1052987da915Sopenharmony_ci bitmap_deallocate(rl[i].lcn, rl[i].length); 1053987da915Sopenharmony_ci } 1054987da915Sopenharmony_ci} 1055987da915Sopenharmony_ci 1056987da915Sopenharmony_ci/** 1057987da915Sopenharmony_ci * allocate_scattered_clusters 1058987da915Sopenharmony_ci * @clusters: Amount of clusters to allocate. 1059987da915Sopenharmony_ci * 1060987da915Sopenharmony_ci * Allocate @clusters and create a runlist of the allocated clusters. 1061987da915Sopenharmony_ci * 1062987da915Sopenharmony_ci * Return the allocated runlist. Caller has to free the runlist when finished 1063987da915Sopenharmony_ci * with it. 1064987da915Sopenharmony_ci * 1065987da915Sopenharmony_ci * On error return NULL and errno is set to the error code. 1066987da915Sopenharmony_ci * 1067987da915Sopenharmony_ci * TODO: We should be returning the size as well, but for mkntfs this is not 1068987da915Sopenharmony_ci * necessary. 1069987da915Sopenharmony_ci */ 1070987da915Sopenharmony_cistatic runlist * allocate_scattered_clusters(s64 clusters) 1071987da915Sopenharmony_ci{ 1072987da915Sopenharmony_ci runlist *rl = NULL, *rlt; 1073987da915Sopenharmony_ci VCN vcn = 0LL; 1074987da915Sopenharmony_ci LCN lcn, end, prev_lcn = 0LL; 1075987da915Sopenharmony_ci int rlpos = 0; 1076987da915Sopenharmony_ci int rlsize = 0; 1077987da915Sopenharmony_ci s64 prev_run_len = 0LL; 1078987da915Sopenharmony_ci char bit; 1079987da915Sopenharmony_ci 1080987da915Sopenharmony_ci end = g_vol->nr_clusters; 1081987da915Sopenharmony_ci /* Loop until all clusters are allocated. */ 1082987da915Sopenharmony_ci while (clusters) { 1083987da915Sopenharmony_ci /* Loop in current zone until we run out of free clusters. */ 1084987da915Sopenharmony_ci for (lcn = g_mft_zone_end; lcn < end; lcn++) { 1085987da915Sopenharmony_ci bit = bitmap_get_and_set(lcn,1); 1086987da915Sopenharmony_ci if (bit) 1087987da915Sopenharmony_ci continue; 1088987da915Sopenharmony_ci /* 1089987da915Sopenharmony_ci * Reallocate memory if necessary. Make sure we have 1090987da915Sopenharmony_ci * enough for the terminator entry as well. 1091987da915Sopenharmony_ci */ 1092987da915Sopenharmony_ci if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) { 1093987da915Sopenharmony_ci rlsize += 4096; /* PAGE_SIZE */ 1094987da915Sopenharmony_ci rlt = realloc(rl, rlsize); 1095987da915Sopenharmony_ci if (!rlt) 1096987da915Sopenharmony_ci goto err_end; 1097987da915Sopenharmony_ci rl = rlt; 1098987da915Sopenharmony_ci } 1099987da915Sopenharmony_ci /* Coalesce with previous run if adjacent LCNs. */ 1100987da915Sopenharmony_ci if (prev_lcn == lcn - prev_run_len) { 1101987da915Sopenharmony_ci rl[rlpos - 1].length = ++prev_run_len; 1102987da915Sopenharmony_ci vcn++; 1103987da915Sopenharmony_ci } else { 1104987da915Sopenharmony_ci rl[rlpos].vcn = vcn++; 1105987da915Sopenharmony_ci rl[rlpos].lcn = lcn; 1106987da915Sopenharmony_ci prev_lcn = lcn; 1107987da915Sopenharmony_ci rl[rlpos].length = 1LL; 1108987da915Sopenharmony_ci prev_run_len = 1LL; 1109987da915Sopenharmony_ci rlpos++; 1110987da915Sopenharmony_ci } 1111987da915Sopenharmony_ci /* Done? */ 1112987da915Sopenharmony_ci if (!--clusters) { 1113987da915Sopenharmony_ci /* Add terminator element and return. */ 1114987da915Sopenharmony_ci rl[rlpos].vcn = vcn; 1115987da915Sopenharmony_ci rl[rlpos].lcn = 0LL; 1116987da915Sopenharmony_ci rl[rlpos].length = 0LL; 1117987da915Sopenharmony_ci return rl; 1118987da915Sopenharmony_ci } 1119987da915Sopenharmony_ci 1120987da915Sopenharmony_ci } 1121987da915Sopenharmony_ci /* Switch to next zone, decreasing mft zone by factor 2. */ 1122987da915Sopenharmony_ci end = g_mft_zone_end; 1123987da915Sopenharmony_ci g_mft_zone_end >>= 1; 1124987da915Sopenharmony_ci /* Have we run out of space on the volume? */ 1125987da915Sopenharmony_ci if (g_mft_zone_end <= 0) 1126987da915Sopenharmony_ci goto err_end; 1127987da915Sopenharmony_ci } 1128987da915Sopenharmony_ci return rl; 1129987da915Sopenharmony_cierr_end: 1130987da915Sopenharmony_ci if (rl) { 1131987da915Sopenharmony_ci /* Add terminator element. */ 1132987da915Sopenharmony_ci rl[rlpos].vcn = vcn; 1133987da915Sopenharmony_ci rl[rlpos].lcn = -1LL; 1134987da915Sopenharmony_ci rl[rlpos].length = 0LL; 1135987da915Sopenharmony_ci /* Deallocate all allocated clusters. */ 1136987da915Sopenharmony_ci deallocate_scattered_clusters(rl); 1137987da915Sopenharmony_ci /* Free the runlist. */ 1138987da915Sopenharmony_ci free(rl); 1139987da915Sopenharmony_ci } 1140987da915Sopenharmony_ci return NULL; 1141987da915Sopenharmony_ci} 1142987da915Sopenharmony_ci 1143987da915Sopenharmony_ci/** 1144987da915Sopenharmony_ci * ntfs_attr_find - find (next) attribute in mft record 1145987da915Sopenharmony_ci * @type: attribute type to find 1146987da915Sopenharmony_ci * @name: attribute name to find (optional, i.e. NULL means don't care) 1147987da915Sopenharmony_ci * @name_len: attribute name length (only needed if @name present) 1148987da915Sopenharmony_ci * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 1149987da915Sopenharmony_ci * @val: attribute value to find (optional, resident attributes only) 1150987da915Sopenharmony_ci * @val_len: attribute value length 1151987da915Sopenharmony_ci * @ctx: search context with mft record and attribute to search from 1152987da915Sopenharmony_ci * 1153987da915Sopenharmony_ci * You shouldn't need to call this function directly. Use lookup_attr() instead. 1154987da915Sopenharmony_ci * 1155987da915Sopenharmony_ci * ntfs_attr_find() takes a search context @ctx as parameter and searches the 1156987da915Sopenharmony_ci * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an 1157987da915Sopenharmony_ci * attribute of @type, optionally @name and @val. If found, ntfs_attr_find() 1158987da915Sopenharmony_ci * returns 0 and @ctx->attr will point to the found attribute. 1159987da915Sopenharmony_ci * 1160987da915Sopenharmony_ci * If not found, ntfs_attr_find() returns -1, with errno set to ENOENT and 1161987da915Sopenharmony_ci * @ctx->attr will point to the attribute before which the attribute being 1162987da915Sopenharmony_ci * searched for would need to be inserted if such an action were to be desired. 1163987da915Sopenharmony_ci * 1164987da915Sopenharmony_ci * On actual error, ntfs_attr_find() returns -1 with errno set to the error 1165987da915Sopenharmony_ci * code but not to ENOENT. In this case @ctx->attr is undefined and in 1166987da915Sopenharmony_ci * particular do not rely on it not changing. 1167987da915Sopenharmony_ci * 1168987da915Sopenharmony_ci * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it 1169987da915Sopenharmony_ci * is FALSE, the search begins after @ctx->attr. 1170987da915Sopenharmony_ci * 1171987da915Sopenharmony_ci * If @type is AT_UNUSED, return the first found attribute, i.e. one can 1172987da915Sopenharmony_ci * enumerate all attributes by setting @type to AT_UNUSED and then calling 1173987da915Sopenharmony_ci * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to 1174987da915Sopenharmony_ci * indicate that there are no more entries. During the enumeration, each 1175987da915Sopenharmony_ci * successful call of ntfs_attr_find() will return the next attribute in the 1176987da915Sopenharmony_ci * mft record @ctx->mrec. 1177987da915Sopenharmony_ci * 1178987da915Sopenharmony_ci * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT. 1179987da915Sopenharmony_ci * AT_END is not a valid attribute, its length is zero for example, thus it is 1180987da915Sopenharmony_ci * safer to return error instead of success in this case. This also allows us 1181987da915Sopenharmony_ci * to interoperate cleanly with ntfs_external_attr_find(). 1182987da915Sopenharmony_ci * 1183987da915Sopenharmony_ci * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present 1184987da915Sopenharmony_ci * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, 1185987da915Sopenharmony_ci * match both named and unnamed attributes. 1186987da915Sopenharmony_ci * 1187987da915Sopenharmony_ci * If @ic is IGNORE_CASE, the @name comparison is not case sensitive and 1188987da915Sopenharmony_ci * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record 1189987da915Sopenharmony_ci * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at 1190987da915Sopenharmony_ci * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case 1191987da915Sopenharmony_ci * sensitive. When @name is present, @name_len is the @name length in Unicode 1192987da915Sopenharmony_ci * characters. 1193987da915Sopenharmony_ci * 1194987da915Sopenharmony_ci * If @name is not present (NULL), we assume that the unnamed attribute is 1195987da915Sopenharmony_ci * being searched for. 1196987da915Sopenharmony_ci * 1197987da915Sopenharmony_ci * Finally, the resident attribute value @val is looked for, if present. 1198987da915Sopenharmony_ci * If @val is not present (NULL), @val_len is ignored. 1199987da915Sopenharmony_ci * 1200987da915Sopenharmony_ci * ntfs_attr_find() only searches the specified mft record and it ignores the 1201987da915Sopenharmony_ci * presence of an attribute list attribute (unless it is the one being searched 1202987da915Sopenharmony_ci * for, obviously). If you need to take attribute lists into consideration, use 1203987da915Sopenharmony_ci * ntfs_attr_lookup() instead (see below). This also means that you cannot use 1204987da915Sopenharmony_ci * ntfs_attr_find() to search for extent records of non-resident attributes, as 1205987da915Sopenharmony_ci * extents with lowest_vcn != 0 are usually described by the attribute list 1206987da915Sopenharmony_ci * attribute only. - Note that it is possible that the first extent is only in 1207987da915Sopenharmony_ci * the attribute list while the last extent is in the base mft record, so don't 1208987da915Sopenharmony_ci * rely on being able to find the first extent in the base mft record. 1209987da915Sopenharmony_ci * 1210987da915Sopenharmony_ci * Warning: Never use @val when looking for attribute types which can be 1211987da915Sopenharmony_ci * non-resident as this most likely will result in a crash! 1212987da915Sopenharmony_ci */ 1213987da915Sopenharmony_cistatic int mkntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, 1214987da915Sopenharmony_ci const u32 name_len, const IGNORE_CASE_BOOL ic, 1215987da915Sopenharmony_ci const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx) 1216987da915Sopenharmony_ci{ 1217987da915Sopenharmony_ci ATTR_RECORD *a; 1218987da915Sopenharmony_ci ntfschar *upcase = g_vol->upcase; 1219987da915Sopenharmony_ci u32 upcase_len = g_vol->upcase_len; 1220987da915Sopenharmony_ci 1221987da915Sopenharmony_ci /* 1222987da915Sopenharmony_ci * Iterate over attributes in mft record starting at @ctx->attr, or the 1223987da915Sopenharmony_ci * attribute following that, if @ctx->is_first is TRUE. 1224987da915Sopenharmony_ci */ 1225987da915Sopenharmony_ci if (ctx->is_first) { 1226987da915Sopenharmony_ci a = ctx->attr; 1227987da915Sopenharmony_ci ctx->is_first = FALSE; 1228987da915Sopenharmony_ci } else { 1229987da915Sopenharmony_ci a = (ATTR_RECORD*)((char*)ctx->attr + 1230987da915Sopenharmony_ci le32_to_cpu(ctx->attr->length)); 1231987da915Sopenharmony_ci } 1232987da915Sopenharmony_ci for (;; a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) { 1233987da915Sopenharmony_ci if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec + 1234987da915Sopenharmony_ci le32_to_cpu(ctx->mrec->bytes_allocated)) 1235987da915Sopenharmony_ci break; 1236987da915Sopenharmony_ci ctx->attr = a; 1237987da915Sopenharmony_ci if (((type != AT_UNUSED) && (le32_to_cpu(a->type) > 1238987da915Sopenharmony_ci le32_to_cpu(type))) || 1239987da915Sopenharmony_ci (a->type == AT_END)) { 1240987da915Sopenharmony_ci errno = ENOENT; 1241987da915Sopenharmony_ci return -1; 1242987da915Sopenharmony_ci } 1243987da915Sopenharmony_ci if (!a->length) 1244987da915Sopenharmony_ci break; 1245987da915Sopenharmony_ci /* If this is an enumeration return this attribute. */ 1246987da915Sopenharmony_ci if (type == AT_UNUSED) 1247987da915Sopenharmony_ci return 0; 1248987da915Sopenharmony_ci if (a->type != type) 1249987da915Sopenharmony_ci continue; 1250987da915Sopenharmony_ci /* 1251987da915Sopenharmony_ci * If @name is AT_UNNAMED we want an unnamed attribute. 1252987da915Sopenharmony_ci * If @name is present, compare the two names. 1253987da915Sopenharmony_ci * Otherwise, match any attribute. 1254987da915Sopenharmony_ci */ 1255987da915Sopenharmony_ci if (name == AT_UNNAMED) { 1256987da915Sopenharmony_ci /* The search failed if the found attribute is named. */ 1257987da915Sopenharmony_ci if (a->name_length) { 1258987da915Sopenharmony_ci errno = ENOENT; 1259987da915Sopenharmony_ci return -1; 1260987da915Sopenharmony_ci } 1261987da915Sopenharmony_ci } else if (name && !ntfs_names_are_equal(name, name_len, 1262987da915Sopenharmony_ci (ntfschar*)((char*)a + le16_to_cpu(a->name_offset)), 1263987da915Sopenharmony_ci a->name_length, ic, upcase, upcase_len)) { 1264987da915Sopenharmony_ci int rc; 1265987da915Sopenharmony_ci 1266987da915Sopenharmony_ci rc = ntfs_names_full_collate(name, name_len, 1267987da915Sopenharmony_ci (ntfschar*)((char*)a + 1268987da915Sopenharmony_ci le16_to_cpu(a->name_offset)), 1269987da915Sopenharmony_ci a->name_length, IGNORE_CASE, 1270987da915Sopenharmony_ci upcase, upcase_len); 1271987da915Sopenharmony_ci /* 1272987da915Sopenharmony_ci * If @name collates before a->name, there is no 1273987da915Sopenharmony_ci * matching attribute. 1274987da915Sopenharmony_ci */ 1275987da915Sopenharmony_ci if (rc == -1) { 1276987da915Sopenharmony_ci errno = ENOENT; 1277987da915Sopenharmony_ci return -1; 1278987da915Sopenharmony_ci } 1279987da915Sopenharmony_ci /* If the strings are not equal, continue search. */ 1280987da915Sopenharmony_ci if (rc) 1281987da915Sopenharmony_ci continue; 1282987da915Sopenharmony_ci rc = ntfs_names_full_collate(name, name_len, 1283987da915Sopenharmony_ci (ntfschar*)((char*)a + 1284987da915Sopenharmony_ci le16_to_cpu(a->name_offset)), 1285987da915Sopenharmony_ci a->name_length, CASE_SENSITIVE, 1286987da915Sopenharmony_ci upcase, upcase_len); 1287987da915Sopenharmony_ci if (rc == -1) { 1288987da915Sopenharmony_ci errno = ENOENT; 1289987da915Sopenharmony_ci return -1; 1290987da915Sopenharmony_ci } 1291987da915Sopenharmony_ci if (rc) 1292987da915Sopenharmony_ci continue; 1293987da915Sopenharmony_ci } 1294987da915Sopenharmony_ci /* 1295987da915Sopenharmony_ci * The names match or @name not present and attribute is 1296987da915Sopenharmony_ci * unnamed. If no @val specified, we have found the attribute 1297987da915Sopenharmony_ci * and are done. 1298987da915Sopenharmony_ci */ 1299987da915Sopenharmony_ci if (!val) { 1300987da915Sopenharmony_ci return 0; 1301987da915Sopenharmony_ci /* @val is present; compare values. */ 1302987da915Sopenharmony_ci } else { 1303987da915Sopenharmony_ci int rc; 1304987da915Sopenharmony_ci 1305987da915Sopenharmony_ci rc = memcmp(val, (char*)a +le16_to_cpu(a->value_offset), 1306987da915Sopenharmony_ci min(val_len, 1307987da915Sopenharmony_ci le32_to_cpu(a->value_length))); 1308987da915Sopenharmony_ci /* 1309987da915Sopenharmony_ci * If @val collates before the current attribute's 1310987da915Sopenharmony_ci * value, there is no matching attribute. 1311987da915Sopenharmony_ci */ 1312987da915Sopenharmony_ci if (!rc) { 1313987da915Sopenharmony_ci u32 avl; 1314987da915Sopenharmony_ci avl = le32_to_cpu(a->value_length); 1315987da915Sopenharmony_ci if (val_len == avl) 1316987da915Sopenharmony_ci return 0; 1317987da915Sopenharmony_ci if (val_len < avl) { 1318987da915Sopenharmony_ci errno = ENOENT; 1319987da915Sopenharmony_ci return -1; 1320987da915Sopenharmony_ci } 1321987da915Sopenharmony_ci } else if (rc < 0) { 1322987da915Sopenharmony_ci errno = ENOENT; 1323987da915Sopenharmony_ci return -1; 1324987da915Sopenharmony_ci } 1325987da915Sopenharmony_ci } 1326987da915Sopenharmony_ci } 1327987da915Sopenharmony_ci ntfs_log_trace("File is corrupt. Run chkdsk.\n"); 1328987da915Sopenharmony_ci errno = EIO; 1329987da915Sopenharmony_ci return -1; 1330987da915Sopenharmony_ci} 1331987da915Sopenharmony_ci 1332987da915Sopenharmony_ci/** 1333987da915Sopenharmony_ci * ntfs_attr_lookup - find an attribute in an ntfs inode 1334987da915Sopenharmony_ci * @type: attribute type to find 1335987da915Sopenharmony_ci * @name: attribute name to find (optional, i.e. NULL means don't care) 1336987da915Sopenharmony_ci * @name_len: attribute name length (only needed if @name present) 1337987da915Sopenharmony_ci * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 1338987da915Sopenharmony_ci * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) 1339987da915Sopenharmony_ci * @val: attribute value to find (optional, resident attributes only) 1340987da915Sopenharmony_ci * @val_len: attribute value length 1341987da915Sopenharmony_ci * @ctx: search context with mft record and attribute to search from 1342987da915Sopenharmony_ci * 1343987da915Sopenharmony_ci * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must 1344987da915Sopenharmony_ci * be the base mft record and @ctx must have been obtained from a call to 1345987da915Sopenharmony_ci * ntfs_attr_get_search_ctx(). 1346987da915Sopenharmony_ci * 1347987da915Sopenharmony_ci * This function transparently handles attribute lists and @ctx is used to 1348987da915Sopenharmony_ci * continue searches where they were left off at. 1349987da915Sopenharmony_ci * 1350987da915Sopenharmony_ci * If @type is AT_UNUSED, return the first found attribute, i.e. one can 1351987da915Sopenharmony_ci * enumerate all attributes by setting @type to AT_UNUSED and then calling 1352987da915Sopenharmony_ci * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT 1353987da915Sopenharmony_ci * to indicate that there are no more entries. During the enumeration, each 1354987da915Sopenharmony_ci * successful call of ntfs_attr_lookup() will return the next attribute, with 1355987da915Sopenharmony_ci * the current attribute being described by the search context @ctx. 1356987da915Sopenharmony_ci * 1357987da915Sopenharmony_ci * If @type is AT_END, seek to the end of the base mft record ignoring the 1358987da915Sopenharmony_ci * attribute list completely and return -1 with errno set to ENOENT. AT_END is 1359987da915Sopenharmony_ci * not a valid attribute, its length is zero for example, thus it is safer to 1360987da915Sopenharmony_ci * return error instead of success in this case. It should never be needed to 1361987da915Sopenharmony_ci * do this, but we implement the functionality because it allows for simpler 1362987da915Sopenharmony_ci * code inside ntfs_external_attr_find(). 1363987da915Sopenharmony_ci * 1364987da915Sopenharmony_ci * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present 1365987da915Sopenharmony_ci * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, 1366987da915Sopenharmony_ci * match both named and unnamed attributes. 1367987da915Sopenharmony_ci * 1368987da915Sopenharmony_ci * After finishing with the attribute/mft record you need to call 1369987da915Sopenharmony_ci * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any 1370987da915Sopenharmony_ci * mapped extent inodes, etc). 1371987da915Sopenharmony_ci * 1372987da915Sopenharmony_ci * Return 0 if the search was successful and -1 if not, with errno set to the 1373987da915Sopenharmony_ci * error code. 1374987da915Sopenharmony_ci * 1375987da915Sopenharmony_ci * On success, @ctx->attr is the found attribute, it is in mft record 1376987da915Sopenharmony_ci * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this 1377987da915Sopenharmony_ci * attribute with @ctx->base_* being the base mft record to which @ctx->attr 1378987da915Sopenharmony_ci * belongs. If no attribute list attribute is present @ctx->al_entry and 1379987da915Sopenharmony_ci * @ctx->base_* are NULL. 1380987da915Sopenharmony_ci * 1381987da915Sopenharmony_ci * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the 1382987da915Sopenharmony_ci * attribute which collates just after the attribute being searched for in the 1383987da915Sopenharmony_ci * base ntfs inode, i.e. if one wants to add the attribute to the mft record 1384987da915Sopenharmony_ci * this is the correct place to insert it into, and if there is not enough 1385987da915Sopenharmony_ci * space, the attribute should be placed in an extent mft record. 1386987da915Sopenharmony_ci * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list 1387987da915Sopenharmony_ci * at which the new attribute's attribute list entry should be inserted. The 1388987da915Sopenharmony_ci * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. 1389987da915Sopenharmony_ci * The only exception to this is when @type is AT_END, in which case 1390987da915Sopenharmony_ci * @ctx->al_entry is set to NULL also (see above). 1391987da915Sopenharmony_ci * 1392987da915Sopenharmony_ci * The following error codes are defined: 1393987da915Sopenharmony_ci * ENOENT Attribute not found, not an error as such. 1394987da915Sopenharmony_ci * EINVAL Invalid arguments. 1395987da915Sopenharmony_ci * EIO I/O error or corrupt data structures found. 1396987da915Sopenharmony_ci * ENOMEM Not enough memory to allocate necessary buffers. 1397987da915Sopenharmony_ci */ 1398987da915Sopenharmony_cistatic int mkntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, 1399987da915Sopenharmony_ci const u32 name_len, const IGNORE_CASE_BOOL ic, 1400987da915Sopenharmony_ci const VCN lowest_vcn __attribute__((unused)), const u8 *val, 1401987da915Sopenharmony_ci const u32 val_len, ntfs_attr_search_ctx *ctx) 1402987da915Sopenharmony_ci{ 1403987da915Sopenharmony_ci ntfs_inode *base_ni; 1404987da915Sopenharmony_ci 1405987da915Sopenharmony_ci if (!ctx || !ctx->mrec || !ctx->attr) { 1406987da915Sopenharmony_ci errno = EINVAL; 1407987da915Sopenharmony_ci return -1; 1408987da915Sopenharmony_ci } 1409987da915Sopenharmony_ci if (ctx->base_ntfs_ino) 1410987da915Sopenharmony_ci base_ni = ctx->base_ntfs_ino; 1411987da915Sopenharmony_ci else 1412987da915Sopenharmony_ci base_ni = ctx->ntfs_ino; 1413987da915Sopenharmony_ci if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST) 1414987da915Sopenharmony_ci return mkntfs_attr_find(type, name, name_len, ic, val, val_len, 1415987da915Sopenharmony_ci ctx); 1416987da915Sopenharmony_ci errno = EOPNOTSUPP; 1417987da915Sopenharmony_ci return -1; 1418987da915Sopenharmony_ci} 1419987da915Sopenharmony_ci 1420987da915Sopenharmony_ci/** 1421987da915Sopenharmony_ci * insert_positioned_attr_in_mft_record 1422987da915Sopenharmony_ci * 1423987da915Sopenharmony_ci * Create a non-resident attribute with a predefined on disk location 1424987da915Sopenharmony_ci * specified by the runlist @rl. The clusters specified by @rl are assumed to 1425987da915Sopenharmony_ci * be allocated already. 1426987da915Sopenharmony_ci * 1427987da915Sopenharmony_ci * Return 0 on success and -errno on error. 1428987da915Sopenharmony_ci */ 1429987da915Sopenharmony_cistatic int insert_positioned_attr_in_mft_record(MFT_RECORD *m, 1430987da915Sopenharmony_ci const ATTR_TYPES type, const char *name, u32 name_len, 1431987da915Sopenharmony_ci const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, 1432987da915Sopenharmony_ci const runlist *rl, const u8 *val, const s64 val_len) 1433987da915Sopenharmony_ci{ 1434987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 1435987da915Sopenharmony_ci ATTR_RECORD *a; 1436987da915Sopenharmony_ci u16 hdr_size; 1437987da915Sopenharmony_ci int asize, mpa_size, err, i; 1438987da915Sopenharmony_ci s64 bw = 0, inited_size; 1439987da915Sopenharmony_ci VCN highest_vcn; 1440987da915Sopenharmony_ci ntfschar *uname = NULL; 1441987da915Sopenharmony_ci int uname_len = 0; 1442987da915Sopenharmony_ci /* 1443987da915Sopenharmony_ci if (base record) 1444987da915Sopenharmony_ci attr_lookup(); 1445987da915Sopenharmony_ci else 1446987da915Sopenharmony_ci */ 1447987da915Sopenharmony_ci 1448987da915Sopenharmony_ci uname = ntfs_str2ucs(name, &uname_len); 1449987da915Sopenharmony_ci if (!uname) 1450987da915Sopenharmony_ci return -errno; 1451987da915Sopenharmony_ci 1452987da915Sopenharmony_ci /* Check if the attribute is already there. */ 1453987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(NULL, m); 1454987da915Sopenharmony_ci if (!ctx) { 1455987da915Sopenharmony_ci ntfs_log_error("Failed to allocate attribute search context.\n"); 1456987da915Sopenharmony_ci err = -ENOMEM; 1457987da915Sopenharmony_ci goto err_out; 1458987da915Sopenharmony_ci } 1459987da915Sopenharmony_ci if (ic == IGNORE_CASE) { 1460987da915Sopenharmony_ci ntfs_log_error("FIXME: Hit unimplemented code path #1.\n"); 1461987da915Sopenharmony_ci err = -EOPNOTSUPP; 1462987da915Sopenharmony_ci goto err_out; 1463987da915Sopenharmony_ci } 1464987da915Sopenharmony_ci if (!mkntfs_attr_lookup(type, uname, uname_len, ic, 0, NULL, 0, ctx)) { 1465987da915Sopenharmony_ci err = -EEXIST; 1466987da915Sopenharmony_ci goto err_out; 1467987da915Sopenharmony_ci } 1468987da915Sopenharmony_ci if (errno != ENOENT) { 1469987da915Sopenharmony_ci ntfs_log_error("Corrupt inode.\n"); 1470987da915Sopenharmony_ci err = -errno; 1471987da915Sopenharmony_ci goto err_out; 1472987da915Sopenharmony_ci } 1473987da915Sopenharmony_ci a = ctx->attr; 1474987da915Sopenharmony_ci if (flags & ATTR_COMPRESSION_MASK) { 1475987da915Sopenharmony_ci ntfs_log_error("Compressed attributes not supported yet.\n"); 1476987da915Sopenharmony_ci /* FIXME: Compress attribute into a temporary buffer, set */ 1477987da915Sopenharmony_ci /* val accordingly and save the compressed size. */ 1478987da915Sopenharmony_ci err = -EOPNOTSUPP; 1479987da915Sopenharmony_ci goto err_out; 1480987da915Sopenharmony_ci } 1481987da915Sopenharmony_ci if (flags & (ATTR_IS_ENCRYPTED | ATTR_IS_SPARSE)) { 1482987da915Sopenharmony_ci ntfs_log_error("Encrypted/sparse attributes not supported.\n"); 1483987da915Sopenharmony_ci err = -EOPNOTSUPP; 1484987da915Sopenharmony_ci goto err_out; 1485987da915Sopenharmony_ci } 1486987da915Sopenharmony_ci if (flags & ATTR_COMPRESSION_MASK) { 1487987da915Sopenharmony_ci hdr_size = 72; 1488987da915Sopenharmony_ci /* FIXME: This compression stuff is all wrong. Never mind for */ 1489987da915Sopenharmony_ci /* now. (AIA) */ 1490987da915Sopenharmony_ci if (val_len) 1491987da915Sopenharmony_ci mpa_size = 0; /* get_size_for_compressed_mapping_pairs(rl); */ 1492987da915Sopenharmony_ci else 1493987da915Sopenharmony_ci mpa_size = 0; 1494987da915Sopenharmony_ci } else { 1495987da915Sopenharmony_ci hdr_size = 64; 1496987da915Sopenharmony_ci if (val_len) { 1497987da915Sopenharmony_ci mpa_size = ntfs_get_size_for_mapping_pairs(g_vol, rl, 0, INT_MAX); 1498987da915Sopenharmony_ci if (mpa_size < 0) { 1499987da915Sopenharmony_ci err = -errno; 1500987da915Sopenharmony_ci ntfs_log_error("Failed to get size for mapping " 1501987da915Sopenharmony_ci "pairs.\n"); 1502987da915Sopenharmony_ci goto err_out; 1503987da915Sopenharmony_ci } 1504987da915Sopenharmony_ci } else { 1505987da915Sopenharmony_ci mpa_size = 0; 1506987da915Sopenharmony_ci } 1507987da915Sopenharmony_ci } 1508987da915Sopenharmony_ci /* Mapping pairs array and next attribute must be 8-byte aligned. */ 1509987da915Sopenharmony_ci asize = (((int)hdr_size + ((name_len + 7) & ~7) + mpa_size) + 7) & ~7; 1510987da915Sopenharmony_ci /* Get the highest vcn. */ 1511987da915Sopenharmony_ci for (i = 0, highest_vcn = 0LL; rl[i].length; i++) 1512987da915Sopenharmony_ci highest_vcn += rl[i].length; 1513987da915Sopenharmony_ci /* Does the value fit inside the allocated size? */ 1514987da915Sopenharmony_ci if (highest_vcn * g_vol->cluster_size < val_len) { 1515987da915Sopenharmony_ci ntfs_log_error("BUG: Allocated size is smaller than data size!\n"); 1516987da915Sopenharmony_ci err = -EINVAL; 1517987da915Sopenharmony_ci goto err_out; 1518987da915Sopenharmony_ci } 1519987da915Sopenharmony_ci err = make_room_for_attribute(m, (char*)a, asize); 1520987da915Sopenharmony_ci if (err == -ENOSPC) { 1521987da915Sopenharmony_ci /* 1522987da915Sopenharmony_ci * FIXME: Make space! (AIA) 1523987da915Sopenharmony_ci * can we make it non-resident? if yes, do that. 1524987da915Sopenharmony_ci * does it fit now? yes -> do it. 1525987da915Sopenharmony_ci * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? 1526987da915Sopenharmony_ci * yes -> make non-resident 1527987da915Sopenharmony_ci * does it fit now? yes -> do it. 1528987da915Sopenharmony_ci * make all attributes non-resident 1529987da915Sopenharmony_ci * does it fit now? yes -> do it. 1530987da915Sopenharmony_ci * m is a base record? yes -> allocate extension record 1531987da915Sopenharmony_ci * does the new attribute fit in there? yes -> do it. 1532987da915Sopenharmony_ci * split up runlist into extents and place each in an extension 1533987da915Sopenharmony_ci * record. 1534987da915Sopenharmony_ci * FIXME: the check for needing extension records should be 1535987da915Sopenharmony_ci * earlier on as it is very quick: asize > m->bytes_allocated? 1536987da915Sopenharmony_ci */ 1537987da915Sopenharmony_ci err = -EOPNOTSUPP; 1538987da915Sopenharmony_ci goto err_out; 1539987da915Sopenharmony_ci#ifdef DEBUG 1540987da915Sopenharmony_ci } else if (err == -EINVAL) { 1541987da915Sopenharmony_ci ntfs_log_error("BUG(): in insert_positioned_attribute_in_mft_" 1542987da915Sopenharmony_ci "record(): make_room_for_attribute() returned " 1543987da915Sopenharmony_ci "error: EINVAL!\n"); 1544987da915Sopenharmony_ci goto err_out; 1545987da915Sopenharmony_ci#endif 1546987da915Sopenharmony_ci } 1547987da915Sopenharmony_ci a->type = type; 1548987da915Sopenharmony_ci a->length = cpu_to_le32(asize); 1549987da915Sopenharmony_ci a->non_resident = 1; 1550987da915Sopenharmony_ci a->name_length = name_len; 1551987da915Sopenharmony_ci a->name_offset = cpu_to_le16(hdr_size); 1552987da915Sopenharmony_ci a->flags = flags; 1553987da915Sopenharmony_ci a->instance = m->next_attr_instance; 1554987da915Sopenharmony_ci m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) 1555987da915Sopenharmony_ci + 1) & 0xffff); 1556987da915Sopenharmony_ci a->lowest_vcn = const_cpu_to_sle64(0); 1557987da915Sopenharmony_ci a->highest_vcn = cpu_to_sle64(highest_vcn - 1LL); 1558987da915Sopenharmony_ci a->mapping_pairs_offset = cpu_to_le16(hdr_size + ((name_len + 7) & ~7)); 1559987da915Sopenharmony_ci memset(a->reserved1, 0, sizeof(a->reserved1)); 1560987da915Sopenharmony_ci /* FIXME: Allocated size depends on compression. */ 1561987da915Sopenharmony_ci a->allocated_size = cpu_to_sle64(highest_vcn * g_vol->cluster_size); 1562987da915Sopenharmony_ci a->data_size = cpu_to_sle64(val_len); 1563987da915Sopenharmony_ci if (name_len) 1564987da915Sopenharmony_ci memcpy((char*)a + hdr_size, uname, name_len << 1); 1565987da915Sopenharmony_ci if (flags & ATTR_COMPRESSION_MASK) { 1566987da915Sopenharmony_ci if (flags & ATTR_COMPRESSION_MASK & ~ATTR_IS_COMPRESSED) { 1567987da915Sopenharmony_ci ntfs_log_error("Unknown compression format. Reverting " 1568987da915Sopenharmony_ci "to standard compression.\n"); 1569987da915Sopenharmony_ci a->flags &= ~ATTR_COMPRESSION_MASK; 1570987da915Sopenharmony_ci a->flags |= ATTR_IS_COMPRESSED; 1571987da915Sopenharmony_ci } 1572987da915Sopenharmony_ci a->compression_unit = 4; 1573987da915Sopenharmony_ci inited_size = val_len; 1574987da915Sopenharmony_ci /* FIXME: Set the compressed size. */ 1575987da915Sopenharmony_ci a->compressed_size = const_cpu_to_sle64(0); 1576987da915Sopenharmony_ci /* FIXME: Write out the compressed data. */ 1577987da915Sopenharmony_ci /* FIXME: err = build_mapping_pairs_compressed(); */ 1578987da915Sopenharmony_ci err = -EOPNOTSUPP; 1579987da915Sopenharmony_ci } else { 1580987da915Sopenharmony_ci a->compression_unit = 0; 1581987da915Sopenharmony_ci if ((type == AT_DATA) 1582987da915Sopenharmony_ci && (m->mft_record_number 1583987da915Sopenharmony_ci == const_cpu_to_le32(FILE_LogFile))) 1584987da915Sopenharmony_ci bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len, 1585987da915Sopenharmony_ci &inited_size, WRITE_LOGFILE); 1586987da915Sopenharmony_ci else 1587987da915Sopenharmony_ci bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len, 1588987da915Sopenharmony_ci &inited_size, WRITE_STANDARD); 1589987da915Sopenharmony_ci if (bw != val_len) { 1590987da915Sopenharmony_ci ntfs_log_error("Error writing non-resident attribute " 1591987da915Sopenharmony_ci "value.\n"); 1592987da915Sopenharmony_ci return -errno; 1593987da915Sopenharmony_ci } 1594987da915Sopenharmony_ci err = ntfs_mapping_pairs_build(g_vol, (u8*)a + hdr_size + 1595987da915Sopenharmony_ci ((name_len + 7) & ~7), mpa_size, rl, 0, NULL); 1596987da915Sopenharmony_ci } 1597987da915Sopenharmony_ci a->initialized_size = cpu_to_sle64(inited_size); 1598987da915Sopenharmony_ci if (err < 0 || bw != val_len) { 1599987da915Sopenharmony_ci /* FIXME: Handle error. */ 1600987da915Sopenharmony_ci /* deallocate clusters */ 1601987da915Sopenharmony_ci /* remove attribute */ 1602987da915Sopenharmony_ci if (err >= 0) 1603987da915Sopenharmony_ci err = -EIO; 1604987da915Sopenharmony_ci ntfs_log_error("insert_positioned_attr_in_mft_record failed " 1605987da915Sopenharmony_ci "with error %i.\n", err < 0 ? err : (int)bw); 1606987da915Sopenharmony_ci } 1607987da915Sopenharmony_cierr_out: 1608987da915Sopenharmony_ci if (ctx) 1609987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1610987da915Sopenharmony_ci ntfs_ucsfree(uname); 1611987da915Sopenharmony_ci return err; 1612987da915Sopenharmony_ci} 1613987da915Sopenharmony_ci 1614987da915Sopenharmony_ci/** 1615987da915Sopenharmony_ci * insert_non_resident_attr_in_mft_record 1616987da915Sopenharmony_ci * 1617987da915Sopenharmony_ci * Return 0 on success and -errno on error. 1618987da915Sopenharmony_ci */ 1619987da915Sopenharmony_cistatic int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, 1620987da915Sopenharmony_ci const ATTR_TYPES type, const char *name, u32 name_len, 1621987da915Sopenharmony_ci const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, 1622987da915Sopenharmony_ci const u8 *val, const s64 val_len, 1623987da915Sopenharmony_ci WRITE_TYPE write_type) 1624987da915Sopenharmony_ci{ 1625987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 1626987da915Sopenharmony_ci ATTR_RECORD *a; 1627987da915Sopenharmony_ci u16 hdr_size; 1628987da915Sopenharmony_ci int asize, mpa_size, err, i; 1629987da915Sopenharmony_ci runlist *rl = NULL; 1630987da915Sopenharmony_ci s64 bw = 0; 1631987da915Sopenharmony_ci ntfschar *uname = NULL; 1632987da915Sopenharmony_ci int uname_len = 0; 1633987da915Sopenharmony_ci /* 1634987da915Sopenharmony_ci if (base record) 1635987da915Sopenharmony_ci attr_lookup(); 1636987da915Sopenharmony_ci else 1637987da915Sopenharmony_ci */ 1638987da915Sopenharmony_ci 1639987da915Sopenharmony_ci uname = ntfs_str2ucs(name, &uname_len); 1640987da915Sopenharmony_ci if (!uname) 1641987da915Sopenharmony_ci return -errno; 1642987da915Sopenharmony_ci 1643987da915Sopenharmony_ci /* Check if the attribute is already there. */ 1644987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(NULL, m); 1645987da915Sopenharmony_ci if (!ctx) { 1646987da915Sopenharmony_ci ntfs_log_error("Failed to allocate attribute search context.\n"); 1647987da915Sopenharmony_ci err = -ENOMEM; 1648987da915Sopenharmony_ci goto err_out; 1649987da915Sopenharmony_ci } 1650987da915Sopenharmony_ci if (ic == IGNORE_CASE) { 1651987da915Sopenharmony_ci ntfs_log_error("FIXME: Hit unimplemented code path #2.\n"); 1652987da915Sopenharmony_ci err = -EOPNOTSUPP; 1653987da915Sopenharmony_ci goto err_out; 1654987da915Sopenharmony_ci } 1655987da915Sopenharmony_ci if (!mkntfs_attr_lookup(type, uname, uname_len, ic, 0, NULL, 0, ctx)) { 1656987da915Sopenharmony_ci err = -EEXIST; 1657987da915Sopenharmony_ci goto err_out; 1658987da915Sopenharmony_ci } 1659987da915Sopenharmony_ci if (errno != ENOENT) { 1660987da915Sopenharmony_ci ntfs_log_error("Corrupt inode.\n"); 1661987da915Sopenharmony_ci err = -errno; 1662987da915Sopenharmony_ci goto err_out; 1663987da915Sopenharmony_ci } 1664987da915Sopenharmony_ci a = ctx->attr; 1665987da915Sopenharmony_ci if (flags & ATTR_COMPRESSION_MASK) { 1666987da915Sopenharmony_ci ntfs_log_error("Compressed attributes not supported yet.\n"); 1667987da915Sopenharmony_ci /* FIXME: Compress attribute into a temporary buffer, set */ 1668987da915Sopenharmony_ci /* val accordingly and save the compressed size. */ 1669987da915Sopenharmony_ci err = -EOPNOTSUPP; 1670987da915Sopenharmony_ci goto err_out; 1671987da915Sopenharmony_ci } 1672987da915Sopenharmony_ci if (flags & (ATTR_IS_ENCRYPTED | ATTR_IS_SPARSE)) { 1673987da915Sopenharmony_ci ntfs_log_error("Encrypted/sparse attributes not supported.\n"); 1674987da915Sopenharmony_ci err = -EOPNOTSUPP; 1675987da915Sopenharmony_ci goto err_out; 1676987da915Sopenharmony_ci } 1677987da915Sopenharmony_ci if (val_len) { 1678987da915Sopenharmony_ci rl = allocate_scattered_clusters((val_len + 1679987da915Sopenharmony_ci g_vol->cluster_size - 1) / g_vol->cluster_size); 1680987da915Sopenharmony_ci if (!rl) { 1681987da915Sopenharmony_ci err = -errno; 1682987da915Sopenharmony_ci ntfs_log_perror("Failed to allocate scattered clusters"); 1683987da915Sopenharmony_ci goto err_out; 1684987da915Sopenharmony_ci } 1685987da915Sopenharmony_ci } else { 1686987da915Sopenharmony_ci rl = NULL; 1687987da915Sopenharmony_ci } 1688987da915Sopenharmony_ci if (flags & ATTR_COMPRESSION_MASK) { 1689987da915Sopenharmony_ci hdr_size = 72; 1690987da915Sopenharmony_ci /* FIXME: This compression stuff is all wrong. Never mind for */ 1691987da915Sopenharmony_ci /* now. (AIA) */ 1692987da915Sopenharmony_ci if (val_len) 1693987da915Sopenharmony_ci mpa_size = 0; /* get_size_for_compressed_mapping_pairs(rl); */ 1694987da915Sopenharmony_ci else 1695987da915Sopenharmony_ci mpa_size = 0; 1696987da915Sopenharmony_ci } else { 1697987da915Sopenharmony_ci hdr_size = 64; 1698987da915Sopenharmony_ci if (val_len) { 1699987da915Sopenharmony_ci mpa_size = ntfs_get_size_for_mapping_pairs(g_vol, rl, 0, INT_MAX); 1700987da915Sopenharmony_ci if (mpa_size < 0) { 1701987da915Sopenharmony_ci err = -errno; 1702987da915Sopenharmony_ci ntfs_log_error("Failed to get size for mapping " 1703987da915Sopenharmony_ci "pairs.\n"); 1704987da915Sopenharmony_ci goto err_out; 1705987da915Sopenharmony_ci } 1706987da915Sopenharmony_ci } else { 1707987da915Sopenharmony_ci mpa_size = 0; 1708987da915Sopenharmony_ci } 1709987da915Sopenharmony_ci } 1710987da915Sopenharmony_ci /* Mapping pairs array and next attribute must be 8-byte aligned. */ 1711987da915Sopenharmony_ci asize = (((int)hdr_size + ((name_len + 7) & ~7) + mpa_size) + 7) & ~7; 1712987da915Sopenharmony_ci err = make_room_for_attribute(m, (char*)a, asize); 1713987da915Sopenharmony_ci if (err == -ENOSPC) { 1714987da915Sopenharmony_ci /* 1715987da915Sopenharmony_ci * FIXME: Make space! (AIA) 1716987da915Sopenharmony_ci * can we make it non-resident? if yes, do that. 1717987da915Sopenharmony_ci * does it fit now? yes -> do it. 1718987da915Sopenharmony_ci * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? 1719987da915Sopenharmony_ci * yes -> make non-resident 1720987da915Sopenharmony_ci * does it fit now? yes -> do it. 1721987da915Sopenharmony_ci * make all attributes non-resident 1722987da915Sopenharmony_ci * does it fit now? yes -> do it. 1723987da915Sopenharmony_ci * m is a base record? yes -> allocate extension record 1724987da915Sopenharmony_ci * does the new attribute fit in there? yes -> do it. 1725987da915Sopenharmony_ci * split up runlist into extents and place each in an extension 1726987da915Sopenharmony_ci * record. 1727987da915Sopenharmony_ci * FIXME: the check for needing extension records should be 1728987da915Sopenharmony_ci * earlier on as it is very quick: asize > m->bytes_allocated? 1729987da915Sopenharmony_ci */ 1730987da915Sopenharmony_ci err = -EOPNOTSUPP; 1731987da915Sopenharmony_ci goto err_out; 1732987da915Sopenharmony_ci#ifdef DEBUG 1733987da915Sopenharmony_ci } else if (err == -EINVAL) { 1734987da915Sopenharmony_ci ntfs_log_error("BUG(): in insert_non_resident_attribute_in_" 1735987da915Sopenharmony_ci "mft_record(): make_room_for_attribute() " 1736987da915Sopenharmony_ci "returned error: EINVAL!\n"); 1737987da915Sopenharmony_ci goto err_out; 1738987da915Sopenharmony_ci#endif 1739987da915Sopenharmony_ci } 1740987da915Sopenharmony_ci a->type = type; 1741987da915Sopenharmony_ci a->length = cpu_to_le32(asize); 1742987da915Sopenharmony_ci a->non_resident = 1; 1743987da915Sopenharmony_ci a->name_length = name_len; 1744987da915Sopenharmony_ci a->name_offset = cpu_to_le16(hdr_size); 1745987da915Sopenharmony_ci a->flags = flags; 1746987da915Sopenharmony_ci a->instance = m->next_attr_instance; 1747987da915Sopenharmony_ci m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) 1748987da915Sopenharmony_ci + 1) & 0xffff); 1749987da915Sopenharmony_ci a->lowest_vcn = const_cpu_to_sle64(0); 1750987da915Sopenharmony_ci for (i = 0; rl[i].length; i++) 1751987da915Sopenharmony_ci ; 1752987da915Sopenharmony_ci a->highest_vcn = cpu_to_sle64(rl[i].vcn - 1); 1753987da915Sopenharmony_ci a->mapping_pairs_offset = cpu_to_le16(hdr_size + ((name_len + 7) & ~7)); 1754987da915Sopenharmony_ci memset(a->reserved1, 0, sizeof(a->reserved1)); 1755987da915Sopenharmony_ci /* FIXME: Allocated size depends on compression. */ 1756987da915Sopenharmony_ci a->allocated_size = cpu_to_sle64((val_len + (g_vol->cluster_size - 1)) & 1757987da915Sopenharmony_ci ~(g_vol->cluster_size - 1)); 1758987da915Sopenharmony_ci a->data_size = cpu_to_sle64(val_len); 1759987da915Sopenharmony_ci a->initialized_size = cpu_to_sle64(val_len); 1760987da915Sopenharmony_ci if (name_len) 1761987da915Sopenharmony_ci memcpy((char*)a + hdr_size, uname, name_len << 1); 1762987da915Sopenharmony_ci if (flags & ATTR_COMPRESSION_MASK) { 1763987da915Sopenharmony_ci if (flags & ATTR_COMPRESSION_MASK & ~ATTR_IS_COMPRESSED) { 1764987da915Sopenharmony_ci ntfs_log_error("Unknown compression format. Reverting " 1765987da915Sopenharmony_ci "to standard compression.\n"); 1766987da915Sopenharmony_ci a->flags &= ~ATTR_COMPRESSION_MASK; 1767987da915Sopenharmony_ci a->flags |= ATTR_IS_COMPRESSED; 1768987da915Sopenharmony_ci } 1769987da915Sopenharmony_ci a->compression_unit = 4; 1770987da915Sopenharmony_ci /* FIXME: Set the compressed size. */ 1771987da915Sopenharmony_ci a->compressed_size = const_cpu_to_sle64(0); 1772987da915Sopenharmony_ci /* FIXME: Write out the compressed data. */ 1773987da915Sopenharmony_ci /* FIXME: err = build_mapping_pairs_compressed(); */ 1774987da915Sopenharmony_ci err = -EOPNOTSUPP; 1775987da915Sopenharmony_ci } else { 1776987da915Sopenharmony_ci a->compression_unit = 0; 1777987da915Sopenharmony_ci bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len, NULL, 1778987da915Sopenharmony_ci write_type); 1779987da915Sopenharmony_ci if (bw != val_len) { 1780987da915Sopenharmony_ci ntfs_log_error("Error writing non-resident attribute " 1781987da915Sopenharmony_ci "value.\n"); 1782987da915Sopenharmony_ci return -errno; 1783987da915Sopenharmony_ci } 1784987da915Sopenharmony_ci err = ntfs_mapping_pairs_build(g_vol, (u8*)a + hdr_size + 1785987da915Sopenharmony_ci ((name_len + 7) & ~7), mpa_size, rl, 0, NULL); 1786987da915Sopenharmony_ci } 1787987da915Sopenharmony_ci if (err < 0 || bw != val_len) { 1788987da915Sopenharmony_ci /* FIXME: Handle error. */ 1789987da915Sopenharmony_ci /* deallocate clusters */ 1790987da915Sopenharmony_ci /* remove attribute */ 1791987da915Sopenharmony_ci if (err >= 0) 1792987da915Sopenharmony_ci err = -EIO; 1793987da915Sopenharmony_ci ntfs_log_error("insert_non_resident_attr_in_mft_record failed with " 1794987da915Sopenharmony_ci "error %lld.\n", (long long) (err < 0 ? err : bw)); 1795987da915Sopenharmony_ci } 1796987da915Sopenharmony_cierr_out: 1797987da915Sopenharmony_ci if (ctx) 1798987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1799987da915Sopenharmony_ci ntfs_ucsfree(uname); 1800987da915Sopenharmony_ci free(rl); 1801987da915Sopenharmony_ci return err; 1802987da915Sopenharmony_ci} 1803987da915Sopenharmony_ci 1804987da915Sopenharmony_ci/** 1805987da915Sopenharmony_ci * insert_resident_attr_in_mft_record 1806987da915Sopenharmony_ci * 1807987da915Sopenharmony_ci * Return 0 on success and -errno on error. 1808987da915Sopenharmony_ci */ 1809987da915Sopenharmony_cistatic int insert_resident_attr_in_mft_record(MFT_RECORD *m, 1810987da915Sopenharmony_ci const ATTR_TYPES type, const char *name, u32 name_len, 1811987da915Sopenharmony_ci const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, 1812987da915Sopenharmony_ci const RESIDENT_ATTR_FLAGS res_flags, 1813987da915Sopenharmony_ci const u8 *val, const u32 val_len) 1814987da915Sopenharmony_ci{ 1815987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 1816987da915Sopenharmony_ci ATTR_RECORD *a; 1817987da915Sopenharmony_ci int asize, err; 1818987da915Sopenharmony_ci ntfschar *uname = NULL; 1819987da915Sopenharmony_ci int uname_len = 0; 1820987da915Sopenharmony_ci /* 1821987da915Sopenharmony_ci if (base record) 1822987da915Sopenharmony_ci mkntfs_attr_lookup(); 1823987da915Sopenharmony_ci else 1824987da915Sopenharmony_ci */ 1825987da915Sopenharmony_ci 1826987da915Sopenharmony_ci uname = ntfs_str2ucs(name, &uname_len); 1827987da915Sopenharmony_ci if (!uname) 1828987da915Sopenharmony_ci return -errno; 1829987da915Sopenharmony_ci 1830987da915Sopenharmony_ci /* Check if the attribute is already there. */ 1831987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(NULL, m); 1832987da915Sopenharmony_ci if (!ctx) { 1833987da915Sopenharmony_ci ntfs_log_error("Failed to allocate attribute search context.\n"); 1834987da915Sopenharmony_ci err = -ENOMEM; 1835987da915Sopenharmony_ci goto err_out; 1836987da915Sopenharmony_ci } 1837987da915Sopenharmony_ci if (ic == IGNORE_CASE) { 1838987da915Sopenharmony_ci ntfs_log_error("FIXME: Hit unimplemented code path #3.\n"); 1839987da915Sopenharmony_ci err = -EOPNOTSUPP; 1840987da915Sopenharmony_ci goto err_out; 1841987da915Sopenharmony_ci } 1842987da915Sopenharmony_ci if (!mkntfs_attr_lookup(type, uname, uname_len, ic, 0, val, val_len, 1843987da915Sopenharmony_ci ctx)) { 1844987da915Sopenharmony_ci err = -EEXIST; 1845987da915Sopenharmony_ci goto err_out; 1846987da915Sopenharmony_ci } 1847987da915Sopenharmony_ci if (errno != ENOENT) { 1848987da915Sopenharmony_ci ntfs_log_error("Corrupt inode.\n"); 1849987da915Sopenharmony_ci err = -errno; 1850987da915Sopenharmony_ci goto err_out; 1851987da915Sopenharmony_ci } 1852987da915Sopenharmony_ci a = ctx->attr; 1853987da915Sopenharmony_ci /* sizeof(resident attribute record header) == 24 */ 1854987da915Sopenharmony_ci asize = ((24 + ((name_len*2 + 7) & ~7) + val_len) + 7) & ~7; 1855987da915Sopenharmony_ci err = make_room_for_attribute(m, (char*)a, asize); 1856987da915Sopenharmony_ci if (err == -ENOSPC) { 1857987da915Sopenharmony_ci /* 1858987da915Sopenharmony_ci * FIXME: Make space! (AIA) 1859987da915Sopenharmony_ci * can we make it non-resident? if yes, do that. 1860987da915Sopenharmony_ci * does it fit now? yes -> do it. 1861987da915Sopenharmony_ci * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? 1862987da915Sopenharmony_ci * yes -> make non-resident 1863987da915Sopenharmony_ci * does it fit now? yes -> do it. 1864987da915Sopenharmony_ci * make all attributes non-resident 1865987da915Sopenharmony_ci * does it fit now? yes -> do it. 1866987da915Sopenharmony_ci * m is a base record? yes -> allocate extension record 1867987da915Sopenharmony_ci * does the new attribute fit in there? yes -> do it. 1868987da915Sopenharmony_ci * split up runlist into extents and place each in an extension 1869987da915Sopenharmony_ci * record. 1870987da915Sopenharmony_ci * FIXME: the check for needing extension records should be 1871987da915Sopenharmony_ci * earlier on as it is very quick: asize > m->bytes_allocated? 1872987da915Sopenharmony_ci */ 1873987da915Sopenharmony_ci err = -EOPNOTSUPP; 1874987da915Sopenharmony_ci goto err_out; 1875987da915Sopenharmony_ci } 1876987da915Sopenharmony_ci#ifdef DEBUG 1877987da915Sopenharmony_ci if (err == -EINVAL) { 1878987da915Sopenharmony_ci ntfs_log_error("BUG(): in insert_resident_attribute_in_mft_" 1879987da915Sopenharmony_ci "record(): make_room_for_attribute() returned " 1880987da915Sopenharmony_ci "error: EINVAL!\n"); 1881987da915Sopenharmony_ci goto err_out; 1882987da915Sopenharmony_ci } 1883987da915Sopenharmony_ci#endif 1884987da915Sopenharmony_ci a->type = type; 1885987da915Sopenharmony_ci a->length = cpu_to_le32(asize); 1886987da915Sopenharmony_ci a->non_resident = 0; 1887987da915Sopenharmony_ci a->name_length = name_len; 1888987da915Sopenharmony_ci if (type == AT_OBJECT_ID) 1889987da915Sopenharmony_ci a->name_offset = const_cpu_to_le16(0); 1890987da915Sopenharmony_ci else 1891987da915Sopenharmony_ci a->name_offset = const_cpu_to_le16(24); 1892987da915Sopenharmony_ci a->flags = flags; 1893987da915Sopenharmony_ci a->instance = m->next_attr_instance; 1894987da915Sopenharmony_ci m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) 1895987da915Sopenharmony_ci + 1) & 0xffff); 1896987da915Sopenharmony_ci a->value_length = cpu_to_le32(val_len); 1897987da915Sopenharmony_ci a->value_offset = cpu_to_le16(24 + ((name_len*2 + 7) & ~7)); 1898987da915Sopenharmony_ci a->resident_flags = res_flags; 1899987da915Sopenharmony_ci a->reservedR = 0; 1900987da915Sopenharmony_ci if (name_len) 1901987da915Sopenharmony_ci memcpy((char*)a + 24, uname, name_len << 1); 1902987da915Sopenharmony_ci if (val_len) 1903987da915Sopenharmony_ci memcpy((char*)a + le16_to_cpu(a->value_offset), val, val_len); 1904987da915Sopenharmony_cierr_out: 1905987da915Sopenharmony_ci if (ctx) 1906987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1907987da915Sopenharmony_ci ntfs_ucsfree(uname); 1908987da915Sopenharmony_ci return err; 1909987da915Sopenharmony_ci} 1910987da915Sopenharmony_ci 1911987da915Sopenharmony_ci 1912987da915Sopenharmony_ci/** 1913987da915Sopenharmony_ci * add_attr_std_info 1914987da915Sopenharmony_ci * 1915987da915Sopenharmony_ci * Return 0 on success or -errno on error. 1916987da915Sopenharmony_ci */ 1917987da915Sopenharmony_cistatic int add_attr_std_info(MFT_RECORD *m, const FILE_ATTR_FLAGS flags, 1918987da915Sopenharmony_ci le32 security_id) 1919987da915Sopenharmony_ci{ 1920987da915Sopenharmony_ci STANDARD_INFORMATION si; 1921987da915Sopenharmony_ci int err, sd_size; 1922987da915Sopenharmony_ci 1923987da915Sopenharmony_ci sd_size = 48; 1924987da915Sopenharmony_ci 1925987da915Sopenharmony_ci si.creation_time = mkntfs_time(); 1926987da915Sopenharmony_ci si.last_data_change_time = si.creation_time; 1927987da915Sopenharmony_ci si.last_mft_change_time = si.creation_time; 1928987da915Sopenharmony_ci si.last_access_time = si.creation_time; 1929987da915Sopenharmony_ci si.file_attributes = flags; /* already LE */ 1930987da915Sopenharmony_ci si.maximum_versions = const_cpu_to_le32(0); 1931987da915Sopenharmony_ci si.version_number = const_cpu_to_le32(0); 1932987da915Sopenharmony_ci si.class_id = const_cpu_to_le32(0); 1933987da915Sopenharmony_ci si.security_id = security_id; 1934987da915Sopenharmony_ci if (si.security_id != const_cpu_to_le32(0)) 1935987da915Sopenharmony_ci sd_size = 72; 1936987da915Sopenharmony_ci /* FIXME: $Quota support... */ 1937987da915Sopenharmony_ci si.owner_id = const_cpu_to_le32(0); 1938987da915Sopenharmony_ci si.quota_charged = const_cpu_to_le64(0ULL); 1939987da915Sopenharmony_ci /* FIXME: $UsnJrnl support... Not needed on fresh w2k3-volume */ 1940987da915Sopenharmony_ci si.usn = const_cpu_to_le64(0ULL); 1941987da915Sopenharmony_ci /* NTFS 1.2: size of si = 48, NTFS 3.[01]: size of si = 72 */ 1942987da915Sopenharmony_ci err = insert_resident_attr_in_mft_record(m, AT_STANDARD_INFORMATION, 1943987da915Sopenharmony_ci NULL, 0, CASE_SENSITIVE, const_cpu_to_le16(0), 1944987da915Sopenharmony_ci 0, (u8*)&si, sd_size); 1945987da915Sopenharmony_ci if (err < 0) 1946987da915Sopenharmony_ci ntfs_log_perror("add_attr_std_info failed"); 1947987da915Sopenharmony_ci return err; 1948987da915Sopenharmony_ci} 1949987da915Sopenharmony_ci 1950987da915Sopenharmony_ci/* 1951987da915Sopenharmony_ci * Tell whether the unnamed data is non resident 1952987da915Sopenharmony_ci */ 1953987da915Sopenharmony_ci 1954987da915Sopenharmony_cistatic BOOL non_resident_unnamed_data(MFT_RECORD *m) 1955987da915Sopenharmony_ci{ 1956987da915Sopenharmony_ci ATTR_RECORD *a; 1957987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 1958987da915Sopenharmony_ci BOOL nonres; 1959987da915Sopenharmony_ci 1960987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(NULL, m); 1961987da915Sopenharmony_ci if (ctx && !mkntfs_attr_find(AT_DATA, 1962987da915Sopenharmony_ci (const ntfschar*)NULL, 0, CASE_SENSITIVE, 1963987da915Sopenharmony_ci (u8*)NULL, 0, ctx)) { 1964987da915Sopenharmony_ci a = ctx->attr; 1965987da915Sopenharmony_ci nonres = a->non_resident != 0; 1966987da915Sopenharmony_ci } else { 1967987da915Sopenharmony_ci ntfs_log_error("BUG: Unnamed data not found\n"); 1968987da915Sopenharmony_ci nonres = TRUE; 1969987da915Sopenharmony_ci } 1970987da915Sopenharmony_ci if (ctx) 1971987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1972987da915Sopenharmony_ci return (nonres); 1973987da915Sopenharmony_ci} 1974987da915Sopenharmony_ci 1975987da915Sopenharmony_ci/* 1976987da915Sopenharmony_ci * Get the time stored in the standard information attribute 1977987da915Sopenharmony_ci */ 1978987da915Sopenharmony_ci 1979987da915Sopenharmony_cistatic ntfs_time stdinfo_time(MFT_RECORD *m) 1980987da915Sopenharmony_ci{ 1981987da915Sopenharmony_ci STANDARD_INFORMATION *si; 1982987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 1983987da915Sopenharmony_ci ntfs_time info_time; 1984987da915Sopenharmony_ci 1985987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(NULL, m); 1986987da915Sopenharmony_ci if (ctx && !mkntfs_attr_find(AT_STANDARD_INFORMATION, 1987987da915Sopenharmony_ci (const ntfschar*)NULL, 0, CASE_SENSITIVE, 1988987da915Sopenharmony_ci (u8*)NULL, 0, ctx)) { 1989987da915Sopenharmony_ci si = (STANDARD_INFORMATION*)((char*)ctx->attr + 1990987da915Sopenharmony_ci le16_to_cpu(ctx->attr->value_offset)); 1991987da915Sopenharmony_ci info_time = si->creation_time; 1992987da915Sopenharmony_ci } else { 1993987da915Sopenharmony_ci ntfs_log_error("BUG: Standard information not found\n"); 1994987da915Sopenharmony_ci info_time = mkntfs_time(); 1995987da915Sopenharmony_ci } 1996987da915Sopenharmony_ci if (ctx) 1997987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1998987da915Sopenharmony_ci return (info_time); 1999987da915Sopenharmony_ci} 2000987da915Sopenharmony_ci 2001987da915Sopenharmony_ci/** 2002987da915Sopenharmony_ci * add_attr_file_name 2003987da915Sopenharmony_ci * 2004987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2005987da915Sopenharmony_ci */ 2006987da915Sopenharmony_cistatic int add_attr_file_name(MFT_RECORD *m, const leMFT_REF parent_dir, 2007987da915Sopenharmony_ci const s64 allocated_size, const s64 data_size, 2008987da915Sopenharmony_ci const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, 2009987da915Sopenharmony_ci const u32 reparse_point_tag, const char *file_name, 2010987da915Sopenharmony_ci const FILE_NAME_TYPE_FLAGS file_name_type) 2011987da915Sopenharmony_ci{ 2012987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 2013987da915Sopenharmony_ci STANDARD_INFORMATION *si; 2014987da915Sopenharmony_ci FILE_NAME_ATTR *fn; 2015987da915Sopenharmony_ci int i, fn_size; 2016987da915Sopenharmony_ci ntfschar *uname; 2017987da915Sopenharmony_ci 2018987da915Sopenharmony_ci /* Check if the attribute is already there. */ 2019987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(NULL, m); 2020987da915Sopenharmony_ci if (!ctx) { 2021987da915Sopenharmony_ci ntfs_log_error("Failed to get attribute search context.\n"); 2022987da915Sopenharmony_ci return -ENOMEM; 2023987da915Sopenharmony_ci } 2024987da915Sopenharmony_ci if (mkntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 2025987da915Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx)) { 2026987da915Sopenharmony_ci int eo = errno; 2027987da915Sopenharmony_ci ntfs_log_error("BUG: Standard information attribute not " 2028987da915Sopenharmony_ci "present in file record.\n"); 2029987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 2030987da915Sopenharmony_ci return -eo; 2031987da915Sopenharmony_ci } 2032987da915Sopenharmony_ci si = (STANDARD_INFORMATION*)((char*)ctx->attr + 2033987da915Sopenharmony_ci le16_to_cpu(ctx->attr->value_offset)); 2034987da915Sopenharmony_ci i = (strlen(file_name) + 1) * sizeof(ntfschar); 2035987da915Sopenharmony_ci fn_size = sizeof(FILE_NAME_ATTR) + i; 2036987da915Sopenharmony_ci fn = ntfs_malloc(fn_size); 2037987da915Sopenharmony_ci if (!fn) { 2038987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 2039987da915Sopenharmony_ci return -errno; 2040987da915Sopenharmony_ci } 2041987da915Sopenharmony_ci fn->parent_directory = parent_dir; 2042987da915Sopenharmony_ci 2043987da915Sopenharmony_ci fn->creation_time = si->creation_time; 2044987da915Sopenharmony_ci fn->last_data_change_time = si->last_data_change_time; 2045987da915Sopenharmony_ci fn->last_mft_change_time = si->last_mft_change_time; 2046987da915Sopenharmony_ci fn->last_access_time = si->last_access_time; 2047987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 2048987da915Sopenharmony_ci 2049987da915Sopenharmony_ci fn->allocated_size = cpu_to_sle64(allocated_size); 2050987da915Sopenharmony_ci fn->data_size = cpu_to_sle64(data_size); 2051987da915Sopenharmony_ci fn->file_attributes = flags; 2052987da915Sopenharmony_ci /* These are in a union so can't have both. */ 2053987da915Sopenharmony_ci if (packed_ea_size && reparse_point_tag) { 2054987da915Sopenharmony_ci free(fn); 2055987da915Sopenharmony_ci return -EINVAL; 2056987da915Sopenharmony_ci } 2057987da915Sopenharmony_ci if (packed_ea_size) { 2058987da915Sopenharmony_ci fn->packed_ea_size = cpu_to_le16(packed_ea_size); 2059987da915Sopenharmony_ci fn->reserved = const_cpu_to_le16(0); 2060987da915Sopenharmony_ci } else { 2061987da915Sopenharmony_ci fn->reparse_point_tag = cpu_to_le32(reparse_point_tag); 2062987da915Sopenharmony_ci } 2063987da915Sopenharmony_ci fn->file_name_type = file_name_type; 2064987da915Sopenharmony_ci uname = fn->file_name; 2065987da915Sopenharmony_ci i = ntfs_mbstoucs_libntfscompat(file_name, &uname, i); 2066987da915Sopenharmony_ci if (i < 1) { 2067987da915Sopenharmony_ci free(fn); 2068987da915Sopenharmony_ci return -EINVAL; 2069987da915Sopenharmony_ci } 2070987da915Sopenharmony_ci if (i > 0xff) { 2071987da915Sopenharmony_ci free(fn); 2072987da915Sopenharmony_ci return -ENAMETOOLONG; 2073987da915Sopenharmony_ci } 2074987da915Sopenharmony_ci /* No terminating null in file names. */ 2075987da915Sopenharmony_ci fn->file_name_length = i; 2076987da915Sopenharmony_ci fn_size = sizeof(FILE_NAME_ATTR) + i * sizeof(ntfschar); 2077987da915Sopenharmony_ci i = insert_resident_attr_in_mft_record(m, AT_FILE_NAME, NULL, 0, 2078987da915Sopenharmony_ci CASE_SENSITIVE, const_cpu_to_le16(0), 2079987da915Sopenharmony_ci RESIDENT_ATTR_IS_INDEXED, (u8*)fn, fn_size); 2080987da915Sopenharmony_ci free(fn); 2081987da915Sopenharmony_ci if (i < 0) 2082987da915Sopenharmony_ci ntfs_log_error("add_attr_file_name failed: %s\n", strerror(-i)); 2083987da915Sopenharmony_ci return i; 2084987da915Sopenharmony_ci} 2085987da915Sopenharmony_ci 2086987da915Sopenharmony_ci/** 2087987da915Sopenharmony_ci * add_attr_object_id - 2088987da915Sopenharmony_ci * 2089987da915Sopenharmony_ci * Note we insert only a basic object id which only has the GUID and none of 2090987da915Sopenharmony_ci * the extended fields. This is because we currently only use this function 2091987da915Sopenharmony_ci * when creating the object id for the volume. 2092987da915Sopenharmony_ci * 2093987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2094987da915Sopenharmony_ci */ 2095987da915Sopenharmony_cistatic int add_attr_object_id(MFT_RECORD *m, const GUID *object_id) 2096987da915Sopenharmony_ci{ 2097987da915Sopenharmony_ci OBJECT_ID_ATTR oi; 2098987da915Sopenharmony_ci int err; 2099987da915Sopenharmony_ci 2100987da915Sopenharmony_ci oi = (OBJECT_ID_ATTR) { 2101987da915Sopenharmony_ci .object_id = *object_id, 2102987da915Sopenharmony_ci }; 2103987da915Sopenharmony_ci err = insert_resident_attr_in_mft_record(m, AT_OBJECT_ID, NULL, 2104987da915Sopenharmony_ci 0, CASE_SENSITIVE, const_cpu_to_le16(0), 2105987da915Sopenharmony_ci 0, (u8*)&oi, sizeof(oi.object_id)); 2106987da915Sopenharmony_ci if (err < 0) 2107987da915Sopenharmony_ci ntfs_log_error("add_attr_vol_info failed: %s\n", strerror(-err)); 2108987da915Sopenharmony_ci return err; 2109987da915Sopenharmony_ci} 2110987da915Sopenharmony_ci 2111987da915Sopenharmony_ci/** 2112987da915Sopenharmony_ci * add_attr_sd 2113987da915Sopenharmony_ci * 2114987da915Sopenharmony_ci * Create the security descriptor attribute adding the security descriptor @sd 2115987da915Sopenharmony_ci * of length @sd_len to the mft record @m. 2116987da915Sopenharmony_ci * 2117987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2118987da915Sopenharmony_ci */ 2119987da915Sopenharmony_cistatic int add_attr_sd(MFT_RECORD *m, const u8 *sd, const s64 sd_len) 2120987da915Sopenharmony_ci{ 2121987da915Sopenharmony_ci int err; 2122987da915Sopenharmony_ci 2123987da915Sopenharmony_ci /* Does it fit? NO: create non-resident. YES: create resident. */ 2124987da915Sopenharmony_ci if (le32_to_cpu(m->bytes_in_use) + 24 + sd_len > 2125987da915Sopenharmony_ci le32_to_cpu(m->bytes_allocated)) 2126987da915Sopenharmony_ci err = insert_non_resident_attr_in_mft_record(m, 2127987da915Sopenharmony_ci AT_SECURITY_DESCRIPTOR, NULL, 0, 2128987da915Sopenharmony_ci CASE_SENSITIVE, const_cpu_to_le16(0), sd, 2129987da915Sopenharmony_ci sd_len, WRITE_STANDARD); 2130987da915Sopenharmony_ci else 2131987da915Sopenharmony_ci err = insert_resident_attr_in_mft_record(m, 2132987da915Sopenharmony_ci AT_SECURITY_DESCRIPTOR, NULL, 0, 2133987da915Sopenharmony_ci CASE_SENSITIVE, const_cpu_to_le16(0), 0, sd, 2134987da915Sopenharmony_ci sd_len); 2135987da915Sopenharmony_ci if (err < 0) 2136987da915Sopenharmony_ci ntfs_log_error("add_attr_sd failed: %s\n", strerror(-err)); 2137987da915Sopenharmony_ci return err; 2138987da915Sopenharmony_ci} 2139987da915Sopenharmony_ci 2140987da915Sopenharmony_ci/** 2141987da915Sopenharmony_ci * add_attr_data 2142987da915Sopenharmony_ci * 2143987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2144987da915Sopenharmony_ci */ 2145987da915Sopenharmony_cistatic int add_attr_data(MFT_RECORD *m, const char *name, const u32 name_len, 2146987da915Sopenharmony_ci const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, 2147987da915Sopenharmony_ci const u8 *val, const s64 val_len) 2148987da915Sopenharmony_ci{ 2149987da915Sopenharmony_ci int err; 2150987da915Sopenharmony_ci 2151987da915Sopenharmony_ci /* 2152987da915Sopenharmony_ci * Does it fit? NO: create non-resident. YES: create resident. 2153987da915Sopenharmony_ci * 2154987da915Sopenharmony_ci * FIXME: Introduced arbitrary limit of mft record allocated size - 512. 2155987da915Sopenharmony_ci * This is to get around the problem that if $Bitmap/$DATA becomes too 2156987da915Sopenharmony_ci * big, but is just small enough to be resident, we would make it 2157987da915Sopenharmony_ci * resident, and later run out of space when creating the other 2158987da915Sopenharmony_ci * attributes and this would cause us to abort as making resident 2159987da915Sopenharmony_ci * attributes non-resident is not supported yet. 2160987da915Sopenharmony_ci * The proper fix is to support making resident attribute non-resident. 2161987da915Sopenharmony_ci */ 2162987da915Sopenharmony_ci if (le32_to_cpu(m->bytes_in_use) + 24 + val_len > 2163987da915Sopenharmony_ci min(le32_to_cpu(m->bytes_allocated), 2164987da915Sopenharmony_ci le32_to_cpu(m->bytes_allocated) - 512)) 2165987da915Sopenharmony_ci err = insert_non_resident_attr_in_mft_record(m, AT_DATA, name, 2166987da915Sopenharmony_ci name_len, ic, flags, val, val_len, 2167987da915Sopenharmony_ci WRITE_STANDARD); 2168987da915Sopenharmony_ci else 2169987da915Sopenharmony_ci err = insert_resident_attr_in_mft_record(m, AT_DATA, name, 2170987da915Sopenharmony_ci name_len, ic, flags, 0, val, val_len); 2171987da915Sopenharmony_ci 2172987da915Sopenharmony_ci if (err < 0) 2173987da915Sopenharmony_ci ntfs_log_error("add_attr_data failed: %s\n", strerror(-err)); 2174987da915Sopenharmony_ci return err; 2175987da915Sopenharmony_ci} 2176987da915Sopenharmony_ci 2177987da915Sopenharmony_ci/** 2178987da915Sopenharmony_ci * add_attr_data_positioned 2179987da915Sopenharmony_ci * 2180987da915Sopenharmony_ci * Create a non-resident data attribute with a predefined on disk location 2181987da915Sopenharmony_ci * specified by the runlist @rl. The clusters specified by @rl are assumed to 2182987da915Sopenharmony_ci * be allocated already. 2183987da915Sopenharmony_ci * 2184987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2185987da915Sopenharmony_ci */ 2186987da915Sopenharmony_cistatic int add_attr_data_positioned(MFT_RECORD *m, const char *name, 2187987da915Sopenharmony_ci const u32 name_len, const IGNORE_CASE_BOOL ic, 2188987da915Sopenharmony_ci const ATTR_FLAGS flags, const runlist *rl, 2189987da915Sopenharmony_ci const u8 *val, const s64 val_len) 2190987da915Sopenharmony_ci{ 2191987da915Sopenharmony_ci int err; 2192987da915Sopenharmony_ci 2193987da915Sopenharmony_ci err = insert_positioned_attr_in_mft_record(m, AT_DATA, name, name_len, 2194987da915Sopenharmony_ci ic, flags, rl, val, val_len); 2195987da915Sopenharmony_ci if (err < 0) 2196987da915Sopenharmony_ci ntfs_log_error("add_attr_data_positioned failed: %s\n", 2197987da915Sopenharmony_ci strerror(-err)); 2198987da915Sopenharmony_ci return err; 2199987da915Sopenharmony_ci} 2200987da915Sopenharmony_ci 2201987da915Sopenharmony_ci/** 2202987da915Sopenharmony_ci * add_attr_vol_name 2203987da915Sopenharmony_ci * 2204987da915Sopenharmony_ci * Create volume name attribute specifying the volume name @vol_name as a null 2205987da915Sopenharmony_ci * terminated char string of length @vol_name_len (number of characters not 2206987da915Sopenharmony_ci * including the terminating null), which is converted internally to a little 2207987da915Sopenharmony_ci * endian ntfschar string. The name is at least 1 character long (though 2208987da915Sopenharmony_ci * Windows accepts zero characters), and at most 128 characters long (not 2209987da915Sopenharmony_ci * counting the terminating null). 2210987da915Sopenharmony_ci * 2211987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2212987da915Sopenharmony_ci */ 2213987da915Sopenharmony_cistatic int add_attr_vol_name(MFT_RECORD *m, const char *vol_name, 2214987da915Sopenharmony_ci const int vol_name_len __attribute__((unused))) 2215987da915Sopenharmony_ci{ 2216987da915Sopenharmony_ci ntfschar *uname = NULL; 2217987da915Sopenharmony_ci int uname_len = 0; 2218987da915Sopenharmony_ci int i; 2219987da915Sopenharmony_ci 2220987da915Sopenharmony_ci if (vol_name) { 2221987da915Sopenharmony_ci uname_len = ntfs_mbstoucs(vol_name, &uname); 2222987da915Sopenharmony_ci if (uname_len < 0) 2223987da915Sopenharmony_ci return -errno; 2224987da915Sopenharmony_ci if (uname_len > 128) { 2225987da915Sopenharmony_ci free(uname); 2226987da915Sopenharmony_ci return -ENAMETOOLONG; 2227987da915Sopenharmony_ci } 2228987da915Sopenharmony_ci } 2229987da915Sopenharmony_ci i = insert_resident_attr_in_mft_record(m, AT_VOLUME_NAME, NULL, 0, 2230987da915Sopenharmony_ci CASE_SENSITIVE, const_cpu_to_le16(0), 2231987da915Sopenharmony_ci 0, (u8*)uname, uname_len*sizeof(ntfschar)); 2232987da915Sopenharmony_ci free(uname); 2233987da915Sopenharmony_ci if (i < 0) 2234987da915Sopenharmony_ci ntfs_log_error("add_attr_vol_name failed: %s\n", strerror(-i)); 2235987da915Sopenharmony_ci return i; 2236987da915Sopenharmony_ci} 2237987da915Sopenharmony_ci 2238987da915Sopenharmony_ci/** 2239987da915Sopenharmony_ci * add_attr_vol_info 2240987da915Sopenharmony_ci * 2241987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2242987da915Sopenharmony_ci */ 2243987da915Sopenharmony_cistatic int add_attr_vol_info(MFT_RECORD *m, const VOLUME_FLAGS flags, 2244987da915Sopenharmony_ci const u8 major_ver, const u8 minor_ver) 2245987da915Sopenharmony_ci{ 2246987da915Sopenharmony_ci VOLUME_INFORMATION vi; 2247987da915Sopenharmony_ci int err; 2248987da915Sopenharmony_ci 2249987da915Sopenharmony_ci memset(&vi, 0, sizeof(vi)); 2250987da915Sopenharmony_ci vi.major_ver = major_ver; 2251987da915Sopenharmony_ci vi.minor_ver = minor_ver; 2252987da915Sopenharmony_ci vi.flags = flags & VOLUME_FLAGS_MASK; 2253987da915Sopenharmony_ci err = insert_resident_attr_in_mft_record(m, AT_VOLUME_INFORMATION, NULL, 2254987da915Sopenharmony_ci 0, CASE_SENSITIVE, const_cpu_to_le16(0), 2255987da915Sopenharmony_ci 0, (u8*)&vi, sizeof(vi)); 2256987da915Sopenharmony_ci if (err < 0) 2257987da915Sopenharmony_ci ntfs_log_error("add_attr_vol_info failed: %s\n", strerror(-err)); 2258987da915Sopenharmony_ci return err; 2259987da915Sopenharmony_ci} 2260987da915Sopenharmony_ci 2261987da915Sopenharmony_ci/** 2262987da915Sopenharmony_ci * add_attr_index_root 2263987da915Sopenharmony_ci * 2264987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2265987da915Sopenharmony_ci */ 2266987da915Sopenharmony_cistatic int add_attr_index_root(MFT_RECORD *m, const char *name, 2267987da915Sopenharmony_ci const u32 name_len, const IGNORE_CASE_BOOL ic, 2268987da915Sopenharmony_ci const ATTR_TYPES indexed_attr_type, 2269987da915Sopenharmony_ci const COLLATION_RULES collation_rule, 2270987da915Sopenharmony_ci const u32 index_block_size) 2271987da915Sopenharmony_ci{ 2272987da915Sopenharmony_ci INDEX_ROOT *r; 2273987da915Sopenharmony_ci INDEX_ENTRY_HEADER *e; 2274987da915Sopenharmony_ci int err, val_len; 2275987da915Sopenharmony_ci 2276987da915Sopenharmony_ci val_len = sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER); 2277987da915Sopenharmony_ci r = ntfs_malloc(val_len); 2278987da915Sopenharmony_ci if (!r) 2279987da915Sopenharmony_ci return -errno; 2280987da915Sopenharmony_ci r->type = (indexed_attr_type == AT_FILE_NAME) 2281987da915Sopenharmony_ci ? AT_FILE_NAME : const_cpu_to_le32(0); 2282987da915Sopenharmony_ci if (indexed_attr_type == AT_FILE_NAME && 2283987da915Sopenharmony_ci collation_rule != COLLATION_FILE_NAME) { 2284987da915Sopenharmony_ci free(r); 2285987da915Sopenharmony_ci ntfs_log_error("add_attr_index_root: indexed attribute is $FILE_NAME " 2286987da915Sopenharmony_ci "but collation rule is not COLLATION_FILE_NAME.\n"); 2287987da915Sopenharmony_ci return -EINVAL; 2288987da915Sopenharmony_ci } 2289987da915Sopenharmony_ci r->collation_rule = collation_rule; 2290987da915Sopenharmony_ci r->index_block_size = cpu_to_le32(index_block_size); 2291987da915Sopenharmony_ci if (index_block_size >= g_vol->cluster_size) { 2292987da915Sopenharmony_ci if (index_block_size % g_vol->cluster_size) { 2293987da915Sopenharmony_ci ntfs_log_error("add_attr_index_root: index block size is not " 2294987da915Sopenharmony_ci "a multiple of the cluster size.\n"); 2295987da915Sopenharmony_ci free(r); 2296987da915Sopenharmony_ci return -EINVAL; 2297987da915Sopenharmony_ci } 2298987da915Sopenharmony_ci r->clusters_per_index_block = index_block_size / 2299987da915Sopenharmony_ci g_vol->cluster_size; 2300987da915Sopenharmony_ci } else { /* if (g_vol->cluster_size > index_block_size) */ 2301987da915Sopenharmony_ci if (index_block_size & (index_block_size - 1)) { 2302987da915Sopenharmony_ci ntfs_log_error("add_attr_index_root: index block size is not " 2303987da915Sopenharmony_ci "a power of 2.\n"); 2304987da915Sopenharmony_ci free(r); 2305987da915Sopenharmony_ci return -EINVAL; 2306987da915Sopenharmony_ci } 2307987da915Sopenharmony_ci if (index_block_size < (u32)opts.sector_size) { 2308987da915Sopenharmony_ci ntfs_log_error("add_attr_index_root: index block size " 2309987da915Sopenharmony_ci "is smaller than the sector size.\n"); 2310987da915Sopenharmony_ci free(r); 2311987da915Sopenharmony_ci return -EINVAL; 2312987da915Sopenharmony_ci } 2313987da915Sopenharmony_ci r->clusters_per_index_block = index_block_size 2314987da915Sopenharmony_ci >> NTFS_BLOCK_SIZE_BITS; 2315987da915Sopenharmony_ci } 2316987da915Sopenharmony_ci memset(&r->reserved, 0, sizeof(r->reserved)); 2317987da915Sopenharmony_ci r->index.entries_offset = const_cpu_to_le32(sizeof(INDEX_HEADER)); 2318987da915Sopenharmony_ci r->index.index_length = const_cpu_to_le32(sizeof(INDEX_HEADER) + 2319987da915Sopenharmony_ci sizeof(INDEX_ENTRY_HEADER)); 2320987da915Sopenharmony_ci r->index.allocated_size = r->index.index_length; 2321987da915Sopenharmony_ci r->index.ih_flags = SMALL_INDEX; 2322987da915Sopenharmony_ci memset(&r->index.reserved, 0, sizeof(r->index.reserved)); 2323987da915Sopenharmony_ci e = (INDEX_ENTRY_HEADER*)((u8*)&r->index + 2324987da915Sopenharmony_ci le32_to_cpu(r->index.entries_offset)); 2325987da915Sopenharmony_ci /* 2326987da915Sopenharmony_ci * No matter whether this is a file index or a view as this is a 2327987da915Sopenharmony_ci * termination entry, hence no key value / data is associated with it 2328987da915Sopenharmony_ci * at all. Thus, we just need the union to be all zero. 2329987da915Sopenharmony_ci */ 2330987da915Sopenharmony_ci e->indexed_file = const_cpu_to_le64(0LL); 2331987da915Sopenharmony_ci e->length = const_cpu_to_le16(sizeof(INDEX_ENTRY_HEADER)); 2332987da915Sopenharmony_ci e->key_length = const_cpu_to_le16(0); 2333987da915Sopenharmony_ci e->flags = INDEX_ENTRY_END; 2334987da915Sopenharmony_ci e->reserved = const_cpu_to_le16(0); 2335987da915Sopenharmony_ci err = insert_resident_attr_in_mft_record(m, AT_INDEX_ROOT, name, 2336987da915Sopenharmony_ci name_len, ic, const_cpu_to_le16(0), 0, 2337987da915Sopenharmony_ci (u8*)r, val_len); 2338987da915Sopenharmony_ci free(r); 2339987da915Sopenharmony_ci if (err < 0) 2340987da915Sopenharmony_ci ntfs_log_error("add_attr_index_root failed: %s\n", strerror(-err)); 2341987da915Sopenharmony_ci return err; 2342987da915Sopenharmony_ci} 2343987da915Sopenharmony_ci 2344987da915Sopenharmony_ci/** 2345987da915Sopenharmony_ci * add_attr_index_alloc 2346987da915Sopenharmony_ci * 2347987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2348987da915Sopenharmony_ci */ 2349987da915Sopenharmony_cistatic int add_attr_index_alloc(MFT_RECORD *m, const char *name, 2350987da915Sopenharmony_ci const u32 name_len, const IGNORE_CASE_BOOL ic, 2351987da915Sopenharmony_ci const u8 *index_alloc_val, const u32 index_alloc_val_len) 2352987da915Sopenharmony_ci{ 2353987da915Sopenharmony_ci int err; 2354987da915Sopenharmony_ci 2355987da915Sopenharmony_ci err = insert_non_resident_attr_in_mft_record(m, AT_INDEX_ALLOCATION, 2356987da915Sopenharmony_ci name, name_len, ic, const_cpu_to_le16(0), 2357987da915Sopenharmony_ci index_alloc_val, index_alloc_val_len, WRITE_STANDARD); 2358987da915Sopenharmony_ci if (err < 0) 2359987da915Sopenharmony_ci ntfs_log_error("add_attr_index_alloc failed: %s\n", strerror(-err)); 2360987da915Sopenharmony_ci return err; 2361987da915Sopenharmony_ci} 2362987da915Sopenharmony_ci 2363987da915Sopenharmony_ci/** 2364987da915Sopenharmony_ci * add_attr_bitmap 2365987da915Sopenharmony_ci * 2366987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2367987da915Sopenharmony_ci */ 2368987da915Sopenharmony_cistatic int add_attr_bitmap(MFT_RECORD *m, const char *name, const u32 name_len, 2369987da915Sopenharmony_ci const IGNORE_CASE_BOOL ic, const u8 *bitmap, 2370987da915Sopenharmony_ci const u32 bitmap_len) 2371987da915Sopenharmony_ci{ 2372987da915Sopenharmony_ci int err; 2373987da915Sopenharmony_ci 2374987da915Sopenharmony_ci /* Does it fit? NO: create non-resident. YES: create resident. */ 2375987da915Sopenharmony_ci if (le32_to_cpu(m->bytes_in_use) + 24 + bitmap_len > 2376987da915Sopenharmony_ci le32_to_cpu(m->bytes_allocated)) 2377987da915Sopenharmony_ci err = insert_non_resident_attr_in_mft_record(m, AT_BITMAP, name, 2378987da915Sopenharmony_ci name_len, ic, const_cpu_to_le16(0), bitmap, 2379987da915Sopenharmony_ci bitmap_len, WRITE_STANDARD); 2380987da915Sopenharmony_ci else 2381987da915Sopenharmony_ci err = insert_resident_attr_in_mft_record(m, AT_BITMAP, name, 2382987da915Sopenharmony_ci name_len, ic, const_cpu_to_le16(0), 0, 2383987da915Sopenharmony_ci bitmap, bitmap_len); 2384987da915Sopenharmony_ci 2385987da915Sopenharmony_ci if (err < 0) 2386987da915Sopenharmony_ci ntfs_log_error("add_attr_bitmap failed: %s\n", strerror(-err)); 2387987da915Sopenharmony_ci return err; 2388987da915Sopenharmony_ci} 2389987da915Sopenharmony_ci 2390987da915Sopenharmony_ci/** 2391987da915Sopenharmony_ci * add_attr_bitmap_positioned 2392987da915Sopenharmony_ci * 2393987da915Sopenharmony_ci * Create a non-resident bitmap attribute with a predefined on disk location 2394987da915Sopenharmony_ci * specified by the runlist @rl. The clusters specified by @rl are assumed to 2395987da915Sopenharmony_ci * be allocated already. 2396987da915Sopenharmony_ci * 2397987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2398987da915Sopenharmony_ci */ 2399987da915Sopenharmony_cistatic int add_attr_bitmap_positioned(MFT_RECORD *m, const char *name, 2400987da915Sopenharmony_ci const u32 name_len, const IGNORE_CASE_BOOL ic, 2401987da915Sopenharmony_ci const runlist *rl, const u8 *bitmap, const u32 bitmap_len) 2402987da915Sopenharmony_ci{ 2403987da915Sopenharmony_ci int err; 2404987da915Sopenharmony_ci 2405987da915Sopenharmony_ci err = insert_positioned_attr_in_mft_record(m, AT_BITMAP, name, name_len, 2406987da915Sopenharmony_ci ic, const_cpu_to_le16(0), rl, bitmap, bitmap_len); 2407987da915Sopenharmony_ci if (err < 0) 2408987da915Sopenharmony_ci ntfs_log_error("add_attr_bitmap_positioned failed: %s\n", 2409987da915Sopenharmony_ci strerror(-err)); 2410987da915Sopenharmony_ci return err; 2411987da915Sopenharmony_ci} 2412987da915Sopenharmony_ci 2413987da915Sopenharmony_ci 2414987da915Sopenharmony_ci/** 2415987da915Sopenharmony_ci * upgrade_to_large_index 2416987da915Sopenharmony_ci * 2417987da915Sopenharmony_ci * Create bitmap and index allocation attributes, modify index root 2418987da915Sopenharmony_ci * attribute accordingly and move all of the index entries from the index root 2419987da915Sopenharmony_ci * into the index allocation. 2420987da915Sopenharmony_ci * 2421987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2422987da915Sopenharmony_ci */ 2423987da915Sopenharmony_cistatic int upgrade_to_large_index(MFT_RECORD *m, const char *name, 2424987da915Sopenharmony_ci u32 name_len, const IGNORE_CASE_BOOL ic, 2425987da915Sopenharmony_ci INDEX_ALLOCATION **idx) 2426987da915Sopenharmony_ci{ 2427987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 2428987da915Sopenharmony_ci ATTR_RECORD *a; 2429987da915Sopenharmony_ci INDEX_ROOT *r; 2430987da915Sopenharmony_ci INDEX_ENTRY *re; 2431987da915Sopenharmony_ci INDEX_ALLOCATION *ia_val = NULL; 2432987da915Sopenharmony_ci ntfschar *uname = NULL; 2433987da915Sopenharmony_ci int uname_len = 0; 2434987da915Sopenharmony_ci u8 bmp[8]; 2435987da915Sopenharmony_ci char *re_start, *re_end; 2436987da915Sopenharmony_ci int i, err, index_block_size; 2437987da915Sopenharmony_ci 2438987da915Sopenharmony_ci uname = ntfs_str2ucs(name, &uname_len); 2439987da915Sopenharmony_ci if (!uname) 2440987da915Sopenharmony_ci return -errno; 2441987da915Sopenharmony_ci 2442987da915Sopenharmony_ci /* Find the index root attribute. */ 2443987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(NULL, m); 2444987da915Sopenharmony_ci if (!ctx) { 2445987da915Sopenharmony_ci ntfs_log_error("Failed to allocate attribute search context.\n"); 2446987da915Sopenharmony_ci ntfs_ucsfree(uname); 2447987da915Sopenharmony_ci return -ENOMEM; 2448987da915Sopenharmony_ci } 2449987da915Sopenharmony_ci if (ic == IGNORE_CASE) { 2450987da915Sopenharmony_ci ntfs_log_error("FIXME: Hit unimplemented code path #4.\n"); 2451987da915Sopenharmony_ci err = -EOPNOTSUPP; 2452987da915Sopenharmony_ci ntfs_ucsfree(uname); 2453987da915Sopenharmony_ci goto err_out; 2454987da915Sopenharmony_ci } 2455987da915Sopenharmony_ci err = mkntfs_attr_lookup(AT_INDEX_ROOT, uname, uname_len, ic, 0, NULL, 0, 2456987da915Sopenharmony_ci ctx); 2457987da915Sopenharmony_ci ntfs_ucsfree(uname); 2458987da915Sopenharmony_ci if (err) { 2459987da915Sopenharmony_ci err = -ENOTDIR; 2460987da915Sopenharmony_ci goto err_out; 2461987da915Sopenharmony_ci } 2462987da915Sopenharmony_ci a = ctx->attr; 2463987da915Sopenharmony_ci if (a->non_resident || a->flags) { 2464987da915Sopenharmony_ci err = -EINVAL; 2465987da915Sopenharmony_ci goto err_out; 2466987da915Sopenharmony_ci } 2467987da915Sopenharmony_ci r = (INDEX_ROOT*)((char*)a + le16_to_cpu(a->value_offset)); 2468987da915Sopenharmony_ci re_end = (char*)r + le32_to_cpu(a->value_length); 2469987da915Sopenharmony_ci re_start = (char*)&r->index + le32_to_cpu(r->index.entries_offset); 2470987da915Sopenharmony_ci re = (INDEX_ENTRY*)re_start; 2471987da915Sopenharmony_ci index_block_size = le32_to_cpu(r->index_block_size); 2472987da915Sopenharmony_ci memset(bmp, 0, sizeof(bmp)); 2473987da915Sopenharmony_ci ntfs_bit_set(bmp, 0ULL, 1); 2474987da915Sopenharmony_ci /* Bitmap has to be at least 8 bytes in size. */ 2475987da915Sopenharmony_ci err = add_attr_bitmap(m, name, name_len, ic, bmp, sizeof(bmp)); 2476987da915Sopenharmony_ci if (err) 2477987da915Sopenharmony_ci goto err_out; 2478987da915Sopenharmony_ci ia_val = ntfs_calloc(index_block_size); 2479987da915Sopenharmony_ci if (!ia_val) { 2480987da915Sopenharmony_ci err = -errno; 2481987da915Sopenharmony_ci goto err_out; 2482987da915Sopenharmony_ci } 2483987da915Sopenharmony_ci /* Setup header. */ 2484987da915Sopenharmony_ci ia_val->magic = magic_INDX; 2485987da915Sopenharmony_ci ia_val->usa_ofs = const_cpu_to_le16(sizeof(INDEX_ALLOCATION)); 2486987da915Sopenharmony_ci if (index_block_size >= NTFS_BLOCK_SIZE) { 2487987da915Sopenharmony_ci ia_val->usa_count = cpu_to_le16(index_block_size / 2488987da915Sopenharmony_ci NTFS_BLOCK_SIZE + 1); 2489987da915Sopenharmony_ci } else { 2490987da915Sopenharmony_ci ia_val->usa_count = const_cpu_to_le16(1); 2491987da915Sopenharmony_ci ntfs_log_error("Sector size is bigger than index block size. " 2492987da915Sopenharmony_ci "Setting usa_count to 1. If Windows chkdsk " 2493987da915Sopenharmony_ci "reports this as corruption, please email %s " 2494987da915Sopenharmony_ci "stating that you saw this message and that " 2495987da915Sopenharmony_ci "the filesystem created was corrupt. " 2496987da915Sopenharmony_ci "Thank you.", NTFS_DEV_LIST); 2497987da915Sopenharmony_ci } 2498987da915Sopenharmony_ci /* Set USN to 1. */ 2499987da915Sopenharmony_ci *(le16*)((char*)ia_val + le16_to_cpu(ia_val->usa_ofs)) = 2500987da915Sopenharmony_ci const_cpu_to_le16(1); 2501987da915Sopenharmony_ci ia_val->lsn = const_cpu_to_sle64(0); 2502987da915Sopenharmony_ci ia_val->index_block_vcn = const_cpu_to_sle64(0); 2503987da915Sopenharmony_ci ia_val->index.ih_flags = LEAF_NODE; 2504987da915Sopenharmony_ci /* Align to 8-byte boundary. */ 2505987da915Sopenharmony_ci ia_val->index.entries_offset = cpu_to_le32((sizeof(INDEX_HEADER) + 2506987da915Sopenharmony_ci le16_to_cpu(ia_val->usa_count) * 2 + 7) & ~7); 2507987da915Sopenharmony_ci ia_val->index.allocated_size = cpu_to_le32(index_block_size - 2508987da915Sopenharmony_ci (sizeof(INDEX_ALLOCATION) - sizeof(INDEX_HEADER))); 2509987da915Sopenharmony_ci /* Find the last entry in the index root and save it in re. */ 2510987da915Sopenharmony_ci while ((char*)re < re_end && !(re->ie_flags & INDEX_ENTRY_END)) { 2511987da915Sopenharmony_ci /* Next entry in index root. */ 2512987da915Sopenharmony_ci re = (INDEX_ENTRY*)((char*)re + le16_to_cpu(re->length)); 2513987da915Sopenharmony_ci } 2514987da915Sopenharmony_ci /* Copy all the entries including the termination entry. */ 2515987da915Sopenharmony_ci i = (char*)re - re_start + le16_to_cpu(re->length); 2516987da915Sopenharmony_ci memcpy((char*)&ia_val->index + 2517987da915Sopenharmony_ci le32_to_cpu(ia_val->index.entries_offset), re_start, i); 2518987da915Sopenharmony_ci /* Finish setting up index allocation. */ 2519987da915Sopenharmony_ci ia_val->index.index_length = cpu_to_le32(i + 2520987da915Sopenharmony_ci le32_to_cpu(ia_val->index.entries_offset)); 2521987da915Sopenharmony_ci /* Move the termination entry forward to the beginning if necessary. */ 2522987da915Sopenharmony_ci if ((char*)re > re_start) { 2523987da915Sopenharmony_ci memmove(re_start, (char*)re, le16_to_cpu(re->length)); 2524987da915Sopenharmony_ci re = (INDEX_ENTRY*)re_start; 2525987da915Sopenharmony_ci } 2526987da915Sopenharmony_ci /* Now fixup empty index root with pointer to index allocation VCN 0. */ 2527987da915Sopenharmony_ci r->index.ih_flags = LARGE_INDEX; 2528987da915Sopenharmony_ci re->ie_flags |= INDEX_ENTRY_NODE; 2529987da915Sopenharmony_ci if (le16_to_cpu(re->length) < sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN)) 2530987da915Sopenharmony_ci re->length = cpu_to_le16(le16_to_cpu(re->length) + sizeof(VCN)); 2531987da915Sopenharmony_ci r->index.index_length = cpu_to_le32(le32_to_cpu(r->index.entries_offset) 2532987da915Sopenharmony_ci + le16_to_cpu(re->length)); 2533987da915Sopenharmony_ci r->index.allocated_size = r->index.index_length; 2534987da915Sopenharmony_ci /* Resize index root attribute. */ 2535987da915Sopenharmony_ci if (ntfs_resident_attr_value_resize(m, a, sizeof(INDEX_ROOT) - 2536987da915Sopenharmony_ci sizeof(INDEX_HEADER) + 2537987da915Sopenharmony_ci le32_to_cpu(r->index.allocated_size))) { 2538987da915Sopenharmony_ci /* TODO: Remove the added bitmap! */ 2539987da915Sopenharmony_ci /* Revert index root from index allocation. */ 2540987da915Sopenharmony_ci err = -errno; 2541987da915Sopenharmony_ci goto err_out; 2542987da915Sopenharmony_ci } 2543987da915Sopenharmony_ci /* Set VCN pointer to 0LL. */ 2544987da915Sopenharmony_ci *(leVCN*)((char*)re + le16_to_cpu(re->length) - sizeof(VCN)) = 2545987da915Sopenharmony_ci const_cpu_to_sle64(0); 2546987da915Sopenharmony_ci err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)ia_val, index_block_size); 2547987da915Sopenharmony_ci if (err) { 2548987da915Sopenharmony_ci err = -errno; 2549987da915Sopenharmony_ci ntfs_log_error("ntfs_mst_pre_write_fixup() failed in " 2550987da915Sopenharmony_ci "upgrade_to_large_index.\n"); 2551987da915Sopenharmony_ci goto err_out; 2552987da915Sopenharmony_ci } 2553987da915Sopenharmony_ci err = add_attr_index_alloc(m, name, name_len, ic, (u8*)ia_val, 2554987da915Sopenharmony_ci index_block_size); 2555987da915Sopenharmony_ci ntfs_mst_post_write_fixup((NTFS_RECORD*)ia_val); 2556987da915Sopenharmony_ci if (err) { 2557987da915Sopenharmony_ci /* TODO: Remove the added bitmap! */ 2558987da915Sopenharmony_ci /* Revert index root from index allocation. */ 2559987da915Sopenharmony_ci goto err_out; 2560987da915Sopenharmony_ci } 2561987da915Sopenharmony_ci *idx = ia_val; 2562987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 2563987da915Sopenharmony_ci return 0; 2564987da915Sopenharmony_cierr_out: 2565987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 2566987da915Sopenharmony_ci free(ia_val); 2567987da915Sopenharmony_ci return err; 2568987da915Sopenharmony_ci} 2569987da915Sopenharmony_ci 2570987da915Sopenharmony_ci/** 2571987da915Sopenharmony_ci * make_room_for_index_entry_in_index_block 2572987da915Sopenharmony_ci * 2573987da915Sopenharmony_ci * Create space of @size bytes at position @pos inside the index block @idx. 2574987da915Sopenharmony_ci * 2575987da915Sopenharmony_ci * Return 0 on success or -errno on error. 2576987da915Sopenharmony_ci */ 2577987da915Sopenharmony_cistatic int make_room_for_index_entry_in_index_block(INDEX_BLOCK *idx, 2578987da915Sopenharmony_ci INDEX_ENTRY *pos, u32 size) 2579987da915Sopenharmony_ci{ 2580987da915Sopenharmony_ci u32 biu; 2581987da915Sopenharmony_ci 2582987da915Sopenharmony_ci if (!size) 2583987da915Sopenharmony_ci return 0; 2584987da915Sopenharmony_ci#ifdef DEBUG 2585987da915Sopenharmony_ci /* 2586987da915Sopenharmony_ci * Rigorous consistency checks. Always return -EINVAL even if more 2587987da915Sopenharmony_ci * appropriate codes exist for simplicity of parsing the return value. 2588987da915Sopenharmony_ci */ 2589987da915Sopenharmony_ci if (size != ((size + 7) & ~7)) { 2590987da915Sopenharmony_ci ntfs_log_error("make_room_for_index_entry_in_index_block() received " 2591987da915Sopenharmony_ci "non 8-byte aligned size.\n"); 2592987da915Sopenharmony_ci return -EINVAL; 2593987da915Sopenharmony_ci } 2594987da915Sopenharmony_ci if (!idx || !pos) 2595987da915Sopenharmony_ci return -EINVAL; 2596987da915Sopenharmony_ci if ((char*)pos < (char*)idx || (char*)pos + size < (char*)idx || 2597987da915Sopenharmony_ci (char*)pos > (char*)idx + sizeof(INDEX_BLOCK) - 2598987da915Sopenharmony_ci sizeof(INDEX_HEADER) + 2599987da915Sopenharmony_ci le32_to_cpu(idx->index.allocated_size) || 2600987da915Sopenharmony_ci (char*)pos + size > (char*)idx + sizeof(INDEX_BLOCK) - 2601987da915Sopenharmony_ci sizeof(INDEX_HEADER) + 2602987da915Sopenharmony_ci le32_to_cpu(idx->index.allocated_size)) 2603987da915Sopenharmony_ci return -EINVAL; 2604987da915Sopenharmony_ci /* The - sizeof(INDEX_ENTRY_HEADER) is for the index terminator. */ 2605987da915Sopenharmony_ci if ((char*)pos - (char*)&idx->index > 2606987da915Sopenharmony_ci (int)le32_to_cpu(idx->index.index_length) 2607987da915Sopenharmony_ci - (int)sizeof(INDEX_ENTRY_HEADER)) 2608987da915Sopenharmony_ci return -EINVAL; 2609987da915Sopenharmony_ci#endif 2610987da915Sopenharmony_ci biu = le32_to_cpu(idx->index.index_length); 2611987da915Sopenharmony_ci /* Do we have enough space? */ 2612987da915Sopenharmony_ci if (biu + size > le32_to_cpu(idx->index.allocated_size)) 2613987da915Sopenharmony_ci return -ENOSPC; 2614987da915Sopenharmony_ci /* Move everything after pos to pos + size. */ 2615987da915Sopenharmony_ci memmove((char*)pos + size, (char*)pos, biu - ((char*)pos - 2616987da915Sopenharmony_ci (char*)&idx->index)); 2617987da915Sopenharmony_ci /* Update index block. */ 2618987da915Sopenharmony_ci idx->index.index_length = cpu_to_le32(biu + size); 2619987da915Sopenharmony_ci return 0; 2620987da915Sopenharmony_ci} 2621987da915Sopenharmony_ci 2622987da915Sopenharmony_ci/** 2623987da915Sopenharmony_ci * ntfs_index_keys_compare 2624987da915Sopenharmony_ci * 2625987da915Sopenharmony_ci * not all types of COLLATION_RULES supported yet... 2626987da915Sopenharmony_ci * added as needed.. (remove this comment when all are added) 2627987da915Sopenharmony_ci */ 2628987da915Sopenharmony_cistatic int ntfs_index_keys_compare(u8 *key1, u8 *key2, int key1_length, 2629987da915Sopenharmony_ci int key2_length, COLLATION_RULES collation_rule) 2630987da915Sopenharmony_ci{ 2631987da915Sopenharmony_ci u32 u1, u2; 2632987da915Sopenharmony_ci int i; 2633987da915Sopenharmony_ci 2634987da915Sopenharmony_ci if (collation_rule == COLLATION_NTOFS_ULONG) { 2635987da915Sopenharmony_ci /* i.e. $SII or $QUOTA-$Q */ 2636987da915Sopenharmony_ci u1 = le32_to_cpup((const le32*)key1); 2637987da915Sopenharmony_ci u2 = le32_to_cpup((const le32*)key2); 2638987da915Sopenharmony_ci if (u1 < u2) 2639987da915Sopenharmony_ci return -1; 2640987da915Sopenharmony_ci if (u1 > u2) 2641987da915Sopenharmony_ci return 1; 2642987da915Sopenharmony_ci /* u1 == u2 */ 2643987da915Sopenharmony_ci return 0; 2644987da915Sopenharmony_ci } 2645987da915Sopenharmony_ci if (collation_rule == COLLATION_NTOFS_ULONGS) { 2646987da915Sopenharmony_ci /* i.e $OBJID-$O */ 2647987da915Sopenharmony_ci i = 0; 2648987da915Sopenharmony_ci while (i < min(key1_length, key2_length)) { 2649987da915Sopenharmony_ci u1 = le32_to_cpup((const le32*)(key1 + i)); 2650987da915Sopenharmony_ci u2 = le32_to_cpup((const le32*)(key2 + i)); 2651987da915Sopenharmony_ci if (u1 < u2) 2652987da915Sopenharmony_ci return -1; 2653987da915Sopenharmony_ci if (u1 > u2) 2654987da915Sopenharmony_ci return 1; 2655987da915Sopenharmony_ci /* u1 == u2 */ 2656987da915Sopenharmony_ci i += sizeof(u32); 2657987da915Sopenharmony_ci } 2658987da915Sopenharmony_ci if (key1_length < key2_length) 2659987da915Sopenharmony_ci return -1; 2660987da915Sopenharmony_ci if (key1_length > key2_length) 2661987da915Sopenharmony_ci return 1; 2662987da915Sopenharmony_ci return 0; 2663987da915Sopenharmony_ci } 2664987da915Sopenharmony_ci if (collation_rule == COLLATION_NTOFS_SECURITY_HASH) { 2665987da915Sopenharmony_ci /* i.e. $SDH */ 2666987da915Sopenharmony_ci u1 = le32_to_cpu(((SDH_INDEX_KEY*)key1)->hash); 2667987da915Sopenharmony_ci u2 = le32_to_cpu(((SDH_INDEX_KEY*)key2)->hash); 2668987da915Sopenharmony_ci if (u1 < u2) 2669987da915Sopenharmony_ci return -1; 2670987da915Sopenharmony_ci if (u1 > u2) 2671987da915Sopenharmony_ci return 1; 2672987da915Sopenharmony_ci /* u1 == u2 */ 2673987da915Sopenharmony_ci u1 = le32_to_cpu(((SDH_INDEX_KEY*)key1)->security_id); 2674987da915Sopenharmony_ci u2 = le32_to_cpu(((SDH_INDEX_KEY*)key2)->security_id); 2675987da915Sopenharmony_ci if (u1 < u2) 2676987da915Sopenharmony_ci return -1; 2677987da915Sopenharmony_ci if (u1 > u2) 2678987da915Sopenharmony_ci return 1; 2679987da915Sopenharmony_ci return 0; 2680987da915Sopenharmony_ci } 2681987da915Sopenharmony_ci if (collation_rule == COLLATION_NTOFS_SID) { 2682987da915Sopenharmony_ci /* i.e. $QUOTA-O */ 2683987da915Sopenharmony_ci i = memcmp(key1, key2, min(key1_length, key2_length)); 2684987da915Sopenharmony_ci if (!i) { 2685987da915Sopenharmony_ci if (key1_length < key2_length) 2686987da915Sopenharmony_ci return -1; 2687987da915Sopenharmony_ci if (key1_length > key2_length) 2688987da915Sopenharmony_ci return 1; 2689987da915Sopenharmony_ci } 2690987da915Sopenharmony_ci return i; 2691987da915Sopenharmony_ci } 2692987da915Sopenharmony_ci ntfs_log_critical("ntfs_index_keys_compare called without supported " 2693987da915Sopenharmony_ci "collation rule.\n"); 2694987da915Sopenharmony_ci return 0; /* Claim they're equal. What else can we do? */ 2695987da915Sopenharmony_ci} 2696987da915Sopenharmony_ci 2697987da915Sopenharmony_ci/** 2698987da915Sopenharmony_ci * insert_index_entry_in_res_dir_index 2699987da915Sopenharmony_ci * 2700987da915Sopenharmony_ci * i.e. insert an index_entry in some named index_root 2701987da915Sopenharmony_ci * simplified search method, works for mkntfs 2702987da915Sopenharmony_ci */ 2703987da915Sopenharmony_cistatic int insert_index_entry_in_res_dir_index(INDEX_ENTRY *idx, u32 idx_size, 2704987da915Sopenharmony_ci MFT_RECORD *m, ntfschar *name, u32 name_size, ATTR_TYPES type) 2705987da915Sopenharmony_ci{ 2706987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 2707987da915Sopenharmony_ci INDEX_HEADER *idx_header; 2708987da915Sopenharmony_ci INDEX_ENTRY *idx_entry, *idx_end; 2709987da915Sopenharmony_ci ATTR_RECORD *a; 2710987da915Sopenharmony_ci COLLATION_RULES collation_rule; 2711987da915Sopenharmony_ci int err, i; 2712987da915Sopenharmony_ci 2713987da915Sopenharmony_ci err = 0; 2714987da915Sopenharmony_ci /* does it fit ?*/ 2715987da915Sopenharmony_ci if (g_vol->mft_record_size > idx_size + le32_to_cpu(m->bytes_allocated)) 2716987da915Sopenharmony_ci return -ENOSPC; 2717987da915Sopenharmony_ci /* find the INDEX_ROOT attribute:*/ 2718987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(NULL, m); 2719987da915Sopenharmony_ci if (!ctx) { 2720987da915Sopenharmony_ci ntfs_log_error("Failed to allocate attribute search " 2721987da915Sopenharmony_ci "context.\n"); 2722987da915Sopenharmony_ci err = -ENOMEM; 2723987da915Sopenharmony_ci goto err_out; 2724987da915Sopenharmony_ci } 2725987da915Sopenharmony_ci if (mkntfs_attr_lookup(AT_INDEX_ROOT, name, name_size, 2726987da915Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx)) { 2727987da915Sopenharmony_ci err = -EEXIST; 2728987da915Sopenharmony_ci goto err_out; 2729987da915Sopenharmony_ci } 2730987da915Sopenharmony_ci /* found attribute */ 2731987da915Sopenharmony_ci a = (ATTR_RECORD*)ctx->attr; 2732987da915Sopenharmony_ci collation_rule = ((INDEX_ROOT*)((u8*)a + 2733987da915Sopenharmony_ci le16_to_cpu(a->value_offset)))->collation_rule; 2734987da915Sopenharmony_ci idx_header = (INDEX_HEADER*)((u8*)a + le16_to_cpu(a->value_offset) 2735987da915Sopenharmony_ci + 0x10); 2736987da915Sopenharmony_ci idx_entry = (INDEX_ENTRY*)((u8*)idx_header + 2737987da915Sopenharmony_ci le32_to_cpu(idx_header->entries_offset)); 2738987da915Sopenharmony_ci idx_end = (INDEX_ENTRY*)((u8*)idx_entry + 2739987da915Sopenharmony_ci le32_to_cpu(idx_header->index_length)); 2740987da915Sopenharmony_ci /* 2741987da915Sopenharmony_ci * Loop until we exceed valid memory (corruption case) or until we 2742987da915Sopenharmony_ci * reach the last entry. 2743987da915Sopenharmony_ci */ 2744987da915Sopenharmony_ci if (type == AT_FILE_NAME) { 2745987da915Sopenharmony_ci while (((u8*)idx_entry < (u8*)idx_end) && 2746987da915Sopenharmony_ci !(idx_entry->ie_flags & INDEX_ENTRY_END)) { 2747987da915Sopenharmony_ci /* 2748987da915Sopenharmony_ci i = ntfs_file_values_compare(&idx->key.file_name, 2749987da915Sopenharmony_ci &idx_entry->key.file_name, 1, 2750987da915Sopenharmony_ci IGNORE_CASE, g_vol->upcase, 2751987da915Sopenharmony_ci g_vol->upcase_len); 2752987da915Sopenharmony_ci */ 2753987da915Sopenharmony_ci i = ntfs_names_full_collate(idx->key.file_name.file_name, idx->key.file_name.file_name_length, 2754987da915Sopenharmony_ci idx_entry->key.file_name.file_name, idx_entry->key.file_name.file_name_length, 2755987da915Sopenharmony_ci IGNORE_CASE, g_vol->upcase, 2756987da915Sopenharmony_ci g_vol->upcase_len); 2757987da915Sopenharmony_ci /* 2758987da915Sopenharmony_ci * If @file_name collates before ie->key.file_name, 2759987da915Sopenharmony_ci * there is no matching index entry. 2760987da915Sopenharmony_ci */ 2761987da915Sopenharmony_ci if (i == -1) 2762987da915Sopenharmony_ci break; 2763987da915Sopenharmony_ci /* If file names are not equal, continue search. */ 2764987da915Sopenharmony_ci if (i) 2765987da915Sopenharmony_ci goto do_next; 2766987da915Sopenharmony_ci if (idx->key.file_name.file_name_type != 2767987da915Sopenharmony_ci FILE_NAME_POSIX || 2768987da915Sopenharmony_ci idx_entry->key.file_name.file_name_type 2769987da915Sopenharmony_ci != FILE_NAME_POSIX) 2770987da915Sopenharmony_ci return -EEXIST; 2771987da915Sopenharmony_ci /* 2772987da915Sopenharmony_ci i = ntfs_file_values_compare(&idx->key.file_name, 2773987da915Sopenharmony_ci &idx_entry->key.file_name, 1, 2774987da915Sopenharmony_ci CASE_SENSITIVE, g_vol->upcase, 2775987da915Sopenharmony_ci g_vol->upcase_len); 2776987da915Sopenharmony_ci */ 2777987da915Sopenharmony_ci i = ntfs_names_full_collate(idx->key.file_name.file_name, idx->key.file_name.file_name_length, 2778987da915Sopenharmony_ci idx_entry->key.file_name.file_name, idx_entry->key.file_name.file_name_length, 2779987da915Sopenharmony_ci CASE_SENSITIVE, g_vol->upcase, 2780987da915Sopenharmony_ci g_vol->upcase_len); 2781987da915Sopenharmony_ci if (!i) 2782987da915Sopenharmony_ci return -EEXIST; 2783987da915Sopenharmony_ci if (i == -1) 2784987da915Sopenharmony_ci break; 2785987da915Sopenharmony_cido_next: 2786987da915Sopenharmony_ci idx_entry = (INDEX_ENTRY*)((u8*)idx_entry + 2787987da915Sopenharmony_ci le16_to_cpu(idx_entry->length)); 2788987da915Sopenharmony_ci } 2789987da915Sopenharmony_ci } else if (type == AT_UNUSED) { /* case view */ 2790987da915Sopenharmony_ci while (((u8*)idx_entry < (u8*)idx_end) && 2791987da915Sopenharmony_ci !(idx_entry->ie_flags & INDEX_ENTRY_END)) { 2792987da915Sopenharmony_ci i = ntfs_index_keys_compare((u8*)idx + 0x10, 2793987da915Sopenharmony_ci (u8*)idx_entry + 0x10, 2794987da915Sopenharmony_ci le16_to_cpu(idx->key_length), 2795987da915Sopenharmony_ci le16_to_cpu(idx_entry->key_length), 2796987da915Sopenharmony_ci collation_rule); 2797987da915Sopenharmony_ci if (!i) 2798987da915Sopenharmony_ci return -EEXIST; 2799987da915Sopenharmony_ci if (i == -1) 2800987da915Sopenharmony_ci break; 2801987da915Sopenharmony_ci idx_entry = (INDEX_ENTRY*)((u8*)idx_entry + 2802987da915Sopenharmony_ci le16_to_cpu(idx_entry->length)); 2803987da915Sopenharmony_ci } 2804987da915Sopenharmony_ci } else 2805987da915Sopenharmony_ci return -EINVAL; 2806987da915Sopenharmony_ci memmove((u8*)idx_entry + idx_size, (u8*)idx_entry, 2807987da915Sopenharmony_ci le32_to_cpu(m->bytes_in_use) - 2808987da915Sopenharmony_ci ((u8*)idx_entry - (u8*)m)); 2809987da915Sopenharmony_ci memcpy((u8*)idx_entry, (u8*)idx, idx_size); 2810987da915Sopenharmony_ci /* Adjust various offsets, etc... */ 2811987da915Sopenharmony_ci m->bytes_in_use = cpu_to_le32(le32_to_cpu(m->bytes_in_use) + idx_size); 2812987da915Sopenharmony_ci a->length = cpu_to_le32(le32_to_cpu(a->length) + idx_size); 2813987da915Sopenharmony_ci a->value_length = cpu_to_le32(le32_to_cpu(a->value_length) + idx_size); 2814987da915Sopenharmony_ci idx_header->index_length = cpu_to_le32( 2815987da915Sopenharmony_ci le32_to_cpu(idx_header->index_length) + idx_size); 2816987da915Sopenharmony_ci idx_header->allocated_size = cpu_to_le32( 2817987da915Sopenharmony_ci le32_to_cpu(idx_header->allocated_size) + idx_size); 2818987da915Sopenharmony_cierr_out: 2819987da915Sopenharmony_ci if (ctx) 2820987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 2821987da915Sopenharmony_ci return err; 2822987da915Sopenharmony_ci} 2823987da915Sopenharmony_ci 2824987da915Sopenharmony_ci/** 2825987da915Sopenharmony_ci * initialize_secure 2826987da915Sopenharmony_ci * 2827987da915Sopenharmony_ci * initializes $Secure's $SDH and $SII indexes from $SDS datastream 2828987da915Sopenharmony_ci */ 2829987da915Sopenharmony_cistatic int initialize_secure(char *sds, u32 sds_size, MFT_RECORD *m) 2830987da915Sopenharmony_ci{ 2831987da915Sopenharmony_ci int err, sdh_size, sii_size; 2832987da915Sopenharmony_ci SECURITY_DESCRIPTOR_HEADER *sds_header; 2833987da915Sopenharmony_ci INDEX_ENTRY *idx_entry_sdh, *idx_entry_sii; 2834987da915Sopenharmony_ci SDH_INDEX_DATA *sdh_data; 2835987da915Sopenharmony_ci SII_INDEX_DATA *sii_data; 2836987da915Sopenharmony_ci 2837987da915Sopenharmony_ci sds_header = (SECURITY_DESCRIPTOR_HEADER*)sds; 2838987da915Sopenharmony_ci sdh_size = sizeof(INDEX_ENTRY_HEADER); 2839987da915Sopenharmony_ci sdh_size += sizeof(SDH_INDEX_KEY) + sizeof(SDH_INDEX_DATA); 2840987da915Sopenharmony_ci sii_size = sizeof(INDEX_ENTRY_HEADER); 2841987da915Sopenharmony_ci sii_size += sizeof(SII_INDEX_KEY) + sizeof(SII_INDEX_DATA); 2842987da915Sopenharmony_ci idx_entry_sdh = ntfs_calloc(sizeof(INDEX_ENTRY)); 2843987da915Sopenharmony_ci if (!idx_entry_sdh) 2844987da915Sopenharmony_ci return -errno; 2845987da915Sopenharmony_ci idx_entry_sii = ntfs_calloc(sizeof(INDEX_ENTRY)); 2846987da915Sopenharmony_ci if (!idx_entry_sii) { 2847987da915Sopenharmony_ci free(idx_entry_sdh); 2848987da915Sopenharmony_ci return -errno; 2849987da915Sopenharmony_ci } 2850987da915Sopenharmony_ci err = 0; 2851987da915Sopenharmony_ci 2852987da915Sopenharmony_ci while ((char*)sds_header < (char*)sds + sds_size) { 2853987da915Sopenharmony_ci if (!sds_header->length) 2854987da915Sopenharmony_ci break; 2855987da915Sopenharmony_ci /* SDH index entry */ 2856987da915Sopenharmony_ci idx_entry_sdh->data_offset = const_cpu_to_le16(0x18); 2857987da915Sopenharmony_ci idx_entry_sdh->data_length = const_cpu_to_le16(0x14); 2858987da915Sopenharmony_ci idx_entry_sdh->reservedV = const_cpu_to_le32(0x00); 2859987da915Sopenharmony_ci idx_entry_sdh->length = const_cpu_to_le16(0x30); 2860987da915Sopenharmony_ci idx_entry_sdh->key_length = const_cpu_to_le16(0x08); 2861987da915Sopenharmony_ci idx_entry_sdh->ie_flags = const_cpu_to_le16(0x00); 2862987da915Sopenharmony_ci idx_entry_sdh->reserved = const_cpu_to_le16(0x00); 2863987da915Sopenharmony_ci idx_entry_sdh->key.sdh.hash = sds_header->hash; 2864987da915Sopenharmony_ci idx_entry_sdh->key.sdh.security_id = sds_header->security_id; 2865987da915Sopenharmony_ci sdh_data = (SDH_INDEX_DATA*)((u8*)idx_entry_sdh + 2866987da915Sopenharmony_ci le16_to_cpu(idx_entry_sdh->data_offset)); 2867987da915Sopenharmony_ci sdh_data->hash = sds_header->hash; 2868987da915Sopenharmony_ci sdh_data->security_id = sds_header->security_id; 2869987da915Sopenharmony_ci sdh_data->offset = sds_header->offset; 2870987da915Sopenharmony_ci sdh_data->length = sds_header->length; 2871987da915Sopenharmony_ci sdh_data->reserved_II = const_cpu_to_le32(0x00490049); 2872987da915Sopenharmony_ci 2873987da915Sopenharmony_ci /* SII index entry */ 2874987da915Sopenharmony_ci idx_entry_sii->data_offset = const_cpu_to_le16(0x14); 2875987da915Sopenharmony_ci idx_entry_sii->data_length = const_cpu_to_le16(0x14); 2876987da915Sopenharmony_ci idx_entry_sii->reservedV = const_cpu_to_le32(0x00); 2877987da915Sopenharmony_ci idx_entry_sii->length = const_cpu_to_le16(0x28); 2878987da915Sopenharmony_ci idx_entry_sii->key_length = const_cpu_to_le16(0x04); 2879987da915Sopenharmony_ci idx_entry_sii->ie_flags = const_cpu_to_le16(0x00); 2880987da915Sopenharmony_ci idx_entry_sii->reserved = const_cpu_to_le16(0x00); 2881987da915Sopenharmony_ci idx_entry_sii->key.sii.security_id = sds_header->security_id; 2882987da915Sopenharmony_ci sii_data = (SII_INDEX_DATA*)((u8*)idx_entry_sii + 2883987da915Sopenharmony_ci le16_to_cpu(idx_entry_sii->data_offset)); 2884987da915Sopenharmony_ci sii_data->hash = sds_header->hash; 2885987da915Sopenharmony_ci sii_data->security_id = sds_header->security_id; 2886987da915Sopenharmony_ci sii_data->offset = sds_header->offset; 2887987da915Sopenharmony_ci sii_data->length = sds_header->length; 2888987da915Sopenharmony_ci if ((err = insert_index_entry_in_res_dir_index(idx_entry_sdh, 2889987da915Sopenharmony_ci sdh_size, m, NTFS_INDEX_SDH, 4, AT_UNUSED))) 2890987da915Sopenharmony_ci break; 2891987da915Sopenharmony_ci if ((err = insert_index_entry_in_res_dir_index(idx_entry_sii, 2892987da915Sopenharmony_ci sii_size, m, NTFS_INDEX_SII, 4, AT_UNUSED))) 2893987da915Sopenharmony_ci break; 2894987da915Sopenharmony_ci sds_header = (SECURITY_DESCRIPTOR_HEADER*)((u8*)sds_header + 2895987da915Sopenharmony_ci ((le32_to_cpu(sds_header->length) + 15) & ~15)); 2896987da915Sopenharmony_ci } 2897987da915Sopenharmony_ci free(idx_entry_sdh); 2898987da915Sopenharmony_ci free(idx_entry_sii); 2899987da915Sopenharmony_ci return err; 2900987da915Sopenharmony_ci} 2901987da915Sopenharmony_ci 2902987da915Sopenharmony_ci/** 2903987da915Sopenharmony_ci * initialize_quota 2904987da915Sopenharmony_ci * 2905987da915Sopenharmony_ci * initialize $Quota with the default quota index-entries. 2906987da915Sopenharmony_ci */ 2907987da915Sopenharmony_cistatic int initialize_quota(MFT_RECORD *m) 2908987da915Sopenharmony_ci{ 2909987da915Sopenharmony_ci int o_size, q1_size, q2_size, err, i; 2910987da915Sopenharmony_ci INDEX_ENTRY *idx_entry_o, *idx_entry_q1, *idx_entry_q2; 2911987da915Sopenharmony_ci QUOTA_O_INDEX_DATA *idx_entry_o_data; 2912987da915Sopenharmony_ci QUOTA_CONTROL_ENTRY *idx_entry_q1_data, *idx_entry_q2_data; 2913987da915Sopenharmony_ci 2914987da915Sopenharmony_ci err = 0; 2915987da915Sopenharmony_ci /* q index entry num 1 */ 2916987da915Sopenharmony_ci q1_size = 0x48; 2917987da915Sopenharmony_ci idx_entry_q1 = ntfs_calloc(q1_size); 2918987da915Sopenharmony_ci if (!idx_entry_q1) 2919987da915Sopenharmony_ci return errno; 2920987da915Sopenharmony_ci idx_entry_q1->data_offset = const_cpu_to_le16(0x14); 2921987da915Sopenharmony_ci idx_entry_q1->data_length = const_cpu_to_le16(0x30); 2922987da915Sopenharmony_ci idx_entry_q1->reservedV = const_cpu_to_le32(0x00); 2923987da915Sopenharmony_ci idx_entry_q1->length = const_cpu_to_le16(0x48); 2924987da915Sopenharmony_ci idx_entry_q1->key_length = const_cpu_to_le16(0x04); 2925987da915Sopenharmony_ci idx_entry_q1->ie_flags = const_cpu_to_le16(0x00); 2926987da915Sopenharmony_ci idx_entry_q1->reserved = const_cpu_to_le16(0x00); 2927987da915Sopenharmony_ci idx_entry_q1->key.owner_id = const_cpu_to_le32(0x01); 2928987da915Sopenharmony_ci idx_entry_q1_data = (QUOTA_CONTROL_ENTRY*)((char*)idx_entry_q1 2929987da915Sopenharmony_ci + le16_to_cpu(idx_entry_q1->data_offset)); 2930987da915Sopenharmony_ci idx_entry_q1_data->version = const_cpu_to_le32(0x02); 2931987da915Sopenharmony_ci idx_entry_q1_data->flags = QUOTA_FLAG_DEFAULT_LIMITS; 2932987da915Sopenharmony_ci idx_entry_q1_data->bytes_used = const_cpu_to_le64(0x00); 2933987da915Sopenharmony_ci idx_entry_q1_data->change_time = mkntfs_time(); 2934987da915Sopenharmony_ci idx_entry_q1_data->threshold = const_cpu_to_sle64(-1); 2935987da915Sopenharmony_ci idx_entry_q1_data->limit = const_cpu_to_sle64(-1); 2936987da915Sopenharmony_ci idx_entry_q1_data->exceeded_time = const_cpu_to_sle64(0); 2937987da915Sopenharmony_ci err = insert_index_entry_in_res_dir_index(idx_entry_q1, q1_size, m, 2938987da915Sopenharmony_ci NTFS_INDEX_Q, 2, AT_UNUSED); 2939987da915Sopenharmony_ci free(idx_entry_q1); 2940987da915Sopenharmony_ci if (err) 2941987da915Sopenharmony_ci return err; 2942987da915Sopenharmony_ci /* q index entry num 2 */ 2943987da915Sopenharmony_ci q2_size = 0x58; 2944987da915Sopenharmony_ci idx_entry_q2 = ntfs_calloc(q2_size); 2945987da915Sopenharmony_ci if (!idx_entry_q2) 2946987da915Sopenharmony_ci return errno; 2947987da915Sopenharmony_ci idx_entry_q2->data_offset = const_cpu_to_le16(0x14); 2948987da915Sopenharmony_ci idx_entry_q2->data_length = const_cpu_to_le16(0x40); 2949987da915Sopenharmony_ci idx_entry_q2->reservedV = const_cpu_to_le32(0x00); 2950987da915Sopenharmony_ci idx_entry_q2->length = const_cpu_to_le16(0x58); 2951987da915Sopenharmony_ci idx_entry_q2->key_length = const_cpu_to_le16(0x04); 2952987da915Sopenharmony_ci idx_entry_q2->ie_flags = const_cpu_to_le16(0x00); 2953987da915Sopenharmony_ci idx_entry_q2->reserved = const_cpu_to_le16(0x00); 2954987da915Sopenharmony_ci idx_entry_q2->key.owner_id = QUOTA_FIRST_USER_ID; 2955987da915Sopenharmony_ci idx_entry_q2_data = (QUOTA_CONTROL_ENTRY*)((char*)idx_entry_q2 2956987da915Sopenharmony_ci + le16_to_cpu(idx_entry_q2->data_offset)); 2957987da915Sopenharmony_ci idx_entry_q2_data->version = const_cpu_to_le32(0x02); 2958987da915Sopenharmony_ci idx_entry_q2_data->flags = QUOTA_FLAG_DEFAULT_LIMITS; 2959987da915Sopenharmony_ci idx_entry_q2_data->bytes_used = const_cpu_to_le64(0x00); 2960987da915Sopenharmony_ci idx_entry_q2_data->change_time = mkntfs_time(); 2961987da915Sopenharmony_ci idx_entry_q2_data->threshold = const_cpu_to_sle64(-1); 2962987da915Sopenharmony_ci idx_entry_q2_data->limit = const_cpu_to_sle64(-1); 2963987da915Sopenharmony_ci idx_entry_q2_data->exceeded_time = const_cpu_to_sle64(0); 2964987da915Sopenharmony_ci idx_entry_q2_data->sid.revision = 1; 2965987da915Sopenharmony_ci idx_entry_q2_data->sid.sub_authority_count = 2; 2966987da915Sopenharmony_ci for (i = 0; i < 5; i++) 2967987da915Sopenharmony_ci idx_entry_q2_data->sid.identifier_authority.value[i] = 0; 2968987da915Sopenharmony_ci idx_entry_q2_data->sid.identifier_authority.value[5] = 0x05; 2969987da915Sopenharmony_ci idx_entry_q2_data->sid.sub_authority[0] = 2970987da915Sopenharmony_ci const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); 2971987da915Sopenharmony_ci idx_entry_q2_data->sid.sub_authority[1] = 2972987da915Sopenharmony_ci const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); 2973987da915Sopenharmony_ci err = insert_index_entry_in_res_dir_index(idx_entry_q2, q2_size, m, 2974987da915Sopenharmony_ci NTFS_INDEX_Q, 2, AT_UNUSED); 2975987da915Sopenharmony_ci free(idx_entry_q2); 2976987da915Sopenharmony_ci if (err) 2977987da915Sopenharmony_ci return err; 2978987da915Sopenharmony_ci o_size = 0x28; 2979987da915Sopenharmony_ci idx_entry_o = ntfs_calloc(o_size); 2980987da915Sopenharmony_ci if (!idx_entry_o) 2981987da915Sopenharmony_ci return errno; 2982987da915Sopenharmony_ci idx_entry_o->data_offset = const_cpu_to_le16(0x20); 2983987da915Sopenharmony_ci idx_entry_o->data_length = const_cpu_to_le16(0x04); 2984987da915Sopenharmony_ci idx_entry_o->reservedV = const_cpu_to_le32(0x00); 2985987da915Sopenharmony_ci idx_entry_o->length = const_cpu_to_le16(0x28); 2986987da915Sopenharmony_ci idx_entry_o->key_length = const_cpu_to_le16(0x10); 2987987da915Sopenharmony_ci idx_entry_o->ie_flags = const_cpu_to_le16(0x00); 2988987da915Sopenharmony_ci idx_entry_o->reserved = const_cpu_to_le16(0x00); 2989987da915Sopenharmony_ci idx_entry_o->key.sid.revision = 0x01; 2990987da915Sopenharmony_ci idx_entry_o->key.sid.sub_authority_count = 0x02; 2991987da915Sopenharmony_ci for (i = 0; i < 5; i++) 2992987da915Sopenharmony_ci idx_entry_o->key.sid.identifier_authority.value[i] = 0; 2993987da915Sopenharmony_ci idx_entry_o->key.sid.identifier_authority.value[5] = 0x05; 2994987da915Sopenharmony_ci idx_entry_o->key.sid.sub_authority[0] = 2995987da915Sopenharmony_ci const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); 2996987da915Sopenharmony_ci idx_entry_o->key.sid.sub_authority[1] = 2997987da915Sopenharmony_ci const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); 2998987da915Sopenharmony_ci idx_entry_o_data = (QUOTA_O_INDEX_DATA*)((char*)idx_entry_o 2999987da915Sopenharmony_ci + le16_to_cpu(idx_entry_o->data_offset)); 3000987da915Sopenharmony_ci idx_entry_o_data->owner_id = QUOTA_FIRST_USER_ID; 3001987da915Sopenharmony_ci /* 20 00 00 00 padding after here on ntfs 3.1. 3.0 is unchecked. */ 3002987da915Sopenharmony_ci idx_entry_o_data->unknown = const_cpu_to_le32(32); 3003987da915Sopenharmony_ci err = insert_index_entry_in_res_dir_index(idx_entry_o, o_size, m, 3004987da915Sopenharmony_ci NTFS_INDEX_O, 2, AT_UNUSED); 3005987da915Sopenharmony_ci free(idx_entry_o); 3006987da915Sopenharmony_ci 3007987da915Sopenharmony_ci return err; 3008987da915Sopenharmony_ci} 3009987da915Sopenharmony_ci 3010987da915Sopenharmony_ci/** 3011987da915Sopenharmony_ci * insert_file_link_in_dir_index 3012987da915Sopenharmony_ci * 3013987da915Sopenharmony_ci * Insert the fully completed FILE_NAME_ATTR @file_name which is inside 3014987da915Sopenharmony_ci * the file with mft reference @file_ref into the index (allocation) block 3015987da915Sopenharmony_ci * @idx (which belongs to @file_ref's parent directory). 3016987da915Sopenharmony_ci * 3017987da915Sopenharmony_ci * Return 0 on success or -errno on error. 3018987da915Sopenharmony_ci */ 3019987da915Sopenharmony_cistatic int insert_file_link_in_dir_index(INDEX_BLOCK *idx, leMFT_REF file_ref, 3020987da915Sopenharmony_ci FILE_NAME_ATTR *file_name, u32 file_name_size) 3021987da915Sopenharmony_ci{ 3022987da915Sopenharmony_ci int err, i; 3023987da915Sopenharmony_ci INDEX_ENTRY *ie; 3024987da915Sopenharmony_ci char *index_end; 3025987da915Sopenharmony_ci 3026987da915Sopenharmony_ci /* 3027987da915Sopenharmony_ci * Lookup dir entry @file_name in dir @idx to determine correct 3028987da915Sopenharmony_ci * insertion location. FIXME: Using a very oversimplified lookup 3029987da915Sopenharmony_ci * method which is sufficient for mkntfs but no good whatsoever in 3030987da915Sopenharmony_ci * real world scenario. (AIA) 3031987da915Sopenharmony_ci */ 3032987da915Sopenharmony_ci 3033987da915Sopenharmony_ci index_end = (char*)&idx->index + le32_to_cpu(idx->index.index_length); 3034987da915Sopenharmony_ci ie = (INDEX_ENTRY*)((char*)&idx->index + 3035987da915Sopenharmony_ci le32_to_cpu(idx->index.entries_offset)); 3036987da915Sopenharmony_ci /* 3037987da915Sopenharmony_ci * Loop until we exceed valid memory (corruption case) or until we 3038987da915Sopenharmony_ci * reach the last entry. 3039987da915Sopenharmony_ci */ 3040987da915Sopenharmony_ci while ((char*)ie < index_end && !(ie->ie_flags & INDEX_ENTRY_END)) { 3041987da915Sopenharmony_ci#if 0 3042987da915Sopenharmony_ci#ifdef DEBUG 3043987da915Sopenharmony_ci ntfs_log_debug("file_name_attr1->file_name_length = %i\n", 3044987da915Sopenharmony_ci file_name->file_name_length); 3045987da915Sopenharmony_ci if (file_name->file_name_length) { 3046987da915Sopenharmony_ci char *__buf = NULL; 3047987da915Sopenharmony_ci i = ntfs_ucstombs((ntfschar*)&file_name->file_name, 3048987da915Sopenharmony_ci file_name->file_name_length, &__buf, 0); 3049987da915Sopenharmony_ci if (i < 0) 3050987da915Sopenharmony_ci ntfs_log_debug("Name contains non-displayable " 3051987da915Sopenharmony_ci "Unicode characters.\n"); 3052987da915Sopenharmony_ci ntfs_log_debug("file_name_attr1->file_name = %s\n", 3053987da915Sopenharmony_ci __buf); 3054987da915Sopenharmony_ci free(__buf); 3055987da915Sopenharmony_ci } 3056987da915Sopenharmony_ci ntfs_log_debug("file_name_attr2->file_name_length = %i\n", 3057987da915Sopenharmony_ci ie->key.file_name.file_name_length); 3058987da915Sopenharmony_ci if (ie->key.file_name.file_name_length) { 3059987da915Sopenharmony_ci char *__buf = NULL; 3060987da915Sopenharmony_ci i = ntfs_ucstombs(ie->key.file_name.file_name, 3061987da915Sopenharmony_ci ie->key.file_name.file_name_length + 1, &__buf, 3062987da915Sopenharmony_ci 0); 3063987da915Sopenharmony_ci if (i < 0) 3064987da915Sopenharmony_ci ntfs_log_debug("Name contains non-displayable " 3065987da915Sopenharmony_ci "Unicode characters.\n"); 3066987da915Sopenharmony_ci ntfs_log_debug("file_name_attr2->file_name = %s\n", 3067987da915Sopenharmony_ci __buf); 3068987da915Sopenharmony_ci free(__buf); 3069987da915Sopenharmony_ci } 3070987da915Sopenharmony_ci#endif 3071987da915Sopenharmony_ci#endif 3072987da915Sopenharmony_ci /* 3073987da915Sopenharmony_ci i = ntfs_file_values_compare(file_name, 3074987da915Sopenharmony_ci (FILE_NAME_ATTR*)&ie->key.file_name, 1, 3075987da915Sopenharmony_ci IGNORE_CASE, g_vol->upcase, g_vol->upcase_len); 3076987da915Sopenharmony_ci */ 3077987da915Sopenharmony_ci i = ntfs_names_full_collate(file_name->file_name, file_name->file_name_length, 3078987da915Sopenharmony_ci ((FILE_NAME_ATTR*)&ie->key.file_name)->file_name, ((FILE_NAME_ATTR*)&ie->key.file_name)->file_name_length, 3079987da915Sopenharmony_ci IGNORE_CASE, g_vol->upcase, g_vol->upcase_len); 3080987da915Sopenharmony_ci /* 3081987da915Sopenharmony_ci * If @file_name collates before ie->key.file_name, there is no 3082987da915Sopenharmony_ci * matching index entry. 3083987da915Sopenharmony_ci */ 3084987da915Sopenharmony_ci if (i == -1) 3085987da915Sopenharmony_ci break; 3086987da915Sopenharmony_ci /* If file names are not equal, continue search. */ 3087987da915Sopenharmony_ci if (i) 3088987da915Sopenharmony_ci goto do_next; 3089987da915Sopenharmony_ci /* File names are equal when compared ignoring case. */ 3090987da915Sopenharmony_ci /* 3091987da915Sopenharmony_ci * If BOTH file names are in the POSIX namespace, do a case 3092987da915Sopenharmony_ci * sensitive comparison as well. Otherwise the names match so 3093987da915Sopenharmony_ci * we return -EEXIST. FIXME: There are problems with this in a 3094987da915Sopenharmony_ci * real world scenario, when one is POSIX and one isn't, but 3095987da915Sopenharmony_ci * fine for mkntfs where we don't use POSIX namespace at all 3096987da915Sopenharmony_ci * and hence this following code is luxury. (AIA) 3097987da915Sopenharmony_ci */ 3098987da915Sopenharmony_ci if (file_name->file_name_type != FILE_NAME_POSIX || 3099987da915Sopenharmony_ci ie->key.file_name.file_name_type != FILE_NAME_POSIX) 3100987da915Sopenharmony_ci return -EEXIST; 3101987da915Sopenharmony_ci /* 3102987da915Sopenharmony_ci i = ntfs_file_values_compare(file_name, 3103987da915Sopenharmony_ci (FILE_NAME_ATTR*)&ie->key.file_name, 1, 3104987da915Sopenharmony_ci CASE_SENSITIVE, g_vol->upcase, 3105987da915Sopenharmony_ci g_vol->upcase_len); 3106987da915Sopenharmony_ci */ 3107987da915Sopenharmony_ci i = ntfs_names_full_collate(file_name->file_name, file_name->file_name_length, 3108987da915Sopenharmony_ci ((FILE_NAME_ATTR*)&ie->key.file_name)->file_name, ((FILE_NAME_ATTR*)&ie->key.file_name)->file_name_length, 3109987da915Sopenharmony_ci CASE_SENSITIVE, g_vol->upcase, g_vol->upcase_len); 3110987da915Sopenharmony_ci if (i == -1) 3111987da915Sopenharmony_ci break; 3112987da915Sopenharmony_ci /* Complete match. Bugger. Can't insert. */ 3113987da915Sopenharmony_ci if (!i) 3114987da915Sopenharmony_ci return -EEXIST; 3115987da915Sopenharmony_cido_next: 3116987da915Sopenharmony_ci#ifdef DEBUG 3117987da915Sopenharmony_ci /* Next entry. */ 3118987da915Sopenharmony_ci if (!ie->length) { 3119987da915Sopenharmony_ci ntfs_log_debug("BUG: ie->length is zero, breaking out " 3120987da915Sopenharmony_ci "of loop.\n"); 3121987da915Sopenharmony_ci break; 3122987da915Sopenharmony_ci } 3123987da915Sopenharmony_ci#endif 3124987da915Sopenharmony_ci ie = (INDEX_ENTRY*)((char*)ie + le16_to_cpu(ie->length)); 3125987da915Sopenharmony_ci }; 3126987da915Sopenharmony_ci i = (sizeof(INDEX_ENTRY_HEADER) + file_name_size + 7) & ~7; 3127987da915Sopenharmony_ci err = make_room_for_index_entry_in_index_block(idx, ie, i); 3128987da915Sopenharmony_ci if (err) { 3129987da915Sopenharmony_ci ntfs_log_error("make_room_for_index_entry_in_index_block " 3130987da915Sopenharmony_ci "failed: %s\n", strerror(-err)); 3131987da915Sopenharmony_ci return err; 3132987da915Sopenharmony_ci } 3133987da915Sopenharmony_ci /* Create entry in place and copy file name attribute value. */ 3134987da915Sopenharmony_ci ie->indexed_file = file_ref; 3135987da915Sopenharmony_ci ie->length = cpu_to_le16(i); 3136987da915Sopenharmony_ci ie->key_length = cpu_to_le16(file_name_size); 3137987da915Sopenharmony_ci ie->ie_flags = const_cpu_to_le16(0); 3138987da915Sopenharmony_ci ie->reserved = const_cpu_to_le16(0); 3139987da915Sopenharmony_ci memcpy((char*)&ie->key.file_name, (char*)file_name, file_name_size); 3140987da915Sopenharmony_ci return 0; 3141987da915Sopenharmony_ci} 3142987da915Sopenharmony_ci 3143987da915Sopenharmony_ci/** 3144987da915Sopenharmony_ci * create_hardlink_res 3145987da915Sopenharmony_ci * 3146987da915Sopenharmony_ci * Create a file_name_attribute in the mft record @m_file which points to the 3147987da915Sopenharmony_ci * parent directory with mft reference @ref_parent. 3148987da915Sopenharmony_ci * 3149987da915Sopenharmony_ci * Then, insert an index entry with this file_name_attribute in the index 3150987da915Sopenharmony_ci * root @idx of the index_root attribute of the parent directory. 3151987da915Sopenharmony_ci * 3152987da915Sopenharmony_ci * @ref_file is the mft reference of @m_file. 3153987da915Sopenharmony_ci * 3154987da915Sopenharmony_ci * Return 0 on success or -errno on error. 3155987da915Sopenharmony_ci */ 3156987da915Sopenharmony_cistatic int create_hardlink_res(MFT_RECORD *m_parent, const leMFT_REF ref_parent, 3157987da915Sopenharmony_ci MFT_RECORD *m_file, const leMFT_REF ref_file, 3158987da915Sopenharmony_ci const s64 allocated_size, const s64 data_size, 3159987da915Sopenharmony_ci const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, 3160987da915Sopenharmony_ci const u32 reparse_point_tag, const char *file_name, 3161987da915Sopenharmony_ci const FILE_NAME_TYPE_FLAGS file_name_type) 3162987da915Sopenharmony_ci{ 3163987da915Sopenharmony_ci FILE_NAME_ATTR *fn; 3164987da915Sopenharmony_ci int i, fn_size, idx_size; 3165987da915Sopenharmony_ci INDEX_ENTRY *idx_entry_new; 3166987da915Sopenharmony_ci ntfschar *uname; 3167987da915Sopenharmony_ci 3168987da915Sopenharmony_ci /* Create the file_name attribute. */ 3169987da915Sopenharmony_ci i = (strlen(file_name) + 1) * sizeof(ntfschar); 3170987da915Sopenharmony_ci fn_size = sizeof(FILE_NAME_ATTR) + i; 3171987da915Sopenharmony_ci fn = ntfs_malloc(fn_size); 3172987da915Sopenharmony_ci if (!fn) 3173987da915Sopenharmony_ci return -errno; 3174987da915Sopenharmony_ci fn->parent_directory = ref_parent; 3175987da915Sopenharmony_ci fn->creation_time = stdinfo_time(m_file); 3176987da915Sopenharmony_ci fn->last_data_change_time = fn->creation_time; 3177987da915Sopenharmony_ci fn->last_mft_change_time = fn->creation_time; 3178987da915Sopenharmony_ci fn->last_access_time = fn->creation_time; 3179987da915Sopenharmony_ci fn->allocated_size = cpu_to_sle64(allocated_size); 3180987da915Sopenharmony_ci fn->data_size = cpu_to_sle64(data_size); 3181987da915Sopenharmony_ci fn->file_attributes = flags; 3182987da915Sopenharmony_ci /* These are in a union so can't have both. */ 3183987da915Sopenharmony_ci if (packed_ea_size && reparse_point_tag) { 3184987da915Sopenharmony_ci free(fn); 3185987da915Sopenharmony_ci return -EINVAL; 3186987da915Sopenharmony_ci } 3187987da915Sopenharmony_ci if (packed_ea_size) { 3188987da915Sopenharmony_ci free(fn); 3189987da915Sopenharmony_ci return -EINVAL; 3190987da915Sopenharmony_ci } 3191987da915Sopenharmony_ci if (packed_ea_size) { 3192987da915Sopenharmony_ci fn->packed_ea_size = cpu_to_le16(packed_ea_size); 3193987da915Sopenharmony_ci fn->reserved = const_cpu_to_le16(0); 3194987da915Sopenharmony_ci } else { 3195987da915Sopenharmony_ci fn->reparse_point_tag = cpu_to_le32(reparse_point_tag); 3196987da915Sopenharmony_ci } 3197987da915Sopenharmony_ci fn->file_name_type = file_name_type; 3198987da915Sopenharmony_ci uname = fn->file_name; 3199987da915Sopenharmony_ci i = ntfs_mbstoucs_libntfscompat(file_name, &uname, i); 3200987da915Sopenharmony_ci if (i < 1) { 3201987da915Sopenharmony_ci free(fn); 3202987da915Sopenharmony_ci return -EINVAL; 3203987da915Sopenharmony_ci } 3204987da915Sopenharmony_ci if (i > 0xff) { 3205987da915Sopenharmony_ci free(fn); 3206987da915Sopenharmony_ci return -ENAMETOOLONG; 3207987da915Sopenharmony_ci } 3208987da915Sopenharmony_ci /* No terminating null in file names. */ 3209987da915Sopenharmony_ci fn->file_name_length = i; 3210987da915Sopenharmony_ci fn_size = sizeof(FILE_NAME_ATTR) + i * sizeof(ntfschar); 3211987da915Sopenharmony_ci /* Increment the link count of @m_file. */ 3212987da915Sopenharmony_ci i = le16_to_cpu(m_file->link_count); 3213987da915Sopenharmony_ci if (i == 0xffff) { 3214987da915Sopenharmony_ci ntfs_log_error("Too many hardlinks present already.\n"); 3215987da915Sopenharmony_ci free(fn); 3216987da915Sopenharmony_ci return -EINVAL; 3217987da915Sopenharmony_ci } 3218987da915Sopenharmony_ci m_file->link_count = cpu_to_le16(i + 1); 3219987da915Sopenharmony_ci /* Add the file_name to @m_file. */ 3220987da915Sopenharmony_ci i = insert_resident_attr_in_mft_record(m_file, AT_FILE_NAME, NULL, 0, 3221987da915Sopenharmony_ci CASE_SENSITIVE, const_cpu_to_le16(0), 3222987da915Sopenharmony_ci RESIDENT_ATTR_IS_INDEXED, (u8*)fn, fn_size); 3223987da915Sopenharmony_ci if (i < 0) { 3224987da915Sopenharmony_ci ntfs_log_error("create_hardlink failed adding file name " 3225987da915Sopenharmony_ci "attribute: %s\n", strerror(-i)); 3226987da915Sopenharmony_ci free(fn); 3227987da915Sopenharmony_ci /* Undo link count increment. */ 3228987da915Sopenharmony_ci m_file->link_count = cpu_to_le16( 3229987da915Sopenharmony_ci le16_to_cpu(m_file->link_count) - 1); 3230987da915Sopenharmony_ci return i; 3231987da915Sopenharmony_ci } 3232987da915Sopenharmony_ci /* Insert the index entry for file_name in @idx. */ 3233987da915Sopenharmony_ci idx_size = (fn_size + 7) & ~7; 3234987da915Sopenharmony_ci idx_entry_new = ntfs_calloc(idx_size + 0x10); 3235987da915Sopenharmony_ci if (!idx_entry_new) 3236987da915Sopenharmony_ci return -errno; 3237987da915Sopenharmony_ci idx_entry_new->indexed_file = ref_file; 3238987da915Sopenharmony_ci idx_entry_new->length = cpu_to_le16(idx_size + 0x10); 3239987da915Sopenharmony_ci idx_entry_new->key_length = cpu_to_le16(fn_size); 3240987da915Sopenharmony_ci memcpy((u8*)idx_entry_new + 0x10, (u8*)fn, fn_size); 3241987da915Sopenharmony_ci i = insert_index_entry_in_res_dir_index(idx_entry_new, idx_size + 0x10, 3242987da915Sopenharmony_ci m_parent, NTFS_INDEX_I30, 4, AT_FILE_NAME); 3243987da915Sopenharmony_ci if (i < 0) { 3244987da915Sopenharmony_ci ntfs_log_error("create_hardlink failed inserting index entry: " 3245987da915Sopenharmony_ci "%s\n", strerror(-i)); 3246987da915Sopenharmony_ci /* FIXME: Remove the file name attribute from @m_file. */ 3247987da915Sopenharmony_ci free(idx_entry_new); 3248987da915Sopenharmony_ci free(fn); 3249987da915Sopenharmony_ci /* Undo link count increment. */ 3250987da915Sopenharmony_ci m_file->link_count = cpu_to_le16( 3251987da915Sopenharmony_ci le16_to_cpu(m_file->link_count) - 1); 3252987da915Sopenharmony_ci return i; 3253987da915Sopenharmony_ci } 3254987da915Sopenharmony_ci free(idx_entry_new); 3255987da915Sopenharmony_ci free(fn); 3256987da915Sopenharmony_ci return 0; 3257987da915Sopenharmony_ci} 3258987da915Sopenharmony_ci 3259987da915Sopenharmony_ci/** 3260987da915Sopenharmony_ci * create_hardlink 3261987da915Sopenharmony_ci * 3262987da915Sopenharmony_ci * Create a file_name_attribute in the mft record @m_file which points to the 3263987da915Sopenharmony_ci * parent directory with mft reference @ref_parent. 3264987da915Sopenharmony_ci * 3265987da915Sopenharmony_ci * Then, insert an index entry with this file_name_attribute in the index 3266987da915Sopenharmony_ci * block @idx of the index allocation attribute of the parent directory. 3267987da915Sopenharmony_ci * 3268987da915Sopenharmony_ci * @ref_file is the mft reference of @m_file. 3269987da915Sopenharmony_ci * 3270987da915Sopenharmony_ci * Return 0 on success or -errno on error. 3271987da915Sopenharmony_ci */ 3272987da915Sopenharmony_cistatic int create_hardlink(INDEX_BLOCK *idx, const leMFT_REF ref_parent, 3273987da915Sopenharmony_ci MFT_RECORD *m_file, const leMFT_REF ref_file, 3274987da915Sopenharmony_ci const s64 allocated_size, const s64 data_size, 3275987da915Sopenharmony_ci const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, 3276987da915Sopenharmony_ci const u32 reparse_point_tag, const char *file_name, 3277987da915Sopenharmony_ci const FILE_NAME_TYPE_FLAGS file_name_type) 3278987da915Sopenharmony_ci{ 3279987da915Sopenharmony_ci FILE_NAME_ATTR *fn; 3280987da915Sopenharmony_ci int i, fn_size; 3281987da915Sopenharmony_ci ntfschar *uname; 3282987da915Sopenharmony_ci 3283987da915Sopenharmony_ci /* Create the file_name attribute. */ 3284987da915Sopenharmony_ci i = (strlen(file_name) + 1) * sizeof(ntfschar); 3285987da915Sopenharmony_ci fn_size = sizeof(FILE_NAME_ATTR) + i; 3286987da915Sopenharmony_ci fn = ntfs_malloc(fn_size); 3287987da915Sopenharmony_ci if (!fn) 3288987da915Sopenharmony_ci return -errno; 3289987da915Sopenharmony_ci fn->parent_directory = ref_parent; 3290987da915Sopenharmony_ci fn->creation_time = stdinfo_time(m_file); 3291987da915Sopenharmony_ci fn->last_data_change_time = fn->creation_time; 3292987da915Sopenharmony_ci fn->last_mft_change_time = fn->creation_time; 3293987da915Sopenharmony_ci fn->last_access_time = fn->creation_time; 3294987da915Sopenharmony_ci /* allocated size depends on unnamed data being resident */ 3295987da915Sopenharmony_ci if (allocated_size && non_resident_unnamed_data(m_file)) 3296987da915Sopenharmony_ci fn->allocated_size = cpu_to_sle64(allocated_size); 3297987da915Sopenharmony_ci else 3298987da915Sopenharmony_ci fn->allocated_size = cpu_to_sle64((data_size + 7) & -8); 3299987da915Sopenharmony_ci fn->data_size = cpu_to_sle64(data_size); 3300987da915Sopenharmony_ci fn->file_attributes = flags; 3301987da915Sopenharmony_ci /* These are in a union so can't have both. */ 3302987da915Sopenharmony_ci if (packed_ea_size && reparse_point_tag) { 3303987da915Sopenharmony_ci free(fn); 3304987da915Sopenharmony_ci return -EINVAL; 3305987da915Sopenharmony_ci } 3306987da915Sopenharmony_ci if (packed_ea_size) { 3307987da915Sopenharmony_ci fn->packed_ea_size = cpu_to_le16(packed_ea_size); 3308987da915Sopenharmony_ci fn->reserved = const_cpu_to_le16(0); 3309987da915Sopenharmony_ci } else { 3310987da915Sopenharmony_ci fn->reparse_point_tag = cpu_to_le32(reparse_point_tag); 3311987da915Sopenharmony_ci } 3312987da915Sopenharmony_ci fn->file_name_type = file_name_type; 3313987da915Sopenharmony_ci uname = fn->file_name; 3314987da915Sopenharmony_ci i = ntfs_mbstoucs_libntfscompat(file_name, &uname, i); 3315987da915Sopenharmony_ci if (i < 1) { 3316987da915Sopenharmony_ci free(fn); 3317987da915Sopenharmony_ci return -EINVAL; 3318987da915Sopenharmony_ci } 3319987da915Sopenharmony_ci if (i > 0xff) { 3320987da915Sopenharmony_ci free(fn); 3321987da915Sopenharmony_ci return -ENAMETOOLONG; 3322987da915Sopenharmony_ci } 3323987da915Sopenharmony_ci /* No terminating null in file names. */ 3324987da915Sopenharmony_ci fn->file_name_length = i; 3325987da915Sopenharmony_ci fn_size = sizeof(FILE_NAME_ATTR) + i * sizeof(ntfschar); 3326987da915Sopenharmony_ci /* Increment the link count of @m_file. */ 3327987da915Sopenharmony_ci i = le16_to_cpu(m_file->link_count); 3328987da915Sopenharmony_ci if (i == 0xffff) { 3329987da915Sopenharmony_ci ntfs_log_error("Too many hardlinks present already.\n"); 3330987da915Sopenharmony_ci free(fn); 3331987da915Sopenharmony_ci return -EINVAL; 3332987da915Sopenharmony_ci } 3333987da915Sopenharmony_ci m_file->link_count = cpu_to_le16(i + 1); 3334987da915Sopenharmony_ci /* Add the file_name to @m_file. */ 3335987da915Sopenharmony_ci i = insert_resident_attr_in_mft_record(m_file, AT_FILE_NAME, NULL, 0, 3336987da915Sopenharmony_ci CASE_SENSITIVE, const_cpu_to_le16(0), 3337987da915Sopenharmony_ci RESIDENT_ATTR_IS_INDEXED, (u8*)fn, fn_size); 3338987da915Sopenharmony_ci if (i < 0) { 3339987da915Sopenharmony_ci ntfs_log_error("create_hardlink failed adding file name attribute: " 3340987da915Sopenharmony_ci "%s\n", strerror(-i)); 3341987da915Sopenharmony_ci free(fn); 3342987da915Sopenharmony_ci /* Undo link count increment. */ 3343987da915Sopenharmony_ci m_file->link_count = cpu_to_le16( 3344987da915Sopenharmony_ci le16_to_cpu(m_file->link_count) - 1); 3345987da915Sopenharmony_ci return i; 3346987da915Sopenharmony_ci } 3347987da915Sopenharmony_ci /* Insert the index entry for file_name in @idx. */ 3348987da915Sopenharmony_ci i = insert_file_link_in_dir_index(idx, ref_file, fn, fn_size); 3349987da915Sopenharmony_ci if (i < 0) { 3350987da915Sopenharmony_ci ntfs_log_error("create_hardlink failed inserting index entry: %s\n", 3351987da915Sopenharmony_ci strerror(-i)); 3352987da915Sopenharmony_ci /* FIXME: Remove the file name attribute from @m_file. */ 3353987da915Sopenharmony_ci free(fn); 3354987da915Sopenharmony_ci /* Undo link count increment. */ 3355987da915Sopenharmony_ci m_file->link_count = cpu_to_le16( 3356987da915Sopenharmony_ci le16_to_cpu(m_file->link_count) - 1); 3357987da915Sopenharmony_ci return i; 3358987da915Sopenharmony_ci } 3359987da915Sopenharmony_ci free(fn); 3360987da915Sopenharmony_ci return 0; 3361987da915Sopenharmony_ci} 3362987da915Sopenharmony_ci 3363987da915Sopenharmony_ci/** 3364987da915Sopenharmony_ci * index_obj_id_insert 3365987da915Sopenharmony_ci * 3366987da915Sopenharmony_ci * Insert an index entry with the key @guid and data pointing to the mft record 3367987da915Sopenharmony_ci * @ref in the $O index root of the mft record @m (which must be the mft record 3368987da915Sopenharmony_ci * for $ObjId). 3369987da915Sopenharmony_ci * 3370987da915Sopenharmony_ci * Return 0 on success or -errno on error. 3371987da915Sopenharmony_ci */ 3372987da915Sopenharmony_cistatic int index_obj_id_insert(MFT_RECORD *m, const GUID *guid, 3373987da915Sopenharmony_ci const leMFT_REF ref) 3374987da915Sopenharmony_ci{ 3375987da915Sopenharmony_ci INDEX_ENTRY *idx_entry_new; 3376987da915Sopenharmony_ci int data_ofs, idx_size, err; 3377987da915Sopenharmony_ci OBJ_ID_INDEX_DATA *oi; 3378987da915Sopenharmony_ci 3379987da915Sopenharmony_ci /* 3380987da915Sopenharmony_ci * Insert the index entry for the object id in the index. 3381987da915Sopenharmony_ci * 3382987da915Sopenharmony_ci * First determine the size of the index entry to be inserted. This 3383987da915Sopenharmony_ci * consists of the index entry header, followed by the index key, i.e. 3384987da915Sopenharmony_ci * the GUID, followed by the index data, i.e. OBJ_ID_INDEX_DATA. 3385987da915Sopenharmony_ci */ 3386987da915Sopenharmony_ci data_ofs = (sizeof(INDEX_ENTRY_HEADER) + sizeof(GUID) + 7) & ~7; 3387987da915Sopenharmony_ci idx_size = (data_ofs + sizeof(OBJ_ID_INDEX_DATA) + 7) & ~7; 3388987da915Sopenharmony_ci idx_entry_new = ntfs_calloc(idx_size); 3389987da915Sopenharmony_ci if (!idx_entry_new) 3390987da915Sopenharmony_ci return -errno; 3391987da915Sopenharmony_ci idx_entry_new->data_offset = cpu_to_le16(data_ofs); 3392987da915Sopenharmony_ci idx_entry_new->data_length = 3393987da915Sopenharmony_ci const_cpu_to_le16(sizeof(OBJ_ID_INDEX_DATA)); 3394987da915Sopenharmony_ci idx_entry_new->length = cpu_to_le16(idx_size); 3395987da915Sopenharmony_ci idx_entry_new->key_length = const_cpu_to_le16(sizeof(GUID)); 3396987da915Sopenharmony_ci idx_entry_new->key.object_id = *guid; 3397987da915Sopenharmony_ci oi = (OBJ_ID_INDEX_DATA*)((u8*)idx_entry_new + data_ofs); 3398987da915Sopenharmony_ci oi->mft_reference = ref; 3399987da915Sopenharmony_ci err = insert_index_entry_in_res_dir_index(idx_entry_new, idx_size, m, 3400987da915Sopenharmony_ci NTFS_INDEX_O, 2, AT_UNUSED); 3401987da915Sopenharmony_ci free(idx_entry_new); 3402987da915Sopenharmony_ci if (err < 0) { 3403987da915Sopenharmony_ci ntfs_log_error("index_obj_id_insert failed inserting index " 3404987da915Sopenharmony_ci "entry: %s\n", strerror(-err)); 3405987da915Sopenharmony_ci return err; 3406987da915Sopenharmony_ci } 3407987da915Sopenharmony_ci return 0; 3408987da915Sopenharmony_ci} 3409987da915Sopenharmony_ci 3410987da915Sopenharmony_ci/** 3411987da915Sopenharmony_ci * mkntfs_cleanup 3412987da915Sopenharmony_ci */ 3413987da915Sopenharmony_cistatic void mkntfs_cleanup(void) 3414987da915Sopenharmony_ci{ 3415987da915Sopenharmony_ci struct BITMAP_ALLOCATION *p, *q; 3416987da915Sopenharmony_ci 3417987da915Sopenharmony_ci /* Close the volume */ 3418987da915Sopenharmony_ci if (g_vol) { 3419987da915Sopenharmony_ci if (g_vol->dev) { 3420987da915Sopenharmony_ci if (NDevOpen(g_vol->dev) && g_vol->dev->d_ops->close(g_vol->dev)) 3421987da915Sopenharmony_ci ntfs_log_perror("Warning: Could not close %s", g_vol->dev->d_name); 3422987da915Sopenharmony_ci ntfs_device_free(g_vol->dev); 3423987da915Sopenharmony_ci } 3424987da915Sopenharmony_ci free(g_vol->vol_name); 3425987da915Sopenharmony_ci free(g_vol->attrdef); 3426987da915Sopenharmony_ci free(g_vol->upcase); 3427987da915Sopenharmony_ci free(g_vol); 3428987da915Sopenharmony_ci g_vol = NULL; 3429987da915Sopenharmony_ci } 3430987da915Sopenharmony_ci 3431987da915Sopenharmony_ci /* Free any memory we've used */ 3432987da915Sopenharmony_ci free(g_bad_blocks); g_bad_blocks = NULL; 3433987da915Sopenharmony_ci free(g_buf); g_buf = NULL; 3434987da915Sopenharmony_ci free(g_index_block); g_index_block = NULL; 3435987da915Sopenharmony_ci free(g_dynamic_buf); g_dynamic_buf = NULL; 3436987da915Sopenharmony_ci free(g_mft_bitmap); g_mft_bitmap = NULL; 3437987da915Sopenharmony_ci free(g_rl_bad); g_rl_bad = NULL; 3438987da915Sopenharmony_ci free(g_rl_boot); g_rl_boot = NULL; 3439987da915Sopenharmony_ci free(g_rl_logfile); g_rl_logfile = NULL; 3440987da915Sopenharmony_ci free(g_rl_mft); g_rl_mft = NULL; 3441987da915Sopenharmony_ci free(g_rl_mft_bmp); g_rl_mft_bmp = NULL; 3442987da915Sopenharmony_ci free(g_rl_mftmirr); g_rl_mftmirr = NULL; 3443987da915Sopenharmony_ci 3444987da915Sopenharmony_ci p = g_allocation; 3445987da915Sopenharmony_ci while (p) { 3446987da915Sopenharmony_ci q = p->next; 3447987da915Sopenharmony_ci free(p); 3448987da915Sopenharmony_ci p = q; 3449987da915Sopenharmony_ci } 3450987da915Sopenharmony_ci} 3451987da915Sopenharmony_ci 3452987da915Sopenharmony_ci 3453987da915Sopenharmony_ci/** 3454987da915Sopenharmony_ci * mkntfs_open_partition - 3455987da915Sopenharmony_ci */ 3456987da915Sopenharmony_cistatic BOOL mkntfs_open_partition(ntfs_volume *vol) 3457987da915Sopenharmony_ci{ 3458987da915Sopenharmony_ci BOOL result = FALSE; 3459987da915Sopenharmony_ci int i; 3460987da915Sopenharmony_ci struct stat sbuf; 3461987da915Sopenharmony_ci unsigned long mnt_flags; 3462987da915Sopenharmony_ci 3463987da915Sopenharmony_ci /* 3464987da915Sopenharmony_ci * Allocate and initialize an ntfs device structure and attach it to 3465987da915Sopenharmony_ci * the volume. 3466987da915Sopenharmony_ci */ 3467987da915Sopenharmony_ci vol->dev = ntfs_device_alloc(opts.dev_name, 0, &ntfs_device_default_io_ops, NULL); 3468987da915Sopenharmony_ci if (!vol->dev) { 3469987da915Sopenharmony_ci ntfs_log_perror("Could not create device"); 3470987da915Sopenharmony_ci goto done; 3471987da915Sopenharmony_ci } 3472987da915Sopenharmony_ci 3473987da915Sopenharmony_ci /* Open the device for reading or reading and writing. */ 3474987da915Sopenharmony_ci if (opts.no_action) { 3475987da915Sopenharmony_ci ntfs_log_quiet("Running in READ-ONLY mode!\n"); 3476987da915Sopenharmony_ci i = O_RDONLY; 3477987da915Sopenharmony_ci } else { 3478987da915Sopenharmony_ci i = O_RDWR; 3479987da915Sopenharmony_ci } 3480987da915Sopenharmony_ci if (vol->dev->d_ops->open(vol->dev, i)) { 3481987da915Sopenharmony_ci if (errno == ENOENT) 3482987da915Sopenharmony_ci ntfs_log_error("The device doesn't exist; did you specify it correctly?\n"); 3483987da915Sopenharmony_ci else 3484987da915Sopenharmony_ci ntfs_log_perror("Could not open %s", vol->dev->d_name); 3485987da915Sopenharmony_ci goto done; 3486987da915Sopenharmony_ci } 3487987da915Sopenharmony_ci /* Verify we are dealing with a block device. */ 3488987da915Sopenharmony_ci if (vol->dev->d_ops->stat(vol->dev, &sbuf)) { 3489987da915Sopenharmony_ci ntfs_log_perror("Error getting information about %s", vol->dev->d_name); 3490987da915Sopenharmony_ci goto done; 3491987da915Sopenharmony_ci } 3492987da915Sopenharmony_ci 3493987da915Sopenharmony_ci if (!S_ISBLK(sbuf.st_mode)) { 3494987da915Sopenharmony_ci ntfs_log_error("%s is not a block device.\n", vol->dev->d_name); 3495987da915Sopenharmony_ci if (!opts.force) { 3496987da915Sopenharmony_ci ntfs_log_error("Refusing to make a filesystem here!\n"); 3497987da915Sopenharmony_ci goto done; 3498987da915Sopenharmony_ci } 3499987da915Sopenharmony_ci if (!opts.num_sectors) { 3500987da915Sopenharmony_ci if (!sbuf.st_size && !sbuf.st_blocks) { 3501987da915Sopenharmony_ci ntfs_log_error("You must specify the number of sectors.\n"); 3502987da915Sopenharmony_ci goto done; 3503987da915Sopenharmony_ci } 3504987da915Sopenharmony_ci if (opts.sector_size) { 3505987da915Sopenharmony_ci if (sbuf.st_size) 3506987da915Sopenharmony_ci opts.num_sectors = sbuf.st_size / opts.sector_size; 3507987da915Sopenharmony_ci else 3508987da915Sopenharmony_ci opts.num_sectors = ((s64)sbuf.st_blocks << 9) / opts.sector_size; 3509987da915Sopenharmony_ci } else { 3510987da915Sopenharmony_ci if (sbuf.st_size) 3511987da915Sopenharmony_ci opts.num_sectors = sbuf.st_size / 512; 3512987da915Sopenharmony_ci else 3513987da915Sopenharmony_ci opts.num_sectors = sbuf.st_blocks; 3514987da915Sopenharmony_ci opts.sector_size = 512; 3515987da915Sopenharmony_ci } 3516987da915Sopenharmony_ci } 3517987da915Sopenharmony_ci ntfs_log_warning("mkntfs forced anyway.\n"); 3518987da915Sopenharmony_ci#ifdef HAVE_LINUX_MAJOR_H 3519987da915Sopenharmony_ci } else if ((IDE_DISK_MAJOR(MAJOR(sbuf.st_rdev)) && 3520987da915Sopenharmony_ci MINOR(sbuf.st_rdev) % 64 == 0) || 3521987da915Sopenharmony_ci (SCSI_DISK_MAJOR(MAJOR(sbuf.st_rdev)) && 3522987da915Sopenharmony_ci MINOR(sbuf.st_rdev) % 16 == 0)) { 3523987da915Sopenharmony_ci ntfs_log_error("%s is entire device, not just one partition.\n", vol->dev->d_name); 3524987da915Sopenharmony_ci if (!opts.force) { 3525987da915Sopenharmony_ci ntfs_log_error("Refusing to make a filesystem here!\n"); 3526987da915Sopenharmony_ci goto done; 3527987da915Sopenharmony_ci } 3528987da915Sopenharmony_ci ntfs_log_warning("mkntfs forced anyway.\n"); 3529987da915Sopenharmony_ci#endif 3530987da915Sopenharmony_ci } 3531987da915Sopenharmony_ci /* Make sure the file system is not mounted. */ 3532987da915Sopenharmony_ci if (ntfs_check_if_mounted(vol->dev->d_name, &mnt_flags)) { 3533987da915Sopenharmony_ci ntfs_log_perror("Failed to determine whether %s is mounted", vol->dev->d_name); 3534987da915Sopenharmony_ci } else if (mnt_flags & NTFS_MF_MOUNTED) { 3535987da915Sopenharmony_ci ntfs_log_error("%s is mounted.\n", vol->dev->d_name); 3536987da915Sopenharmony_ci if (!opts.force) { 3537987da915Sopenharmony_ci ntfs_log_error("Refusing to make a filesystem here!\n"); 3538987da915Sopenharmony_ci goto done; 3539987da915Sopenharmony_ci } 3540987da915Sopenharmony_ci ntfs_log_warning("mkntfs forced anyway. Hope /etc/mtab is incorrect.\n"); 3541987da915Sopenharmony_ci } 3542987da915Sopenharmony_ci result = TRUE; 3543987da915Sopenharmony_cidone: 3544987da915Sopenharmony_ci return result; 3545987da915Sopenharmony_ci} 3546987da915Sopenharmony_ci 3547987da915Sopenharmony_ci/** 3548987da915Sopenharmony_ci * mkntfs_get_page_size - detect the system's memory page size. 3549987da915Sopenharmony_ci */ 3550987da915Sopenharmony_cistatic long mkntfs_get_page_size(void) 3551987da915Sopenharmony_ci{ 3552987da915Sopenharmony_ci long page_size; 3553987da915Sopenharmony_ci#ifdef _SC_PAGESIZE 3554987da915Sopenharmony_ci page_size = sysconf(_SC_PAGESIZE); 3555987da915Sopenharmony_ci if (page_size < 0) 3556987da915Sopenharmony_ci#endif 3557987da915Sopenharmony_ci { 3558987da915Sopenharmony_ci ntfs_log_warning("Failed to determine system page size. " 3559987da915Sopenharmony_ci "Assuming safe default of 4096 bytes.\n"); 3560987da915Sopenharmony_ci return 4096; 3561987da915Sopenharmony_ci } 3562987da915Sopenharmony_ci ntfs_log_debug("System page size is %li bytes.\n", page_size); 3563987da915Sopenharmony_ci return page_size; 3564987da915Sopenharmony_ci} 3565987da915Sopenharmony_ci 3566987da915Sopenharmony_ci/** 3567987da915Sopenharmony_ci * mkntfs_override_vol_params - 3568987da915Sopenharmony_ci */ 3569987da915Sopenharmony_cistatic BOOL mkntfs_override_vol_params(ntfs_volume *vol) 3570987da915Sopenharmony_ci{ 3571987da915Sopenharmony_ci s64 volume_size; 3572987da915Sopenharmony_ci long page_size; 3573987da915Sopenharmony_ci int i; 3574987da915Sopenharmony_ci BOOL winboot = TRUE; 3575987da915Sopenharmony_ci 3576987da915Sopenharmony_ci /* If user didn't specify the sector size, determine it now. */ 3577987da915Sopenharmony_ci if (opts.sector_size < 0) { 3578987da915Sopenharmony_ci opts.sector_size = ntfs_device_sector_size_get(vol->dev); 3579987da915Sopenharmony_ci if (opts.sector_size < 0) { 3580987da915Sopenharmony_ci ntfs_log_warning("The sector size was not specified " 3581987da915Sopenharmony_ci "for %s and it could not be obtained " 3582987da915Sopenharmony_ci "automatically. It has been set to 512 " 3583987da915Sopenharmony_ci "bytes.\n", vol->dev->d_name); 3584987da915Sopenharmony_ci opts.sector_size = 512; 3585987da915Sopenharmony_ci } 3586987da915Sopenharmony_ci } 3587987da915Sopenharmony_ci /* Validate sector size. */ 3588987da915Sopenharmony_ci if ((opts.sector_size - 1) & opts.sector_size) { 3589987da915Sopenharmony_ci ntfs_log_error("The sector size is invalid. It must be a " 3590987da915Sopenharmony_ci "power of two, e.g. 512, 1024.\n"); 3591987da915Sopenharmony_ci return FALSE; 3592987da915Sopenharmony_ci } 3593987da915Sopenharmony_ci if (opts.sector_size < 256 || opts.sector_size > 4096) { 3594987da915Sopenharmony_ci ntfs_log_error("The sector size is invalid. The minimum size " 3595987da915Sopenharmony_ci "is 256 bytes and the maximum is 4096 bytes.\n"); 3596987da915Sopenharmony_ci return FALSE; 3597987da915Sopenharmony_ci } 3598987da915Sopenharmony_ci ntfs_log_debug("sector size = %ld bytes\n", opts.sector_size); 3599987da915Sopenharmony_ci /* Now set the device block size to the sector size. */ 3600987da915Sopenharmony_ci if (ntfs_device_block_size_set(vol->dev, opts.sector_size)) 3601987da915Sopenharmony_ci ntfs_log_debug("Failed to set the device block size to the " 3602987da915Sopenharmony_ci "sector size. This may cause problems when " 3603987da915Sopenharmony_ci "creating the backup boot sector and also may " 3604987da915Sopenharmony_ci "affect performance but should be harmless " 3605987da915Sopenharmony_ci "otherwise. Error: %s\n", strerror(errno)); 3606987da915Sopenharmony_ci /* If user didn't specify the number of sectors, determine it now. */ 3607987da915Sopenharmony_ci if (opts.num_sectors < 0) { 3608987da915Sopenharmony_ci opts.num_sectors = ntfs_device_size_get(vol->dev, 3609987da915Sopenharmony_ci opts.sector_size); 3610987da915Sopenharmony_ci if (opts.num_sectors <= 0) { 3611987da915Sopenharmony_ci ntfs_log_error("Couldn't determine the size of %s. " 3612987da915Sopenharmony_ci "Please specify the number of sectors " 3613987da915Sopenharmony_ci "manually.\n", vol->dev->d_name); 3614987da915Sopenharmony_ci return FALSE; 3615987da915Sopenharmony_ci } 3616987da915Sopenharmony_ci } 3617987da915Sopenharmony_ci ntfs_log_debug("number of sectors = %lld (0x%llx)\n", opts.num_sectors, 3618987da915Sopenharmony_ci opts.num_sectors); 3619987da915Sopenharmony_ci /* 3620987da915Sopenharmony_ci * Reserve the last sector for the backup boot sector unless the 3621987da915Sopenharmony_ci * sector size is less than 512 bytes in which case reserve 512 bytes 3622987da915Sopenharmony_ci * worth of sectors. 3623987da915Sopenharmony_ci */ 3624987da915Sopenharmony_ci i = 1; 3625987da915Sopenharmony_ci if (opts.sector_size < 512) 3626987da915Sopenharmony_ci i = 512 / opts.sector_size; 3627987da915Sopenharmony_ci opts.num_sectors -= i; 3628987da915Sopenharmony_ci /* If user didn't specify the partition start sector, determine it. */ 3629987da915Sopenharmony_ci if (opts.part_start_sect < 0) { 3630987da915Sopenharmony_ci opts.part_start_sect = ntfs_device_partition_start_sector_get( 3631987da915Sopenharmony_ci vol->dev); 3632987da915Sopenharmony_ci if (opts.part_start_sect < 0) { 3633987da915Sopenharmony_ci ntfs_log_warning("The partition start sector was not " 3634987da915Sopenharmony_ci "specified for %s and it could not be obtained " 3635987da915Sopenharmony_ci "automatically. It has been set to 0.\n", 3636987da915Sopenharmony_ci vol->dev->d_name); 3637987da915Sopenharmony_ci opts.part_start_sect = 0; 3638987da915Sopenharmony_ci winboot = FALSE; 3639987da915Sopenharmony_ci } else if (opts.part_start_sect >> 32) { 3640987da915Sopenharmony_ci ntfs_log_warning("The partition start sector was not " 3641987da915Sopenharmony_ci "specified for %s and the automatically " 3642987da915Sopenharmony_ci "determined value is too large (%lld). " 3643987da915Sopenharmony_ci "It has been set to 0.\n", 3644987da915Sopenharmony_ci vol->dev->d_name, 3645987da915Sopenharmony_ci (long long)opts.part_start_sect); 3646987da915Sopenharmony_ci opts.part_start_sect = 0; 3647987da915Sopenharmony_ci winboot = FALSE; 3648987da915Sopenharmony_ci } 3649987da915Sopenharmony_ci } else if (opts.part_start_sect >> 32) { 3650987da915Sopenharmony_ci ntfs_log_error("Invalid partition start sector. Maximum is " 3651987da915Sopenharmony_ci "4294967295 (2^32-1).\n"); 3652987da915Sopenharmony_ci return FALSE; 3653987da915Sopenharmony_ci } 3654987da915Sopenharmony_ci /* If user didn't specify the sectors per track, determine it now. */ 3655987da915Sopenharmony_ci if (opts.sectors_per_track < 0) { 3656987da915Sopenharmony_ci opts.sectors_per_track = ntfs_device_sectors_per_track_get( 3657987da915Sopenharmony_ci vol->dev); 3658987da915Sopenharmony_ci if (opts.sectors_per_track < 0) { 3659987da915Sopenharmony_ci ntfs_log_warning("The number of sectors per track was " 3660987da915Sopenharmony_ci "not specified for %s and it could not be " 3661987da915Sopenharmony_ci "obtained automatically. It has been set to " 3662987da915Sopenharmony_ci "0.\n", vol->dev->d_name); 3663987da915Sopenharmony_ci opts.sectors_per_track = 0; 3664987da915Sopenharmony_ci winboot = FALSE; 3665987da915Sopenharmony_ci } else if (opts.sectors_per_track > 65535) { 3666987da915Sopenharmony_ci ntfs_log_warning("The number of sectors per track was " 3667987da915Sopenharmony_ci "not specified for %s and the automatically " 3668987da915Sopenharmony_ci "determined value is too large. It has been " 3669987da915Sopenharmony_ci "set to 0.\n", vol->dev->d_name); 3670987da915Sopenharmony_ci opts.sectors_per_track = 0; 3671987da915Sopenharmony_ci winboot = FALSE; 3672987da915Sopenharmony_ci } 3673987da915Sopenharmony_ci } else if (opts.sectors_per_track > 65535) { 3674987da915Sopenharmony_ci ntfs_log_error("Invalid number of sectors per track. Maximum " 3675987da915Sopenharmony_ci "is 65535.\n"); 3676987da915Sopenharmony_ci return FALSE; 3677987da915Sopenharmony_ci } 3678987da915Sopenharmony_ci /* If user didn't specify the number of heads, determine it now. */ 3679987da915Sopenharmony_ci if (opts.heads < 0) { 3680987da915Sopenharmony_ci opts.heads = ntfs_device_heads_get(vol->dev); 3681987da915Sopenharmony_ci if (opts.heads < 0) { 3682987da915Sopenharmony_ci ntfs_log_warning("The number of heads was not " 3683987da915Sopenharmony_ci "specified for %s and it could not be obtained " 3684987da915Sopenharmony_ci "automatically. It has been set to 0.\n", 3685987da915Sopenharmony_ci vol->dev->d_name); 3686987da915Sopenharmony_ci opts.heads = 0; 3687987da915Sopenharmony_ci winboot = FALSE; 3688987da915Sopenharmony_ci } else if (opts.heads > 65535) { 3689987da915Sopenharmony_ci ntfs_log_warning("The number of heads was not " 3690987da915Sopenharmony_ci "specified for %s and the automatically " 3691987da915Sopenharmony_ci "determined value is too large. It has been " 3692987da915Sopenharmony_ci "set to 0.\n", vol->dev->d_name); 3693987da915Sopenharmony_ci opts.heads = 0; 3694987da915Sopenharmony_ci winboot = FALSE; 3695987da915Sopenharmony_ci } 3696987da915Sopenharmony_ci } else if (opts.heads > 65535) { 3697987da915Sopenharmony_ci ntfs_log_error("Invalid number of heads. Maximum is 65535.\n"); 3698987da915Sopenharmony_ci return FALSE; 3699987da915Sopenharmony_ci } 3700987da915Sopenharmony_ci volume_size = opts.num_sectors * opts.sector_size; 3701987da915Sopenharmony_ci /* Validate volume size. */ 3702987da915Sopenharmony_ci if (volume_size < (1 << 20)) { /* 1MiB */ 3703987da915Sopenharmony_ci ntfs_log_error("Device is too small (%llikiB). Minimum NTFS " 3704987da915Sopenharmony_ci "volume size is 1MiB.\n", 3705987da915Sopenharmony_ci (long long)(volume_size / 1024)); 3706987da915Sopenharmony_ci return FALSE; 3707987da915Sopenharmony_ci } 3708987da915Sopenharmony_ci ntfs_log_debug("volume size = %llikiB\n", 3709987da915Sopenharmony_ci (long long)(volume_size / 1024)); 3710987da915Sopenharmony_ci /* If user didn't specify the cluster size, determine it now. */ 3711987da915Sopenharmony_ci if (!vol->cluster_size) { 3712987da915Sopenharmony_ci /* 3713987da915Sopenharmony_ci * Windows Vista always uses 4096 bytes as the default cluster 3714987da915Sopenharmony_ci * size regardless of the volume size so we do it, too. 3715987da915Sopenharmony_ci */ 3716987da915Sopenharmony_ci vol->cluster_size = 4096; 3717987da915Sopenharmony_ci /* For small volumes on devices with large sector sizes. */ 3718987da915Sopenharmony_ci if (vol->cluster_size < (u32)opts.sector_size) 3719987da915Sopenharmony_ci vol->cluster_size = opts.sector_size; 3720987da915Sopenharmony_ci /* 3721987da915Sopenharmony_ci * For huge volumes, grow the cluster size until the number of 3722987da915Sopenharmony_ci * clusters fits into 32 bits or the cluster size exceeds the 3723987da915Sopenharmony_ci * maximum limit of NTFS_MAX_CLUSTER_SIZE. 3724987da915Sopenharmony_ci */ 3725987da915Sopenharmony_ci while (volume_size >> (ffs(vol->cluster_size) - 1 + 32)) { 3726987da915Sopenharmony_ci vol->cluster_size <<= 1; 3727987da915Sopenharmony_ci if (vol->cluster_size >= NTFS_MAX_CLUSTER_SIZE) { 3728987da915Sopenharmony_ci ntfs_log_error("Device is too large to hold an " 3729987da915Sopenharmony_ci "NTFS volume (maximum size is " 3730987da915Sopenharmony_ci "256TiB).\n"); 3731987da915Sopenharmony_ci return FALSE; 3732987da915Sopenharmony_ci } 3733987da915Sopenharmony_ci } 3734987da915Sopenharmony_ci ntfs_log_quiet("Cluster size has been automatically set to %u " 3735987da915Sopenharmony_ci "bytes.\n", (unsigned)vol->cluster_size); 3736987da915Sopenharmony_ci } 3737987da915Sopenharmony_ci /* Validate cluster size. */ 3738987da915Sopenharmony_ci if (vol->cluster_size & (vol->cluster_size - 1)) { 3739987da915Sopenharmony_ci ntfs_log_error("The cluster size is invalid. It must be a " 3740987da915Sopenharmony_ci "power of two, e.g. 1024, 4096.\n"); 3741987da915Sopenharmony_ci return FALSE; 3742987da915Sopenharmony_ci } 3743987da915Sopenharmony_ci if (vol->cluster_size < (u32)opts.sector_size) { 3744987da915Sopenharmony_ci ntfs_log_error("The cluster size is invalid. It must be equal " 3745987da915Sopenharmony_ci "to, or larger than, the sector size.\n"); 3746987da915Sopenharmony_ci return FALSE; 3747987da915Sopenharmony_ci } 3748987da915Sopenharmony_ci /* Before Windows 10 Creators, the limit was 128 */ 3749987da915Sopenharmony_ci if (vol->cluster_size > 4096 * (u32)opts.sector_size) { 3750987da915Sopenharmony_ci ntfs_log_error("The cluster size is invalid. It cannot be " 3751987da915Sopenharmony_ci "more that 4096 times the size of the sector " 3752987da915Sopenharmony_ci "size.\n"); 3753987da915Sopenharmony_ci return FALSE; 3754987da915Sopenharmony_ci } 3755987da915Sopenharmony_ci if (vol->cluster_size > NTFS_MAX_CLUSTER_SIZE) { 3756987da915Sopenharmony_ci ntfs_log_error("The cluster size is invalid. The maximum " 3757987da915Sopenharmony_ci "cluster size is %lu bytes (%lukiB).\n", 3758987da915Sopenharmony_ci (unsigned long)NTFS_MAX_CLUSTER_SIZE, 3759987da915Sopenharmony_ci (unsigned long)(NTFS_MAX_CLUSTER_SIZE >> 10)); 3760987da915Sopenharmony_ci return FALSE; 3761987da915Sopenharmony_ci } 3762987da915Sopenharmony_ci vol->cluster_size_bits = ffs(vol->cluster_size) - 1; 3763987da915Sopenharmony_ci ntfs_log_debug("cluster size = %u bytes\n", 3764987da915Sopenharmony_ci (unsigned int)vol->cluster_size); 3765987da915Sopenharmony_ci if (vol->cluster_size > 4096) { 3766987da915Sopenharmony_ci if (opts.enable_compression) { 3767987da915Sopenharmony_ci if (!opts.force) { 3768987da915Sopenharmony_ci ntfs_log_error("Windows cannot use compression " 3769987da915Sopenharmony_ci "when the cluster size is " 3770987da915Sopenharmony_ci "larger than 4096 bytes.\n"); 3771987da915Sopenharmony_ci return FALSE; 3772987da915Sopenharmony_ci } 3773987da915Sopenharmony_ci opts.enable_compression = 0; 3774987da915Sopenharmony_ci } 3775987da915Sopenharmony_ci ntfs_log_warning("Windows cannot use compression when the " 3776987da915Sopenharmony_ci "cluster size is larger than 4096 bytes. " 3777987da915Sopenharmony_ci "Compression has been disabled for this " 3778987da915Sopenharmony_ci "volume.\n"); 3779987da915Sopenharmony_ci } 3780987da915Sopenharmony_ci vol->nr_clusters = volume_size / vol->cluster_size; 3781987da915Sopenharmony_ci /* 3782987da915Sopenharmony_ci * Check the cluster_size and num_sectors for consistency with 3783987da915Sopenharmony_ci * sector_size and num_sectors. And check both of these for consistency 3784987da915Sopenharmony_ci * with volume_size. 3785987da915Sopenharmony_ci */ 3786987da915Sopenharmony_ci if ((vol->nr_clusters != ((opts.num_sectors * opts.sector_size) / 3787987da915Sopenharmony_ci vol->cluster_size) || 3788987da915Sopenharmony_ci (volume_size / opts.sector_size) != opts.num_sectors || 3789987da915Sopenharmony_ci (volume_size / vol->cluster_size) != 3790987da915Sopenharmony_ci vol->nr_clusters)) { 3791987da915Sopenharmony_ci /* XXX is this code reachable? */ 3792987da915Sopenharmony_ci ntfs_log_error("Illegal combination of volume/cluster/sector " 3793987da915Sopenharmony_ci "size and/or cluster/sector number.\n"); 3794987da915Sopenharmony_ci return FALSE; 3795987da915Sopenharmony_ci } 3796987da915Sopenharmony_ci ntfs_log_debug("number of clusters = %llu (0x%llx)\n", 3797987da915Sopenharmony_ci (unsigned long long)vol->nr_clusters, 3798987da915Sopenharmony_ci (unsigned long long)vol->nr_clusters); 3799987da915Sopenharmony_ci /* Number of clusters must fit within 32 bits (Win2k limitation). */ 3800987da915Sopenharmony_ci if (vol->nr_clusters >> 32) { 3801987da915Sopenharmony_ci if (vol->cluster_size >= 65536) { 3802987da915Sopenharmony_ci ntfs_log_error("Device is too large to hold an NTFS " 3803987da915Sopenharmony_ci "volume (maximum size is 256TiB).\n"); 3804987da915Sopenharmony_ci return FALSE; 3805987da915Sopenharmony_ci } 3806987da915Sopenharmony_ci ntfs_log_error("Number of clusters exceeds 32 bits. Please " 3807987da915Sopenharmony_ci "try again with a larger\ncluster size or " 3808987da915Sopenharmony_ci "leave the cluster size unspecified and the " 3809987da915Sopenharmony_ci "smallest possible cluster size for the size " 3810987da915Sopenharmony_ci "of the device will be used.\n"); 3811987da915Sopenharmony_ci return FALSE; 3812987da915Sopenharmony_ci } 3813987da915Sopenharmony_ci page_size = mkntfs_get_page_size(); 3814987da915Sopenharmony_ci /* 3815987da915Sopenharmony_ci * Set the mft record size. By default this is 1024 but it has to be 3816987da915Sopenharmony_ci * at least as big as a sector and not bigger than a page on the system 3817987da915Sopenharmony_ci * or the NTFS kernel driver will not be able to mount the volume. 3818987da915Sopenharmony_ci * TODO: The mft record size should be user specifiable just like the 3819987da915Sopenharmony_ci * "inode size" can be specified on other Linux/Unix file systems. 3820987da915Sopenharmony_ci */ 3821987da915Sopenharmony_ci vol->mft_record_size = 1024; 3822987da915Sopenharmony_ci if (vol->mft_record_size < (u32)opts.sector_size) 3823987da915Sopenharmony_ci vol->mft_record_size = opts.sector_size; 3824987da915Sopenharmony_ci if (vol->mft_record_size > (unsigned long)page_size) 3825987da915Sopenharmony_ci ntfs_log_warning("Mft record size (%u bytes) exceeds system " 3826987da915Sopenharmony_ci "page size (%li bytes). You will not be able " 3827987da915Sopenharmony_ci "to mount this volume using the NTFS kernel " 3828987da915Sopenharmony_ci "driver.\n", (unsigned)vol->mft_record_size, 3829987da915Sopenharmony_ci page_size); 3830987da915Sopenharmony_ci vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1; 3831987da915Sopenharmony_ci ntfs_log_debug("mft record size = %u bytes\n", 3832987da915Sopenharmony_ci (unsigned)vol->mft_record_size); 3833987da915Sopenharmony_ci /* 3834987da915Sopenharmony_ci * Set the index record size. By default this is 4096 but it has to be 3835987da915Sopenharmony_ci * at least as big as a sector and not bigger than a page on the system 3836987da915Sopenharmony_ci * or the NTFS kernel driver will not be able to mount the volume. 3837987da915Sopenharmony_ci * FIXME: Should we make the index record size to be user specifiable? 3838987da915Sopenharmony_ci */ 3839987da915Sopenharmony_ci vol->indx_record_size = 4096; 3840987da915Sopenharmony_ci if (vol->indx_record_size < (u32)opts.sector_size) 3841987da915Sopenharmony_ci vol->indx_record_size = opts.sector_size; 3842987da915Sopenharmony_ci if (vol->indx_record_size > (unsigned long)page_size) 3843987da915Sopenharmony_ci ntfs_log_warning("Index record size (%u bytes) exceeds system " 3844987da915Sopenharmony_ci "page size (%li bytes). You will not be able " 3845987da915Sopenharmony_ci "to mount this volume using the NTFS kernel " 3846987da915Sopenharmony_ci "driver.\n", (unsigned)vol->indx_record_size, 3847987da915Sopenharmony_ci page_size); 3848987da915Sopenharmony_ci vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1; 3849987da915Sopenharmony_ci ntfs_log_debug("index record size = %u bytes\n", 3850987da915Sopenharmony_ci (unsigned)vol->indx_record_size); 3851987da915Sopenharmony_ci if (!winboot) { 3852987da915Sopenharmony_ci ntfs_log_warning("To boot from a device, Windows needs the " 3853987da915Sopenharmony_ci "'partition start sector', the 'sectors per " 3854987da915Sopenharmony_ci "track' and the 'number of heads' to be " 3855987da915Sopenharmony_ci "set.\n"); 3856987da915Sopenharmony_ci ntfs_log_warning("Windows will not be able to boot from this " 3857987da915Sopenharmony_ci "device.\n"); 3858987da915Sopenharmony_ci } 3859987da915Sopenharmony_ci return TRUE; 3860987da915Sopenharmony_ci} 3861987da915Sopenharmony_ci 3862987da915Sopenharmony_ci/** 3863987da915Sopenharmony_ci * mkntfs_initialize_bitmaps - 3864987da915Sopenharmony_ci */ 3865987da915Sopenharmony_cistatic BOOL mkntfs_initialize_bitmaps(void) 3866987da915Sopenharmony_ci{ 3867987da915Sopenharmony_ci u64 i; 3868987da915Sopenharmony_ci int mft_bitmap_size; 3869987da915Sopenharmony_ci 3870987da915Sopenharmony_ci /* Determine lcn bitmap byte size and allocate it. */ 3871987da915Sopenharmony_ci g_lcn_bitmap_byte_size = (g_vol->nr_clusters + 7) >> 3; 3872987da915Sopenharmony_ci /* Needs to be multiple of 8 bytes. */ 3873987da915Sopenharmony_ci g_lcn_bitmap_byte_size = (g_lcn_bitmap_byte_size + 7) & ~7; 3874987da915Sopenharmony_ci i = (g_lcn_bitmap_byte_size + g_vol->cluster_size - 1) & 3875987da915Sopenharmony_ci ~(g_vol->cluster_size - 1); 3876987da915Sopenharmony_ci ntfs_log_debug("g_lcn_bitmap_byte_size = %i, allocated = %llu\n", 3877987da915Sopenharmony_ci g_lcn_bitmap_byte_size, (unsigned long long)i); 3878987da915Sopenharmony_ci g_dynamic_buf_size = mkntfs_get_page_size(); 3879987da915Sopenharmony_ci g_dynamic_buf = (u8*)ntfs_calloc(g_dynamic_buf_size); 3880987da915Sopenharmony_ci if (!g_dynamic_buf) 3881987da915Sopenharmony_ci return FALSE; 3882987da915Sopenharmony_ci /* 3883987da915Sopenharmony_ci * $Bitmap can overlap the end of the volume. Any bits in this region 3884987da915Sopenharmony_ci * must be set. This region also encompasses the backup boot sector. 3885987da915Sopenharmony_ci */ 3886987da915Sopenharmony_ci if (!bitmap_allocate(g_vol->nr_clusters, 3887987da915Sopenharmony_ci ((s64)g_lcn_bitmap_byte_size << 3) - g_vol->nr_clusters)) 3888987da915Sopenharmony_ci return (FALSE); 3889987da915Sopenharmony_ci /* 3890987da915Sopenharmony_ci * Mft size is 27 (NTFS 3.0+) mft records or one cluster, whichever is 3891987da915Sopenharmony_ci * bigger. 3892987da915Sopenharmony_ci */ 3893987da915Sopenharmony_ci g_mft_size = 27; 3894987da915Sopenharmony_ci g_mft_size *= g_vol->mft_record_size; 3895987da915Sopenharmony_ci if (g_mft_size < (s32)g_vol->cluster_size) 3896987da915Sopenharmony_ci g_mft_size = g_vol->cluster_size; 3897987da915Sopenharmony_ci ntfs_log_debug("MFT size = %i (0x%x) bytes\n", g_mft_size, g_mft_size); 3898987da915Sopenharmony_ci /* Determine mft bitmap size and allocate it. */ 3899987da915Sopenharmony_ci mft_bitmap_size = g_mft_size / g_vol->mft_record_size; 3900987da915Sopenharmony_ci /* Convert to bytes, at least one. */ 3901987da915Sopenharmony_ci g_mft_bitmap_byte_size = (mft_bitmap_size + 7) >> 3; 3902987da915Sopenharmony_ci /* Mft bitmap is allocated in multiples of 8 bytes. */ 3903987da915Sopenharmony_ci g_mft_bitmap_byte_size = (g_mft_bitmap_byte_size + 7) & ~7; 3904987da915Sopenharmony_ci ntfs_log_debug("mft_bitmap_size = %i, g_mft_bitmap_byte_size = %i\n", 3905987da915Sopenharmony_ci mft_bitmap_size, g_mft_bitmap_byte_size); 3906987da915Sopenharmony_ci g_mft_bitmap = ntfs_calloc(g_mft_bitmap_byte_size); 3907987da915Sopenharmony_ci if (!g_mft_bitmap) 3908987da915Sopenharmony_ci return FALSE; 3909987da915Sopenharmony_ci /* Create runlist for mft bitmap. */ 3910987da915Sopenharmony_ci g_rl_mft_bmp = ntfs_malloc(2 * sizeof(runlist)); 3911987da915Sopenharmony_ci if (!g_rl_mft_bmp) 3912987da915Sopenharmony_ci return FALSE; 3913987da915Sopenharmony_ci 3914987da915Sopenharmony_ci g_rl_mft_bmp[0].vcn = 0LL; 3915987da915Sopenharmony_ci /* Mft bitmap is right after $Boot's data. */ 3916987da915Sopenharmony_ci i = (8192 + g_vol->cluster_size - 1) / g_vol->cluster_size; 3917987da915Sopenharmony_ci g_rl_mft_bmp[0].lcn = i; 3918987da915Sopenharmony_ci /* 3919987da915Sopenharmony_ci * Size is always one cluster, even though valid data size and 3920987da915Sopenharmony_ci * initialized data size are only 8 bytes. 3921987da915Sopenharmony_ci */ 3922987da915Sopenharmony_ci g_rl_mft_bmp[1].vcn = 1LL; 3923987da915Sopenharmony_ci g_rl_mft_bmp[0].length = 1LL; 3924987da915Sopenharmony_ci g_rl_mft_bmp[1].lcn = -1LL; 3925987da915Sopenharmony_ci g_rl_mft_bmp[1].length = 0LL; 3926987da915Sopenharmony_ci /* Allocate cluster for mft bitmap. */ 3927987da915Sopenharmony_ci return (bitmap_allocate(i,1)); 3928987da915Sopenharmony_ci} 3929987da915Sopenharmony_ci 3930987da915Sopenharmony_ci/** 3931987da915Sopenharmony_ci * mkntfs_initialize_rl_mft - 3932987da915Sopenharmony_ci */ 3933987da915Sopenharmony_cistatic BOOL mkntfs_initialize_rl_mft(void) 3934987da915Sopenharmony_ci{ 3935987da915Sopenharmony_ci int j; 3936987da915Sopenharmony_ci BOOL done; 3937987da915Sopenharmony_ci 3938987da915Sopenharmony_ci /* If user didn't specify the mft lcn, determine it now. */ 3939987da915Sopenharmony_ci if (!g_mft_lcn) { 3940987da915Sopenharmony_ci /* 3941987da915Sopenharmony_ci * We start at the higher value out of 16kiB and just after the 3942987da915Sopenharmony_ci * mft bitmap. 3943987da915Sopenharmony_ci */ 3944987da915Sopenharmony_ci g_mft_lcn = g_rl_mft_bmp[0].lcn + g_rl_mft_bmp[0].length; 3945987da915Sopenharmony_ci if (g_mft_lcn * g_vol->cluster_size < 16 * 1024) 3946987da915Sopenharmony_ci g_mft_lcn = (16 * 1024 + g_vol->cluster_size - 1) / 3947987da915Sopenharmony_ci g_vol->cluster_size; 3948987da915Sopenharmony_ci } 3949987da915Sopenharmony_ci ntfs_log_debug("$MFT logical cluster number = 0x%llx\n", g_mft_lcn); 3950987da915Sopenharmony_ci /* Determine MFT zone size. */ 3951987da915Sopenharmony_ci g_mft_zone_end = g_vol->nr_clusters; 3952987da915Sopenharmony_ci switch (opts.mft_zone_multiplier) { /* % of volume size in clusters */ 3953987da915Sopenharmony_ci case 4: 3954987da915Sopenharmony_ci g_mft_zone_end = g_mft_zone_end >> 1; /* 50% */ 3955987da915Sopenharmony_ci break; 3956987da915Sopenharmony_ci case 3: 3957987da915Sopenharmony_ci g_mft_zone_end = g_mft_zone_end * 3 >> 3;/* 37.5% */ 3958987da915Sopenharmony_ci break; 3959987da915Sopenharmony_ci case 2: 3960987da915Sopenharmony_ci g_mft_zone_end = g_mft_zone_end >> 2; /* 25% */ 3961987da915Sopenharmony_ci break; 3962987da915Sopenharmony_ci case 1: 3963987da915Sopenharmony_ci default: 3964987da915Sopenharmony_ci g_mft_zone_end = g_mft_zone_end >> 3; /* 12.5% */ 3965987da915Sopenharmony_ci break; 3966987da915Sopenharmony_ci } 3967987da915Sopenharmony_ci ntfs_log_debug("MFT zone size = %lldkiB\n", g_mft_zone_end << 3968987da915Sopenharmony_ci g_vol->cluster_size_bits >> 10 /* >> 10 == / 1024 */); 3969987da915Sopenharmony_ci /* 3970987da915Sopenharmony_ci * The mft zone begins with the mft data attribute, not at the beginning 3971987da915Sopenharmony_ci * of the device. 3972987da915Sopenharmony_ci */ 3973987da915Sopenharmony_ci g_mft_zone_end += g_mft_lcn; 3974987da915Sopenharmony_ci /* Create runlist for mft. */ 3975987da915Sopenharmony_ci g_rl_mft = ntfs_malloc(2 * sizeof(runlist)); 3976987da915Sopenharmony_ci if (!g_rl_mft) 3977987da915Sopenharmony_ci return FALSE; 3978987da915Sopenharmony_ci 3979987da915Sopenharmony_ci g_rl_mft[0].vcn = 0LL; 3980987da915Sopenharmony_ci g_rl_mft[0].lcn = g_mft_lcn; 3981987da915Sopenharmony_ci /* rounded up division by cluster size */ 3982987da915Sopenharmony_ci j = (g_mft_size + g_vol->cluster_size - 1) / g_vol->cluster_size; 3983987da915Sopenharmony_ci g_rl_mft[1].vcn = j; 3984987da915Sopenharmony_ci g_rl_mft[0].length = j; 3985987da915Sopenharmony_ci g_rl_mft[1].lcn = -1LL; 3986987da915Sopenharmony_ci g_rl_mft[1].length = 0LL; 3987987da915Sopenharmony_ci /* Allocate clusters for mft. */ 3988987da915Sopenharmony_ci bitmap_allocate(g_mft_lcn,j); 3989987da915Sopenharmony_ci /* Determine mftmirr_lcn (middle of volume). */ 3990987da915Sopenharmony_ci g_mftmirr_lcn = (opts.num_sectors * opts.sector_size >> 1) 3991987da915Sopenharmony_ci / g_vol->cluster_size; 3992987da915Sopenharmony_ci ntfs_log_debug("$MFTMirr logical cluster number = 0x%llx\n", 3993987da915Sopenharmony_ci g_mftmirr_lcn); 3994987da915Sopenharmony_ci /* Create runlist for mft mirror. */ 3995987da915Sopenharmony_ci g_rl_mftmirr = ntfs_malloc(2 * sizeof(runlist)); 3996987da915Sopenharmony_ci if (!g_rl_mftmirr) 3997987da915Sopenharmony_ci return FALSE; 3998987da915Sopenharmony_ci 3999987da915Sopenharmony_ci g_rl_mftmirr[0].vcn = 0LL; 4000987da915Sopenharmony_ci g_rl_mftmirr[0].lcn = g_mftmirr_lcn; 4001987da915Sopenharmony_ci /* 4002987da915Sopenharmony_ci * The mft mirror is either 4kb (the first four records) or one cluster 4003987da915Sopenharmony_ci * in size, which ever is bigger. In either case, it contains a 4004987da915Sopenharmony_ci * byte-for-byte identical copy of the beginning of the mft (i.e. either 4005987da915Sopenharmony_ci * the first four records (4kb) or the first cluster worth of records, 4006987da915Sopenharmony_ci * whichever is bigger). 4007987da915Sopenharmony_ci */ 4008987da915Sopenharmony_ci j = (4 * g_vol->mft_record_size + g_vol->cluster_size - 1) / g_vol->cluster_size; 4009987da915Sopenharmony_ci g_rl_mftmirr[1].vcn = j; 4010987da915Sopenharmony_ci g_rl_mftmirr[0].length = j; 4011987da915Sopenharmony_ci g_rl_mftmirr[1].lcn = -1LL; 4012987da915Sopenharmony_ci g_rl_mftmirr[1].length = 0LL; 4013987da915Sopenharmony_ci /* Allocate clusters for mft mirror. */ 4014987da915Sopenharmony_ci done = bitmap_allocate(g_mftmirr_lcn,j); 4015987da915Sopenharmony_ci g_logfile_lcn = g_mftmirr_lcn + j; 4016987da915Sopenharmony_ci ntfs_log_debug("$LogFile logical cluster number = 0x%llx\n", 4017987da915Sopenharmony_ci g_logfile_lcn); 4018987da915Sopenharmony_ci return (done); 4019987da915Sopenharmony_ci} 4020987da915Sopenharmony_ci 4021987da915Sopenharmony_ci/** 4022987da915Sopenharmony_ci * mkntfs_initialize_rl_logfile - 4023987da915Sopenharmony_ci */ 4024987da915Sopenharmony_cistatic BOOL mkntfs_initialize_rl_logfile(void) 4025987da915Sopenharmony_ci{ 4026987da915Sopenharmony_ci int j; 4027987da915Sopenharmony_ci u64 volume_size; 4028987da915Sopenharmony_ci 4029987da915Sopenharmony_ci /* Create runlist for log file. */ 4030987da915Sopenharmony_ci g_rl_logfile = ntfs_malloc(2 * sizeof(runlist)); 4031987da915Sopenharmony_ci if (!g_rl_logfile) 4032987da915Sopenharmony_ci return FALSE; 4033987da915Sopenharmony_ci 4034987da915Sopenharmony_ci 4035987da915Sopenharmony_ci volume_size = g_vol->nr_clusters << g_vol->cluster_size_bits; 4036987da915Sopenharmony_ci 4037987da915Sopenharmony_ci g_rl_logfile[0].vcn = 0LL; 4038987da915Sopenharmony_ci g_rl_logfile[0].lcn = g_logfile_lcn; 4039987da915Sopenharmony_ci /* 4040987da915Sopenharmony_ci * Determine logfile_size from volume_size (rounded up to a cluster), 4041987da915Sopenharmony_ci * making sure it does not overflow the end of the volume. 4042987da915Sopenharmony_ci */ 4043987da915Sopenharmony_ci if (volume_size < 2048LL * 1024) /* < 2MiB */ 4044987da915Sopenharmony_ci g_logfile_size = 256LL * 1024; /* -> 256kiB */ 4045987da915Sopenharmony_ci else if (volume_size < 4000000LL) /* < 4MB */ 4046987da915Sopenharmony_ci g_logfile_size = 512LL * 1024; /* -> 512kiB */ 4047987da915Sopenharmony_ci else if (volume_size <= 200LL * 1024 * 1024) /* < 200MiB */ 4048987da915Sopenharmony_ci g_logfile_size = 2048LL * 1024; /* -> 2MiB */ 4049987da915Sopenharmony_ci else { 4050987da915Sopenharmony_ci /* 4051987da915Sopenharmony_ci * FIXME: The $LogFile size is 64 MiB upwards from 12GiB but 4052987da915Sopenharmony_ci * the "200" divider below apparently approximates "100" or 4053987da915Sopenharmony_ci * some other value as the volume size decreases. For example: 4054987da915Sopenharmony_ci * Volume size LogFile size Ratio 4055987da915Sopenharmony_ci * 8799808 46048 191.100 4056987da915Sopenharmony_ci * 8603248 45072 190.877 4057987da915Sopenharmony_ci * 7341704 38768 189.375 4058987da915Sopenharmony_ci * 6144828 32784 187.433 4059987da915Sopenharmony_ci * 4192932 23024 182.111 4060987da915Sopenharmony_ci */ 4061987da915Sopenharmony_ci if (volume_size >= 12LL << 30) /* > 12GiB */ 4062987da915Sopenharmony_ci g_logfile_size = 64 << 20; /* -> 64MiB */ 4063987da915Sopenharmony_ci else 4064987da915Sopenharmony_ci g_logfile_size = (volume_size / 200) & 4065987da915Sopenharmony_ci ~(g_vol->cluster_size - 1); 4066987da915Sopenharmony_ci } 4067987da915Sopenharmony_ci j = g_logfile_size / g_vol->cluster_size; 4068987da915Sopenharmony_ci while (g_rl_logfile[0].lcn + j >= g_vol->nr_clusters) { 4069987da915Sopenharmony_ci /* 4070987da915Sopenharmony_ci * $Logfile would overflow volume. Need to make it smaller than 4071987da915Sopenharmony_ci * the standard size. It's ok as we are creating a non-standard 4072987da915Sopenharmony_ci * volume anyway if it is that small. 4073987da915Sopenharmony_ci */ 4074987da915Sopenharmony_ci g_logfile_size >>= 1; 4075987da915Sopenharmony_ci j = g_logfile_size / g_vol->cluster_size; 4076987da915Sopenharmony_ci } 4077987da915Sopenharmony_ci g_logfile_size = (g_logfile_size + g_vol->cluster_size - 1) & 4078987da915Sopenharmony_ci ~(g_vol->cluster_size - 1); 4079987da915Sopenharmony_ci ntfs_log_debug("$LogFile (journal) size = %ikiB\n", 4080987da915Sopenharmony_ci g_logfile_size / 1024); 4081987da915Sopenharmony_ci /* 4082987da915Sopenharmony_ci * FIXME: The 256kiB limit is arbitrary. Should find out what the real 4083987da915Sopenharmony_ci * minimum requirement for Windows is so it doesn't blue screen. 4084987da915Sopenharmony_ci */ 4085987da915Sopenharmony_ci if (g_logfile_size < 256 << 10) { 4086987da915Sopenharmony_ci ntfs_log_error("$LogFile would be created with invalid size. " 4087987da915Sopenharmony_ci "This is not allowed as it would cause Windows " 4088987da915Sopenharmony_ci "to blue screen and during boot.\n"); 4089987da915Sopenharmony_ci return FALSE; 4090987da915Sopenharmony_ci } 4091987da915Sopenharmony_ci g_rl_logfile[1].vcn = j; 4092987da915Sopenharmony_ci g_rl_logfile[0].length = j; 4093987da915Sopenharmony_ci g_rl_logfile[1].lcn = -1LL; 4094987da915Sopenharmony_ci g_rl_logfile[1].length = 0LL; 4095987da915Sopenharmony_ci /* Allocate clusters for log file. */ 4096987da915Sopenharmony_ci return (bitmap_allocate(g_logfile_lcn,j)); 4097987da915Sopenharmony_ci} 4098987da915Sopenharmony_ci 4099987da915Sopenharmony_ci/** 4100987da915Sopenharmony_ci * mkntfs_initialize_rl_boot - 4101987da915Sopenharmony_ci */ 4102987da915Sopenharmony_cistatic BOOL mkntfs_initialize_rl_boot(void) 4103987da915Sopenharmony_ci{ 4104987da915Sopenharmony_ci int j; 4105987da915Sopenharmony_ci /* Create runlist for $Boot. */ 4106987da915Sopenharmony_ci g_rl_boot = ntfs_malloc(2 * sizeof(runlist)); 4107987da915Sopenharmony_ci if (!g_rl_boot) 4108987da915Sopenharmony_ci return FALSE; 4109987da915Sopenharmony_ci 4110987da915Sopenharmony_ci g_rl_boot[0].vcn = 0LL; 4111987da915Sopenharmony_ci g_rl_boot[0].lcn = 0LL; 4112987da915Sopenharmony_ci /* 4113987da915Sopenharmony_ci * $Boot is always 8192 (0x2000) bytes or 1 cluster, whichever is 4114987da915Sopenharmony_ci * bigger. 4115987da915Sopenharmony_ci */ 4116987da915Sopenharmony_ci j = (8192 + g_vol->cluster_size - 1) / g_vol->cluster_size; 4117987da915Sopenharmony_ci g_rl_boot[1].vcn = j; 4118987da915Sopenharmony_ci g_rl_boot[0].length = j; 4119987da915Sopenharmony_ci g_rl_boot[1].lcn = -1LL; 4120987da915Sopenharmony_ci g_rl_boot[1].length = 0LL; 4121987da915Sopenharmony_ci /* Allocate clusters for $Boot. */ 4122987da915Sopenharmony_ci return (bitmap_allocate(0,j)); 4123987da915Sopenharmony_ci} 4124987da915Sopenharmony_ci 4125987da915Sopenharmony_ci/** 4126987da915Sopenharmony_ci * mkntfs_initialize_rl_bad - 4127987da915Sopenharmony_ci */ 4128987da915Sopenharmony_cistatic BOOL mkntfs_initialize_rl_bad(void) 4129987da915Sopenharmony_ci{ 4130987da915Sopenharmony_ci /* Create runlist for $BadClus, $DATA named stream $Bad. */ 4131987da915Sopenharmony_ci g_rl_bad = ntfs_malloc(2 * sizeof(runlist)); 4132987da915Sopenharmony_ci if (!g_rl_bad) 4133987da915Sopenharmony_ci return FALSE; 4134987da915Sopenharmony_ci 4135987da915Sopenharmony_ci g_rl_bad[0].vcn = 0LL; 4136987da915Sopenharmony_ci g_rl_bad[0].lcn = -1LL; 4137987da915Sopenharmony_ci /* 4138987da915Sopenharmony_ci * $BadClus named stream $Bad contains the whole volume as a single 4139987da915Sopenharmony_ci * sparse runlist entry. 4140987da915Sopenharmony_ci */ 4141987da915Sopenharmony_ci g_rl_bad[1].vcn = g_vol->nr_clusters; 4142987da915Sopenharmony_ci g_rl_bad[0].length = g_vol->nr_clusters; 4143987da915Sopenharmony_ci g_rl_bad[1].lcn = -1LL; 4144987da915Sopenharmony_ci g_rl_bad[1].length = 0LL; 4145987da915Sopenharmony_ci 4146987da915Sopenharmony_ci /* TODO: Mark bad blocks as such. */ 4147987da915Sopenharmony_ci return TRUE; 4148987da915Sopenharmony_ci} 4149987da915Sopenharmony_ci 4150987da915Sopenharmony_ci/** 4151987da915Sopenharmony_ci * mkntfs_fill_device_with_zeroes - 4152987da915Sopenharmony_ci */ 4153987da915Sopenharmony_cistatic BOOL mkntfs_fill_device_with_zeroes(void) 4154987da915Sopenharmony_ci{ 4155987da915Sopenharmony_ci /* 4156987da915Sopenharmony_ci * If not quick format, fill the device with 0s. 4157987da915Sopenharmony_ci * FIXME: Except bad blocks! (AIA) 4158987da915Sopenharmony_ci */ 4159987da915Sopenharmony_ci int i; 4160987da915Sopenharmony_ci ssize_t bw; 4161987da915Sopenharmony_ci unsigned long long position; 4162987da915Sopenharmony_ci float progress_inc = (float)g_vol->nr_clusters / 100; 4163987da915Sopenharmony_ci u64 volume_size; 4164987da915Sopenharmony_ci 4165987da915Sopenharmony_ci volume_size = g_vol->nr_clusters << g_vol->cluster_size_bits; 4166987da915Sopenharmony_ci 4167987da915Sopenharmony_ci ntfs_log_progress("Initializing device with zeroes: 0%%"); 4168987da915Sopenharmony_ci for (position = 0; position < (unsigned long long)g_vol->nr_clusters; 4169987da915Sopenharmony_ci position++) { 4170987da915Sopenharmony_ci if (!(position % (int)(progress_inc+1))) { 4171987da915Sopenharmony_ci ntfs_log_progress("\b\b\b\b%3.0f%%", position / 4172987da915Sopenharmony_ci progress_inc); 4173987da915Sopenharmony_ci } 4174987da915Sopenharmony_ci bw = mkntfs_write(g_vol->dev, g_buf, g_vol->cluster_size); 4175987da915Sopenharmony_ci if (bw != (ssize_t)g_vol->cluster_size) { 4176987da915Sopenharmony_ci if (bw != -1 || errno != EIO) { 4177987da915Sopenharmony_ci ntfs_log_error("This should not happen.\n"); 4178987da915Sopenharmony_ci return FALSE; 4179987da915Sopenharmony_ci } 4180987da915Sopenharmony_ci if (!position) { 4181987da915Sopenharmony_ci ntfs_log_error("Error: Cluster zero is bad. " 4182987da915Sopenharmony_ci "Cannot create NTFS file " 4183987da915Sopenharmony_ci "system.\n"); 4184987da915Sopenharmony_ci return FALSE; 4185987da915Sopenharmony_ci } 4186987da915Sopenharmony_ci /* Add the baddie to our bad blocks list. */ 4187987da915Sopenharmony_ci if (!append_to_bad_blocks(position)) 4188987da915Sopenharmony_ci return FALSE; 4189987da915Sopenharmony_ci ntfs_log_quiet("\nFound bad cluster (%lld). Adding to " 4190987da915Sopenharmony_ci "list of bad blocks.\nInitializing " 4191987da915Sopenharmony_ci "device with zeroes: %3.0f%%", position, 4192987da915Sopenharmony_ci position / progress_inc); 4193987da915Sopenharmony_ci /* Seek to next cluster. */ 4194987da915Sopenharmony_ci g_vol->dev->d_ops->seek(g_vol->dev, 4195987da915Sopenharmony_ci ((off_t)position + 1) * 4196987da915Sopenharmony_ci g_vol->cluster_size, SEEK_SET); 4197987da915Sopenharmony_ci } 4198987da915Sopenharmony_ci } 4199987da915Sopenharmony_ci ntfs_log_progress("\b\b\b\b100%%"); 4200987da915Sopenharmony_ci position = (volume_size & (g_vol->cluster_size - 1)) / 4201987da915Sopenharmony_ci opts.sector_size; 4202987da915Sopenharmony_ci for (i = 0; (unsigned long)i < position; i++) { 4203987da915Sopenharmony_ci bw = mkntfs_write(g_vol->dev, g_buf, opts.sector_size); 4204987da915Sopenharmony_ci if (bw != opts.sector_size) { 4205987da915Sopenharmony_ci if (bw != -1 || errno != EIO) { 4206987da915Sopenharmony_ci ntfs_log_error("This should not happen.\n"); 4207987da915Sopenharmony_ci return FALSE; 4208987da915Sopenharmony_ci } else if (i + 1ull == position) { 4209987da915Sopenharmony_ci ntfs_log_error("Error: Bad cluster found in " 4210987da915Sopenharmony_ci "location reserved for system " 4211987da915Sopenharmony_ci "file $Boot.\n"); 4212987da915Sopenharmony_ci return FALSE; 4213987da915Sopenharmony_ci } 4214987da915Sopenharmony_ci /* Seek to next sector. */ 4215987da915Sopenharmony_ci g_vol->dev->d_ops->seek(g_vol->dev, 4216987da915Sopenharmony_ci opts.sector_size, SEEK_CUR); 4217987da915Sopenharmony_ci } 4218987da915Sopenharmony_ci } 4219987da915Sopenharmony_ci ntfs_log_progress(" - Done.\n"); 4220987da915Sopenharmony_ci return TRUE; 4221987da915Sopenharmony_ci} 4222987da915Sopenharmony_ci 4223987da915Sopenharmony_ci/** 4224987da915Sopenharmony_ci * mkntfs_sync_index_record 4225987da915Sopenharmony_ci * 4226987da915Sopenharmony_ci * (ERSO) made a function out of this, but the reason for doing that 4227987da915Sopenharmony_ci * disappeared during coding.... 4228987da915Sopenharmony_ci */ 4229987da915Sopenharmony_cistatic BOOL mkntfs_sync_index_record(INDEX_ALLOCATION* idx, MFT_RECORD* m, 4230987da915Sopenharmony_ci ntfschar* name, u32 name_len) 4231987da915Sopenharmony_ci{ 4232987da915Sopenharmony_ci int i, err; 4233987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 4234987da915Sopenharmony_ci ATTR_RECORD *a; 4235987da915Sopenharmony_ci long long lw; 4236987da915Sopenharmony_ci runlist *rl_index = NULL; 4237987da915Sopenharmony_ci 4238987da915Sopenharmony_ci i = 5 * sizeof(ntfschar); 4239987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(NULL, m); 4240987da915Sopenharmony_ci if (!ctx) { 4241987da915Sopenharmony_ci ntfs_log_perror("Failed to allocate attribute search context"); 4242987da915Sopenharmony_ci return FALSE; 4243987da915Sopenharmony_ci } 4244987da915Sopenharmony_ci /* FIXME: This should be IGNORE_CASE! */ 4245987da915Sopenharmony_ci if (mkntfs_attr_lookup(AT_INDEX_ALLOCATION, name, name_len, 4246987da915Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx)) { 4247987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 4248987da915Sopenharmony_ci ntfs_log_error("BUG: $INDEX_ALLOCATION attribute not found.\n"); 4249987da915Sopenharmony_ci return FALSE; 4250987da915Sopenharmony_ci } 4251987da915Sopenharmony_ci a = ctx->attr; 4252987da915Sopenharmony_ci rl_index = ntfs_mapping_pairs_decompress(g_vol, a, NULL); 4253987da915Sopenharmony_ci if (!rl_index) { 4254987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 4255987da915Sopenharmony_ci ntfs_log_error("Failed to decompress runlist of $INDEX_ALLOCATION " 4256987da915Sopenharmony_ci "attribute.\n"); 4257987da915Sopenharmony_ci return FALSE; 4258987da915Sopenharmony_ci } 4259987da915Sopenharmony_ci if (sle64_to_cpu(a->initialized_size) < i) { 4260987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 4261987da915Sopenharmony_ci free(rl_index); 4262987da915Sopenharmony_ci ntfs_log_error("BUG: $INDEX_ALLOCATION attribute too short.\n"); 4263987da915Sopenharmony_ci return FALSE; 4264987da915Sopenharmony_ci } 4265987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 4266987da915Sopenharmony_ci i = sizeof(INDEX_BLOCK) - sizeof(INDEX_HEADER) + 4267987da915Sopenharmony_ci le32_to_cpu(idx->index.allocated_size); 4268987da915Sopenharmony_ci err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)idx, i); 4269987da915Sopenharmony_ci if (err) { 4270987da915Sopenharmony_ci free(rl_index); 4271987da915Sopenharmony_ci ntfs_log_error("ntfs_mst_pre_write_fixup() failed while " 4272987da915Sopenharmony_ci "syncing index block.\n"); 4273987da915Sopenharmony_ci return FALSE; 4274987da915Sopenharmony_ci } 4275987da915Sopenharmony_ci lw = ntfs_rlwrite(g_vol->dev, rl_index, (u8*)idx, i, NULL, 4276987da915Sopenharmony_ci WRITE_STANDARD); 4277987da915Sopenharmony_ci free(rl_index); 4278987da915Sopenharmony_ci if (lw != i) { 4279987da915Sopenharmony_ci ntfs_log_error("Error writing $INDEX_ALLOCATION.\n"); 4280987da915Sopenharmony_ci return FALSE; 4281987da915Sopenharmony_ci } 4282987da915Sopenharmony_ci /* No more changes to @idx below here so no need for fixup: */ 4283987da915Sopenharmony_ci /* ntfs_mst_post_write_fixup((NTFS_RECORD*)idx); */ 4284987da915Sopenharmony_ci return TRUE; 4285987da915Sopenharmony_ci} 4286987da915Sopenharmony_ci 4287987da915Sopenharmony_ci/** 4288987da915Sopenharmony_ci * create_file_volume - 4289987da915Sopenharmony_ci */ 4290987da915Sopenharmony_cistatic BOOL create_file_volume(MFT_RECORD *m, leMFT_REF root_ref, 4291987da915Sopenharmony_ci VOLUME_FLAGS fl, const GUID *volume_guid) 4292987da915Sopenharmony_ci{ 4293987da915Sopenharmony_ci int i, err; 4294987da915Sopenharmony_ci u8 *sd; 4295987da915Sopenharmony_ci 4296987da915Sopenharmony_ci ntfs_log_verbose("Creating $Volume (mft record 3)\n"); 4297987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 3 * g_vol->mft_record_size); 4298987da915Sopenharmony_ci err = create_hardlink(g_index_block, root_ref, m, 4299987da915Sopenharmony_ci MK_LE_MREF(FILE_Volume, FILE_Volume), 0LL, 0LL, 4300987da915Sopenharmony_ci FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, 4301987da915Sopenharmony_ci "$Volume", FILE_NAME_WIN32_AND_DOS); 4302987da915Sopenharmony_ci if (!err) { 4303987da915Sopenharmony_ci init_system_file_sd(FILE_Volume, &sd, &i); 4304987da915Sopenharmony_ci err = add_attr_sd(m, sd, i); 4305987da915Sopenharmony_ci } 4306987da915Sopenharmony_ci if (!err) 4307987da915Sopenharmony_ci err = add_attr_data(m, NULL, 0, CASE_SENSITIVE, 4308987da915Sopenharmony_ci const_cpu_to_le16(0), NULL, 0); 4309987da915Sopenharmony_ci if (!err) 4310987da915Sopenharmony_ci err = add_attr_vol_name(m, g_vol->vol_name, g_vol->vol_name ? 4311987da915Sopenharmony_ci strlen(g_vol->vol_name) : 0); 4312987da915Sopenharmony_ci if (!err) { 4313987da915Sopenharmony_ci if (fl & VOLUME_IS_DIRTY) 4314987da915Sopenharmony_ci ntfs_log_quiet("Setting the volume dirty so check " 4315987da915Sopenharmony_ci "disk runs on next reboot into " 4316987da915Sopenharmony_ci "Windows.\n"); 4317987da915Sopenharmony_ci err = add_attr_vol_info(m, fl, g_vol->major_ver, 4318987da915Sopenharmony_ci g_vol->minor_ver); 4319987da915Sopenharmony_ci } 4320987da915Sopenharmony_ci if (!err && opts.with_uuid) 4321987da915Sopenharmony_ci err = add_attr_object_id(m, volume_guid); 4322987da915Sopenharmony_ci if (err < 0) { 4323987da915Sopenharmony_ci ntfs_log_error("Couldn't create $Volume: %s\n", 4324987da915Sopenharmony_ci strerror(-err)); 4325987da915Sopenharmony_ci return FALSE; 4326987da915Sopenharmony_ci } 4327987da915Sopenharmony_ci return TRUE; 4328987da915Sopenharmony_ci} 4329987da915Sopenharmony_ci 4330987da915Sopenharmony_ci/** 4331987da915Sopenharmony_ci * create_backup_boot_sector 4332987da915Sopenharmony_ci * 4333987da915Sopenharmony_ci * Return 0 on success or -1 if it couldn't be created. 4334987da915Sopenharmony_ci */ 4335987da915Sopenharmony_cistatic int create_backup_boot_sector(u8 *buff) 4336987da915Sopenharmony_ci{ 4337987da915Sopenharmony_ci const char *s; 4338987da915Sopenharmony_ci ssize_t bw; 4339987da915Sopenharmony_ci int size, e; 4340987da915Sopenharmony_ci 4341987da915Sopenharmony_ci ntfs_log_verbose("Creating backup boot sector.\n"); 4342987da915Sopenharmony_ci /* 4343987da915Sopenharmony_ci * Write the first max(512, opts.sector_size) bytes from buf to the 4344987da915Sopenharmony_ci * last sector, but limit that to 8192 bytes of written data since that 4345987da915Sopenharmony_ci * is how big $Boot is (and how big our buffer is).. 4346987da915Sopenharmony_ci */ 4347987da915Sopenharmony_ci size = 512; 4348987da915Sopenharmony_ci if (size < opts.sector_size) 4349987da915Sopenharmony_ci size = opts.sector_size; 4350987da915Sopenharmony_ci if (g_vol->dev->d_ops->seek(g_vol->dev, (opts.num_sectors + 1) * 4351987da915Sopenharmony_ci opts.sector_size - size, SEEK_SET) == (off_t)-1) { 4352987da915Sopenharmony_ci ntfs_log_perror("Seek failed"); 4353987da915Sopenharmony_ci goto bb_err; 4354987da915Sopenharmony_ci } 4355987da915Sopenharmony_ci if (size > 8192) 4356987da915Sopenharmony_ci size = 8192; 4357987da915Sopenharmony_ci bw = mkntfs_write(g_vol->dev, buff, size); 4358987da915Sopenharmony_ci if (bw == size) 4359987da915Sopenharmony_ci return 0; 4360987da915Sopenharmony_ci e = errno; 4361987da915Sopenharmony_ci if (bw == -1LL) 4362987da915Sopenharmony_ci s = strerror(e); 4363987da915Sopenharmony_ci else 4364987da915Sopenharmony_ci s = "unknown error"; 4365987da915Sopenharmony_ci /* At least some 2.4 kernels return EIO instead of ENOSPC. */ 4366987da915Sopenharmony_ci if (bw != -1LL || (bw == -1LL && e != ENOSPC && e != EIO)) { 4367987da915Sopenharmony_ci ntfs_log_critical("Couldn't write backup boot sector: %s\n", s); 4368987da915Sopenharmony_ci return -1; 4369987da915Sopenharmony_ci } 4370987da915Sopenharmony_cibb_err: 4371987da915Sopenharmony_ci ntfs_log_error("Couldn't write backup boot sector. This is due to a " 4372987da915Sopenharmony_ci "limitation in the\nLinux kernel. This is not a major " 4373987da915Sopenharmony_ci "problem as Windows check disk will create the\n" 4374987da915Sopenharmony_ci "backup boot sector when it is run on your next boot " 4375987da915Sopenharmony_ci "into Windows.\n"); 4376987da915Sopenharmony_ci return -1; 4377987da915Sopenharmony_ci} 4378987da915Sopenharmony_ci 4379987da915Sopenharmony_ci/** 4380987da915Sopenharmony_ci * mkntfs_create_root_structures - 4381987da915Sopenharmony_ci */ 4382987da915Sopenharmony_cistatic BOOL mkntfs_create_root_structures(void) 4383987da915Sopenharmony_ci{ 4384987da915Sopenharmony_ci NTFS_BOOT_SECTOR *bs; 4385987da915Sopenharmony_ci MFT_RECORD *m; 4386987da915Sopenharmony_ci leMFT_REF root_ref; 4387987da915Sopenharmony_ci leMFT_REF extend_ref; 4388987da915Sopenharmony_ci int i; 4389987da915Sopenharmony_ci int j; 4390987da915Sopenharmony_ci int err; 4391987da915Sopenharmony_ci u8 *sd; 4392987da915Sopenharmony_ci FILE_ATTR_FLAGS extend_flags; 4393987da915Sopenharmony_ci VOLUME_FLAGS volume_flags = const_cpu_to_le16(0); 4394987da915Sopenharmony_ci int sectors_per_cluster; 4395987da915Sopenharmony_ci int nr_sysfiles; 4396987da915Sopenharmony_ci int buf_sds_first_size; 4397987da915Sopenharmony_ci char *buf_sds; 4398987da915Sopenharmony_ci GUID vol_guid; 4399987da915Sopenharmony_ci 4400987da915Sopenharmony_ci ntfs_log_quiet("Creating NTFS volume structures.\n"); 4401987da915Sopenharmony_ci nr_sysfiles = 27; 4402987da915Sopenharmony_ci /* 4403987da915Sopenharmony_ci * Setup an empty mft record. Note, we can just give 0 as the mft 4404987da915Sopenharmony_ci * reference as we are creating an NTFS 1.2 volume for which the mft 4405987da915Sopenharmony_ci * reference is ignored by ntfs_mft_record_layout(). 4406987da915Sopenharmony_ci * 4407987da915Sopenharmony_ci * Copy the mft record onto all 16 records in the buffer and setup the 4408987da915Sopenharmony_ci * sequence numbers of each system file to equal the mft record number 4409987da915Sopenharmony_ci * of that file (only for $MFT is the sequence number 1 rather than 0). 4410987da915Sopenharmony_ci */ 4411987da915Sopenharmony_ci for (i = 0; i < nr_sysfiles; i++) { 4412987da915Sopenharmony_ci if (ntfs_mft_record_layout(g_vol, 0, m = (MFT_RECORD *)(g_buf + 4413987da915Sopenharmony_ci i * g_vol->mft_record_size))) { 4414987da915Sopenharmony_ci ntfs_log_error("Failed to layout system mft records." 4415987da915Sopenharmony_ci "\n"); 4416987da915Sopenharmony_ci return FALSE; 4417987da915Sopenharmony_ci } 4418987da915Sopenharmony_ci if (i == 0 || i > 23) 4419987da915Sopenharmony_ci m->sequence_number = const_cpu_to_le16(1); 4420987da915Sopenharmony_ci else 4421987da915Sopenharmony_ci m->sequence_number = cpu_to_le16(i); 4422987da915Sopenharmony_ci } 4423987da915Sopenharmony_ci /* 4424987da915Sopenharmony_ci * If only one cluster contains all system files then 4425987da915Sopenharmony_ci * fill the rest of it with empty, formatted records. 4426987da915Sopenharmony_ci */ 4427987da915Sopenharmony_ci if (nr_sysfiles * (s32)g_vol->mft_record_size < g_mft_size) { 4428987da915Sopenharmony_ci for (i = nr_sysfiles; 4429987da915Sopenharmony_ci i * (s32)g_vol->mft_record_size < g_mft_size; i++) { 4430987da915Sopenharmony_ci m = (MFT_RECORD *)(g_buf + i * g_vol->mft_record_size); 4431987da915Sopenharmony_ci if (ntfs_mft_record_layout(g_vol, 0, m)) { 4432987da915Sopenharmony_ci ntfs_log_error("Failed to layout mft record." 4433987da915Sopenharmony_ci "\n"); 4434987da915Sopenharmony_ci return FALSE; 4435987da915Sopenharmony_ci } 4436987da915Sopenharmony_ci m->flags = const_cpu_to_le16(0); 4437987da915Sopenharmony_ci m->sequence_number = cpu_to_le16(i); 4438987da915Sopenharmony_ci } 4439987da915Sopenharmony_ci } 4440987da915Sopenharmony_ci /* 4441987da915Sopenharmony_ci * Create the 16 system files, adding the system information attribute 4442987da915Sopenharmony_ci * to each as well as marking them in use in the mft bitmap. 4443987da915Sopenharmony_ci */ 4444987da915Sopenharmony_ci for (i = 0; i < nr_sysfiles; i++) { 4445987da915Sopenharmony_ci le32 file_attrs; 4446987da915Sopenharmony_ci 4447987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); 4448987da915Sopenharmony_ci if (i < 16 || i > 23) { 4449987da915Sopenharmony_ci m->mft_record_number = cpu_to_le32(i); 4450987da915Sopenharmony_ci m->flags |= MFT_RECORD_IN_USE; 4451987da915Sopenharmony_ci ntfs_bit_set(g_mft_bitmap, 0LL + i, 1); 4452987da915Sopenharmony_ci } 4453987da915Sopenharmony_ci file_attrs = FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM; 4454987da915Sopenharmony_ci if (i == FILE_root) { 4455987da915Sopenharmony_ci file_attrs |= FILE_ATTR_ARCHIVE; 4456987da915Sopenharmony_ci if (opts.disable_indexing) 4457987da915Sopenharmony_ci file_attrs |= FILE_ATTR_NOT_CONTENT_INDEXED; 4458987da915Sopenharmony_ci if (opts.enable_compression) 4459987da915Sopenharmony_ci file_attrs |= FILE_ATTR_COMPRESSED; 4460987da915Sopenharmony_ci } 4461987da915Sopenharmony_ci /* setting specific security_id flag and */ 4462987da915Sopenharmony_ci /* file permissions for ntfs 3.x */ 4463987da915Sopenharmony_ci if (i == 0 || i == 1 || i == 2 || i == 6 || i == 8 || 4464987da915Sopenharmony_ci i == 10) { 4465987da915Sopenharmony_ci add_attr_std_info(m, file_attrs, 4466987da915Sopenharmony_ci const_cpu_to_le32(0x0100)); 4467987da915Sopenharmony_ci } else if (i == 9) { 4468987da915Sopenharmony_ci file_attrs |= FILE_ATTR_VIEW_INDEX_PRESENT; 4469987da915Sopenharmony_ci add_attr_std_info(m, file_attrs, 4470987da915Sopenharmony_ci const_cpu_to_le32(0x0101)); 4471987da915Sopenharmony_ci } else if (i == 11) { 4472987da915Sopenharmony_ci add_attr_std_info(m, file_attrs, 4473987da915Sopenharmony_ci const_cpu_to_le32(0x0101)); 4474987da915Sopenharmony_ci } else if (i == 24 || i == 25 || i == 26) { 4475987da915Sopenharmony_ci file_attrs |= FILE_ATTR_ARCHIVE; 4476987da915Sopenharmony_ci file_attrs |= FILE_ATTR_VIEW_INDEX_PRESENT; 4477987da915Sopenharmony_ci add_attr_std_info(m, file_attrs, 4478987da915Sopenharmony_ci const_cpu_to_le32(0x0101)); 4479987da915Sopenharmony_ci } else { 4480987da915Sopenharmony_ci add_attr_std_info(m, file_attrs, 4481987da915Sopenharmony_ci const_cpu_to_le32(0x00)); 4482987da915Sopenharmony_ci } 4483987da915Sopenharmony_ci } 4484987da915Sopenharmony_ci /* The root directory mft reference. */ 4485987da915Sopenharmony_ci root_ref = MK_LE_MREF(FILE_root, FILE_root); 4486987da915Sopenharmony_ci extend_ref = MK_LE_MREF(11,11); 4487987da915Sopenharmony_ci ntfs_log_verbose("Creating root directory (mft record 5)\n"); 4488987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 5 * g_vol->mft_record_size); 4489987da915Sopenharmony_ci m->flags |= MFT_RECORD_IS_DIRECTORY; 4490987da915Sopenharmony_ci m->link_count = cpu_to_le16(le16_to_cpu(m->link_count) + 1); 4491987da915Sopenharmony_ci err = add_attr_file_name(m, root_ref, 0LL, 0LL, 4492987da915Sopenharmony_ci FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | 4493987da915Sopenharmony_ci FILE_ATTR_I30_INDEX_PRESENT, 0, 0, ".", 4494987da915Sopenharmony_ci FILE_NAME_WIN32_AND_DOS); 4495987da915Sopenharmony_ci if (!err) { 4496987da915Sopenharmony_ci init_root_sd(&sd, &i); 4497987da915Sopenharmony_ci err = add_attr_sd(m, sd, i); 4498987da915Sopenharmony_ci } 4499987da915Sopenharmony_ci /* FIXME: This should be IGNORE_CASE */ 4500987da915Sopenharmony_ci if (!err) 4501987da915Sopenharmony_ci err = add_attr_index_root(m, "$I30", 4, CASE_SENSITIVE, 4502987da915Sopenharmony_ci AT_FILE_NAME, COLLATION_FILE_NAME, 4503987da915Sopenharmony_ci g_vol->indx_record_size); 4504987da915Sopenharmony_ci /* FIXME: This should be IGNORE_CASE */ 4505987da915Sopenharmony_ci if (!err) 4506987da915Sopenharmony_ci err = upgrade_to_large_index(m, "$I30", 4, CASE_SENSITIVE, 4507987da915Sopenharmony_ci &g_index_block); 4508987da915Sopenharmony_ci if (!err) { 4509987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 4510987da915Sopenharmony_ci ATTR_RECORD *a; 4511987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(NULL, m); 4512987da915Sopenharmony_ci if (!ctx) { 4513987da915Sopenharmony_ci ntfs_log_perror("Failed to allocate attribute search " 4514987da915Sopenharmony_ci "context"); 4515987da915Sopenharmony_ci return FALSE; 4516987da915Sopenharmony_ci } 4517987da915Sopenharmony_ci /* There is exactly one file name so this is ok. */ 4518987da915Sopenharmony_ci if (mkntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 4519987da915Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx)) { 4520987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 4521987da915Sopenharmony_ci ntfs_log_error("BUG: $FILE_NAME attribute not found." 4522987da915Sopenharmony_ci "\n"); 4523987da915Sopenharmony_ci return FALSE; 4524987da915Sopenharmony_ci } 4525987da915Sopenharmony_ci a = ctx->attr; 4526987da915Sopenharmony_ci err = insert_file_link_in_dir_index(g_index_block, root_ref, 4527987da915Sopenharmony_ci (FILE_NAME_ATTR*)((char*)a + 4528987da915Sopenharmony_ci le16_to_cpu(a->value_offset)), 4529987da915Sopenharmony_ci le32_to_cpu(a->value_length)); 4530987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 4531987da915Sopenharmony_ci } 4532987da915Sopenharmony_ci if (err) { 4533987da915Sopenharmony_ci ntfs_log_error("Couldn't create root directory: %s\n", 4534987da915Sopenharmony_ci strerror(-err)); 4535987da915Sopenharmony_ci return FALSE; 4536987da915Sopenharmony_ci } 4537987da915Sopenharmony_ci /* Add all other attributes, on a per-file basis for clarity. */ 4538987da915Sopenharmony_ci ntfs_log_verbose("Creating $MFT (mft record 0)\n"); 4539987da915Sopenharmony_ci m = (MFT_RECORD*)g_buf; 4540987da915Sopenharmony_ci err = add_attr_data_positioned(m, NULL, 0, CASE_SENSITIVE, 4541987da915Sopenharmony_ci const_cpu_to_le16(0), g_rl_mft, g_buf, g_mft_size); 4542987da915Sopenharmony_ci if (!err) 4543987da915Sopenharmony_ci err = create_hardlink(g_index_block, root_ref, m, 4544987da915Sopenharmony_ci MK_LE_MREF(FILE_MFT, 1), 4545987da915Sopenharmony_ci ((g_mft_size - 1) 4546987da915Sopenharmony_ci | (g_vol->cluster_size - 1)) + 1, 4547987da915Sopenharmony_ci g_mft_size, FILE_ATTR_HIDDEN | 4548987da915Sopenharmony_ci FILE_ATTR_SYSTEM, 0, 0, "$MFT", 4549987da915Sopenharmony_ci FILE_NAME_WIN32_AND_DOS); 4550987da915Sopenharmony_ci /* mft_bitmap is not modified in mkntfs; no need to sync it later. */ 4551987da915Sopenharmony_ci if (!err) 4552987da915Sopenharmony_ci err = add_attr_bitmap_positioned(m, NULL, 0, CASE_SENSITIVE, 4553987da915Sopenharmony_ci g_rl_mft_bmp, 4554987da915Sopenharmony_ci g_mft_bitmap, g_mft_bitmap_byte_size); 4555987da915Sopenharmony_ci if (err < 0) { 4556987da915Sopenharmony_ci ntfs_log_error("Couldn't create $MFT: %s\n", strerror(-err)); 4557987da915Sopenharmony_ci return FALSE; 4558987da915Sopenharmony_ci } 4559987da915Sopenharmony_ci ntfs_log_verbose("Creating $MFTMirr (mft record 1)\n"); 4560987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 1 * g_vol->mft_record_size); 4561987da915Sopenharmony_ci err = add_attr_data_positioned(m, NULL, 0, CASE_SENSITIVE, 4562987da915Sopenharmony_ci const_cpu_to_le16(0), g_rl_mftmirr, g_buf, 4563987da915Sopenharmony_ci g_rl_mftmirr[0].length * g_vol->cluster_size); 4564987da915Sopenharmony_ci if (!err) 4565987da915Sopenharmony_ci err = create_hardlink(g_index_block, root_ref, m, 4566987da915Sopenharmony_ci MK_LE_MREF(FILE_MFTMirr, FILE_MFTMirr), 4567987da915Sopenharmony_ci g_rl_mftmirr[0].length * g_vol->cluster_size, 4568987da915Sopenharmony_ci g_rl_mftmirr[0].length * g_vol->cluster_size, 4569987da915Sopenharmony_ci FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, 4570987da915Sopenharmony_ci "$MFTMirr", FILE_NAME_WIN32_AND_DOS); 4571987da915Sopenharmony_ci if (err < 0) { 4572987da915Sopenharmony_ci ntfs_log_error("Couldn't create $MFTMirr: %s\n", 4573987da915Sopenharmony_ci strerror(-err)); 4574987da915Sopenharmony_ci return FALSE; 4575987da915Sopenharmony_ci } 4576987da915Sopenharmony_ci ntfs_log_verbose("Creating $LogFile (mft record 2)\n"); 4577987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 2 * g_vol->mft_record_size); 4578987da915Sopenharmony_ci err = add_attr_data_positioned(m, NULL, 0, CASE_SENSITIVE, 4579987da915Sopenharmony_ci const_cpu_to_le16(0), g_rl_logfile, 4580987da915Sopenharmony_ci (const u8*)NULL, g_logfile_size); 4581987da915Sopenharmony_ci if (!err) 4582987da915Sopenharmony_ci err = create_hardlink(g_index_block, root_ref, m, 4583987da915Sopenharmony_ci MK_LE_MREF(FILE_LogFile, FILE_LogFile), 4584987da915Sopenharmony_ci g_logfile_size, g_logfile_size, 4585987da915Sopenharmony_ci FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, 4586987da915Sopenharmony_ci "$LogFile", FILE_NAME_WIN32_AND_DOS); 4587987da915Sopenharmony_ci if (err < 0) { 4588987da915Sopenharmony_ci ntfs_log_error("Couldn't create $LogFile: %s\n", 4589987da915Sopenharmony_ci strerror(-err)); 4590987da915Sopenharmony_ci return FALSE; 4591987da915Sopenharmony_ci } 4592987da915Sopenharmony_ci ntfs_log_verbose("Creating $AttrDef (mft record 4)\n"); 4593987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 4 * g_vol->mft_record_size); 4594987da915Sopenharmony_ci err = add_attr_data(m, NULL, 0, CASE_SENSITIVE, const_cpu_to_le16(0), 4595987da915Sopenharmony_ci (u8*)g_vol->attrdef, g_vol->attrdef_len); 4596987da915Sopenharmony_ci if (!err) 4597987da915Sopenharmony_ci err = create_hardlink(g_index_block, root_ref, m, 4598987da915Sopenharmony_ci MK_LE_MREF(FILE_AttrDef, FILE_AttrDef), 4599987da915Sopenharmony_ci (g_vol->attrdef_len + g_vol->cluster_size - 1) & 4600987da915Sopenharmony_ci ~(g_vol->cluster_size - 1), g_vol->attrdef_len, 4601987da915Sopenharmony_ci FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, 4602987da915Sopenharmony_ci "$AttrDef", FILE_NAME_WIN32_AND_DOS); 4603987da915Sopenharmony_ci if (!err) { 4604987da915Sopenharmony_ci init_system_file_sd(FILE_AttrDef, &sd, &i); 4605987da915Sopenharmony_ci err = add_attr_sd(m, sd, i); 4606987da915Sopenharmony_ci } 4607987da915Sopenharmony_ci if (err < 0) { 4608987da915Sopenharmony_ci ntfs_log_error("Couldn't create $AttrDef: %s\n", 4609987da915Sopenharmony_ci strerror(-err)); 4610987da915Sopenharmony_ci return FALSE; 4611987da915Sopenharmony_ci } 4612987da915Sopenharmony_ci ntfs_log_verbose("Creating $Bitmap (mft record 6)\n"); 4613987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 6 * g_vol->mft_record_size); 4614987da915Sopenharmony_ci /* the data attribute of $Bitmap must be non-resident or otherwise */ 4615987da915Sopenharmony_ci /* windows 2003 will regard the volume as corrupt (ERSO) */ 4616987da915Sopenharmony_ci if (!err) 4617987da915Sopenharmony_ci err = insert_non_resident_attr_in_mft_record(m, 4618987da915Sopenharmony_ci AT_DATA, NULL, 0, CASE_SENSITIVE, 4619987da915Sopenharmony_ci const_cpu_to_le16(0), (const u8*)NULL, 4620987da915Sopenharmony_ci g_lcn_bitmap_byte_size, WRITE_BITMAP); 4621987da915Sopenharmony_ci 4622987da915Sopenharmony_ci 4623987da915Sopenharmony_ci if (!err) 4624987da915Sopenharmony_ci err = create_hardlink(g_index_block, root_ref, m, 4625987da915Sopenharmony_ci MK_LE_MREF(FILE_Bitmap, FILE_Bitmap), 4626987da915Sopenharmony_ci (g_lcn_bitmap_byte_size + g_vol->cluster_size - 4627987da915Sopenharmony_ci 1) & ~(g_vol->cluster_size - 1), 4628987da915Sopenharmony_ci g_lcn_bitmap_byte_size, 4629987da915Sopenharmony_ci FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, 4630987da915Sopenharmony_ci "$Bitmap", FILE_NAME_WIN32_AND_DOS); 4631987da915Sopenharmony_ci if (err < 0) { 4632987da915Sopenharmony_ci ntfs_log_error("Couldn't create $Bitmap: %s\n", strerror(-err)); 4633987da915Sopenharmony_ci return FALSE; 4634987da915Sopenharmony_ci } 4635987da915Sopenharmony_ci ntfs_log_verbose("Creating $Boot (mft record 7)\n"); 4636987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 7 * g_vol->mft_record_size); 4637987da915Sopenharmony_ci bs = ntfs_calloc(8192); 4638987da915Sopenharmony_ci if (!bs) 4639987da915Sopenharmony_ci return FALSE; 4640987da915Sopenharmony_ci memcpy(bs, boot_array, sizeof(boot_array)); 4641987da915Sopenharmony_ci /* 4642987da915Sopenharmony_ci * Create the boot sector in bs. Note, that bs is already zeroed 4643987da915Sopenharmony_ci * in the boot sector section and that it has the NTFS OEM id/magic 4644987da915Sopenharmony_ci * already inserted, so no need to worry about these things. 4645987da915Sopenharmony_ci */ 4646987da915Sopenharmony_ci bs->bpb.bytes_per_sector = cpu_to_le16(opts.sector_size); 4647987da915Sopenharmony_ci sectors_per_cluster = g_vol->cluster_size / opts.sector_size; 4648987da915Sopenharmony_ci if (sectors_per_cluster > 128) 4649987da915Sopenharmony_ci bs->bpb.sectors_per_cluster = 257 - ffs(sectors_per_cluster); 4650987da915Sopenharmony_ci else 4651987da915Sopenharmony_ci bs->bpb.sectors_per_cluster = sectors_per_cluster; 4652987da915Sopenharmony_ci bs->bpb.media_type = 0xf8; /* hard disk */ 4653987da915Sopenharmony_ci bs->bpb.sectors_per_track = cpu_to_le16(opts.sectors_per_track); 4654987da915Sopenharmony_ci ntfs_log_debug("sectors per track = %ld (0x%lx)\n", 4655987da915Sopenharmony_ci opts.sectors_per_track, opts.sectors_per_track); 4656987da915Sopenharmony_ci bs->bpb.heads = cpu_to_le16(opts.heads); 4657987da915Sopenharmony_ci ntfs_log_debug("heads = %ld (0x%lx)\n", opts.heads, opts.heads); 4658987da915Sopenharmony_ci bs->bpb.hidden_sectors = cpu_to_le32(opts.part_start_sect); 4659987da915Sopenharmony_ci ntfs_log_debug("hidden sectors = %llu (0x%llx)\n", opts.part_start_sect, 4660987da915Sopenharmony_ci opts.part_start_sect); 4661987da915Sopenharmony_ci bs->physical_drive = 0x80; /* boot from hard disk */ 4662987da915Sopenharmony_ci bs->extended_boot_signature = 0x80; /* everybody sets this, so we do */ 4663987da915Sopenharmony_ci bs->number_of_sectors = cpu_to_sle64(opts.num_sectors); 4664987da915Sopenharmony_ci bs->mft_lcn = cpu_to_sle64(g_mft_lcn); 4665987da915Sopenharmony_ci bs->mftmirr_lcn = cpu_to_sle64(g_mftmirr_lcn); 4666987da915Sopenharmony_ci if (g_vol->mft_record_size >= g_vol->cluster_size) { 4667987da915Sopenharmony_ci bs->clusters_per_mft_record = g_vol->mft_record_size / 4668987da915Sopenharmony_ci g_vol->cluster_size; 4669987da915Sopenharmony_ci } else { 4670987da915Sopenharmony_ci bs->clusters_per_mft_record = -(ffs(g_vol->mft_record_size) - 4671987da915Sopenharmony_ci 1); 4672987da915Sopenharmony_ci if ((u32)(1 << -bs->clusters_per_mft_record) != 4673987da915Sopenharmony_ci g_vol->mft_record_size) { 4674987da915Sopenharmony_ci free(bs); 4675987da915Sopenharmony_ci ntfs_log_error("BUG: calculated clusters_per_mft_record" 4676987da915Sopenharmony_ci " is wrong (= 0x%x)\n", 4677987da915Sopenharmony_ci bs->clusters_per_mft_record); 4678987da915Sopenharmony_ci return FALSE; 4679987da915Sopenharmony_ci } 4680987da915Sopenharmony_ci } 4681987da915Sopenharmony_ci ntfs_log_debug("clusters per mft record = %i (0x%x)\n", 4682987da915Sopenharmony_ci bs->clusters_per_mft_record, 4683987da915Sopenharmony_ci bs->clusters_per_mft_record); 4684987da915Sopenharmony_ci if (g_vol->indx_record_size >= g_vol->cluster_size) { 4685987da915Sopenharmony_ci bs->clusters_per_index_record = g_vol->indx_record_size / 4686987da915Sopenharmony_ci g_vol->cluster_size; 4687987da915Sopenharmony_ci } else { 4688987da915Sopenharmony_ci bs->clusters_per_index_record = -g_vol->indx_record_size_bits; 4689987da915Sopenharmony_ci if ((1 << -bs->clusters_per_index_record) != 4690987da915Sopenharmony_ci (s32)g_vol->indx_record_size) { 4691987da915Sopenharmony_ci free(bs); 4692987da915Sopenharmony_ci ntfs_log_error("BUG: calculated " 4693987da915Sopenharmony_ci "clusters_per_index_record is wrong " 4694987da915Sopenharmony_ci "(= 0x%x)\n", 4695987da915Sopenharmony_ci bs->clusters_per_index_record); 4696987da915Sopenharmony_ci return FALSE; 4697987da915Sopenharmony_ci } 4698987da915Sopenharmony_ci } 4699987da915Sopenharmony_ci ntfs_log_debug("clusters per index block = %i (0x%x)\n", 4700987da915Sopenharmony_ci bs->clusters_per_index_record, 4701987da915Sopenharmony_ci bs->clusters_per_index_record); 4702987da915Sopenharmony_ci /* Generate a 64-bit random number for the serial number. */ 4703987da915Sopenharmony_ci bs->volume_serial_number = cpu_to_le64(((u64)random() << 32) | 4704987da915Sopenharmony_ci ((u64)random() & 0xffffffff)); 4705987da915Sopenharmony_ci /* 4706987da915Sopenharmony_ci * Leave zero for now as NT4 leaves it zero, too. If want it later, see 4707987da915Sopenharmony_ci * ../libntfs/bootsect.c for how to calculate it. 4708987da915Sopenharmony_ci */ 4709987da915Sopenharmony_ci bs->checksum = const_cpu_to_le32(0); 4710987da915Sopenharmony_ci /* Make sure the bootsector is ok. */ 4711987da915Sopenharmony_ci if (!ntfs_boot_sector_is_ntfs(bs)) { 4712987da915Sopenharmony_ci free(bs); 4713987da915Sopenharmony_ci ntfs_log_error("FATAL: Generated boot sector is invalid!\n"); 4714987da915Sopenharmony_ci return FALSE; 4715987da915Sopenharmony_ci } 4716987da915Sopenharmony_ci err = add_attr_data_positioned(m, NULL, 0, CASE_SENSITIVE, 4717987da915Sopenharmony_ci const_cpu_to_le16(0), g_rl_boot, (u8*)bs, 8192); 4718987da915Sopenharmony_ci if (!err) 4719987da915Sopenharmony_ci err = create_hardlink(g_index_block, root_ref, m, 4720987da915Sopenharmony_ci MK_LE_MREF(FILE_Boot, FILE_Boot), 4721987da915Sopenharmony_ci (8192 + g_vol->cluster_size - 1) & 4722987da915Sopenharmony_ci ~(g_vol->cluster_size - 1), 8192, 4723987da915Sopenharmony_ci FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, 4724987da915Sopenharmony_ci "$Boot", FILE_NAME_WIN32_AND_DOS); 4725987da915Sopenharmony_ci if (!err) { 4726987da915Sopenharmony_ci init_system_file_sd(FILE_Boot, &sd, &i); 4727987da915Sopenharmony_ci err = add_attr_sd(m, sd, i); 4728987da915Sopenharmony_ci } 4729987da915Sopenharmony_ci if (err < 0) { 4730987da915Sopenharmony_ci free(bs); 4731987da915Sopenharmony_ci ntfs_log_error("Couldn't create $Boot: %s\n", strerror(-err)); 4732987da915Sopenharmony_ci return FALSE; 4733987da915Sopenharmony_ci } 4734987da915Sopenharmony_ci if (create_backup_boot_sector((u8*)bs)) { 4735987da915Sopenharmony_ci /* 4736987da915Sopenharmony_ci * Pre-2.6 kernels couldn't access the last sector if it was 4737987da915Sopenharmony_ci * odd and we failed to set the device block size to the sector 4738987da915Sopenharmony_ci * size, hence we schedule chkdsk to create it. 4739987da915Sopenharmony_ci */ 4740987da915Sopenharmony_ci volume_flags |= VOLUME_IS_DIRTY; 4741987da915Sopenharmony_ci } 4742987da915Sopenharmony_ci free(bs); 4743987da915Sopenharmony_ci /* 4744987da915Sopenharmony_ci * We cheat a little here and if the user has requested all times to be 4745987da915Sopenharmony_ci * set to zero then we set the GUID to zero as well. This options is 4746987da915Sopenharmony_ci * only used for development purposes so that should be fine. 4747987da915Sopenharmony_ci */ 4748987da915Sopenharmony_ci if (!opts.use_epoch_time) { 4749987da915Sopenharmony_ci /* Generate a GUID for the volume. */ 4750987da915Sopenharmony_ci#ifdef ENABLE_UUID 4751987da915Sopenharmony_ci uuid_generate((void*)&vol_guid); 4752987da915Sopenharmony_ci#else 4753987da915Sopenharmony_ci ntfs_generate_guid(&vol_guid); 4754987da915Sopenharmony_ci#endif 4755987da915Sopenharmony_ci } else 4756987da915Sopenharmony_ci memset(&vol_guid, 0, sizeof(vol_guid)); 4757987da915Sopenharmony_ci if (!create_file_volume(m, root_ref, volume_flags, &vol_guid)) 4758987da915Sopenharmony_ci return FALSE; 4759987da915Sopenharmony_ci ntfs_log_verbose("Creating $BadClus (mft record 8)\n"); 4760987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 8 * g_vol->mft_record_size); 4761987da915Sopenharmony_ci /* FIXME: This should be IGNORE_CASE */ 4762987da915Sopenharmony_ci /* Create a sparse named stream of size equal to the volume size. */ 4763987da915Sopenharmony_ci err = add_attr_data_positioned(m, "$Bad", 4, CASE_SENSITIVE, 4764987da915Sopenharmony_ci const_cpu_to_le16(0), g_rl_bad, NULL, 4765987da915Sopenharmony_ci g_vol->nr_clusters * g_vol->cluster_size); 4766987da915Sopenharmony_ci if (!err) { 4767987da915Sopenharmony_ci err = add_attr_data(m, NULL, 0, CASE_SENSITIVE, 4768987da915Sopenharmony_ci const_cpu_to_le16(0), NULL, 0); 4769987da915Sopenharmony_ci } 4770987da915Sopenharmony_ci if (!err) { 4771987da915Sopenharmony_ci err = create_hardlink(g_index_block, root_ref, m, 4772987da915Sopenharmony_ci MK_LE_MREF(FILE_BadClus, FILE_BadClus), 4773987da915Sopenharmony_ci 0LL, 0LL, FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 4774987da915Sopenharmony_ci 0, 0, "$BadClus", FILE_NAME_WIN32_AND_DOS); 4775987da915Sopenharmony_ci } 4776987da915Sopenharmony_ci if (err < 0) { 4777987da915Sopenharmony_ci ntfs_log_error("Couldn't create $BadClus: %s\n", 4778987da915Sopenharmony_ci strerror(-err)); 4779987da915Sopenharmony_ci return FALSE; 4780987da915Sopenharmony_ci } 4781987da915Sopenharmony_ci /* create $Secure (NTFS 3.0+) */ 4782987da915Sopenharmony_ci ntfs_log_verbose("Creating $Secure (mft record 9)\n"); 4783987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 9 * g_vol->mft_record_size); 4784987da915Sopenharmony_ci m->flags |= MFT_RECORD_IS_VIEW_INDEX; 4785987da915Sopenharmony_ci if (!err) 4786987da915Sopenharmony_ci err = create_hardlink(g_index_block, root_ref, m, 4787987da915Sopenharmony_ci MK_LE_MREF(9, 9), 0LL, 0LL, 4788987da915Sopenharmony_ci FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | 4789987da915Sopenharmony_ci FILE_ATTR_VIEW_INDEX_PRESENT, 0, 0, 4790987da915Sopenharmony_ci "$Secure", FILE_NAME_WIN32_AND_DOS); 4791987da915Sopenharmony_ci buf_sds = NULL; 4792987da915Sopenharmony_ci buf_sds_first_size = 0; 4793987da915Sopenharmony_ci if (!err) { 4794987da915Sopenharmony_ci int buf_sds_size; 4795987da915Sopenharmony_ci 4796987da915Sopenharmony_ci buf_sds_first_size = 0xfc; 4797987da915Sopenharmony_ci buf_sds_size = 0x40000 + buf_sds_first_size; 4798987da915Sopenharmony_ci buf_sds = ntfs_calloc(buf_sds_size); 4799987da915Sopenharmony_ci if (!buf_sds) 4800987da915Sopenharmony_ci return FALSE; 4801987da915Sopenharmony_ci init_secure_sds(buf_sds); 4802987da915Sopenharmony_ci memcpy(buf_sds + 0x40000, buf_sds, buf_sds_first_size); 4803987da915Sopenharmony_ci err = add_attr_data(m, "$SDS", 4, CASE_SENSITIVE, 4804987da915Sopenharmony_ci const_cpu_to_le16(0), (u8*)buf_sds, 4805987da915Sopenharmony_ci buf_sds_size); 4806987da915Sopenharmony_ci } 4807987da915Sopenharmony_ci /* FIXME: This should be IGNORE_CASE */ 4808987da915Sopenharmony_ci if (!err) 4809987da915Sopenharmony_ci err = add_attr_index_root(m, "$SDH", 4, CASE_SENSITIVE, 4810987da915Sopenharmony_ci AT_UNUSED, COLLATION_NTOFS_SECURITY_HASH, 4811987da915Sopenharmony_ci g_vol->indx_record_size); 4812987da915Sopenharmony_ci /* FIXME: This should be IGNORE_CASE */ 4813987da915Sopenharmony_ci if (!err) 4814987da915Sopenharmony_ci err = add_attr_index_root(m, "$SII", 4, CASE_SENSITIVE, 4815987da915Sopenharmony_ci AT_UNUSED, COLLATION_NTOFS_ULONG, 4816987da915Sopenharmony_ci g_vol->indx_record_size); 4817987da915Sopenharmony_ci if (!err) 4818987da915Sopenharmony_ci err = initialize_secure(buf_sds, buf_sds_first_size, m); 4819987da915Sopenharmony_ci free(buf_sds); 4820987da915Sopenharmony_ci if (err < 0) { 4821987da915Sopenharmony_ci ntfs_log_error("Couldn't create $Secure: %s\n", 4822987da915Sopenharmony_ci strerror(-err)); 4823987da915Sopenharmony_ci return FALSE; 4824987da915Sopenharmony_ci } 4825987da915Sopenharmony_ci ntfs_log_verbose("Creating $UpCase (mft record 0xa)\n"); 4826987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 0xa * g_vol->mft_record_size); 4827987da915Sopenharmony_ci err = add_attr_data(m, NULL, 0, CASE_SENSITIVE, const_cpu_to_le16(0), 4828987da915Sopenharmony_ci (u8*)g_vol->upcase, g_vol->upcase_len << 1); 4829987da915Sopenharmony_ci /* 4830987da915Sopenharmony_ci * The $Info only exists since Windows 8, but it apparently 4831987da915Sopenharmony_ci * does not disturb chkdsk from earlier versions. 4832987da915Sopenharmony_ci */ 4833987da915Sopenharmony_ci if (!err) 4834987da915Sopenharmony_ci err = add_attr_data(m, "$Info", 5, CASE_SENSITIVE, 4835987da915Sopenharmony_ci const_cpu_to_le16(0), 4836987da915Sopenharmony_ci (u8*)g_upcaseinfo, sizeof(struct UPCASEINFO)); 4837987da915Sopenharmony_ci if (!err) 4838987da915Sopenharmony_ci err = create_hardlink(g_index_block, root_ref, m, 4839987da915Sopenharmony_ci MK_LE_MREF(FILE_UpCase, FILE_UpCase), 4840987da915Sopenharmony_ci ((g_vol->upcase_len << 1) + 4841987da915Sopenharmony_ci g_vol->cluster_size - 1) & 4842987da915Sopenharmony_ci ~(g_vol->cluster_size - 1), 4843987da915Sopenharmony_ci g_vol->upcase_len << 1, 4844987da915Sopenharmony_ci FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, 4845987da915Sopenharmony_ci "$UpCase", FILE_NAME_WIN32_AND_DOS); 4846987da915Sopenharmony_ci if (err < 0) { 4847987da915Sopenharmony_ci ntfs_log_error("Couldn't create $UpCase: %s\n", strerror(-err)); 4848987da915Sopenharmony_ci return FALSE; 4849987da915Sopenharmony_ci } 4850987da915Sopenharmony_ci ntfs_log_verbose("Creating $Extend (mft record 11)\n"); 4851987da915Sopenharmony_ci /* 4852987da915Sopenharmony_ci * $Extend index must be resident. Otherwise, w2k3 will regard the 4853987da915Sopenharmony_ci * volume as corrupt. (ERSO) 4854987da915Sopenharmony_ci */ 4855987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 11 * g_vol->mft_record_size); 4856987da915Sopenharmony_ci m->flags |= MFT_RECORD_IS_DIRECTORY; 4857987da915Sopenharmony_ci if (!err) 4858987da915Sopenharmony_ci err = create_hardlink(g_index_block, root_ref, m, 4859987da915Sopenharmony_ci MK_LE_MREF(11, 11), 0LL, 0LL, 4860987da915Sopenharmony_ci FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | 4861987da915Sopenharmony_ci FILE_ATTR_I30_INDEX_PRESENT, 0, 0, 4862987da915Sopenharmony_ci "$Extend", FILE_NAME_WIN32_AND_DOS); 4863987da915Sopenharmony_ci /* FIXME: This should be IGNORE_CASE */ 4864987da915Sopenharmony_ci if (!err) 4865987da915Sopenharmony_ci err = add_attr_index_root(m, "$I30", 4, CASE_SENSITIVE, 4866987da915Sopenharmony_ci AT_FILE_NAME, COLLATION_FILE_NAME, 4867987da915Sopenharmony_ci g_vol->indx_record_size); 4868987da915Sopenharmony_ci if (err < 0) { 4869987da915Sopenharmony_ci ntfs_log_error("Couldn't create $Extend: %s\n", 4870987da915Sopenharmony_ci strerror(-err)); 4871987da915Sopenharmony_ci return FALSE; 4872987da915Sopenharmony_ci } 4873987da915Sopenharmony_ci /* NTFS reserved system files (mft records 0xc-0xf) */ 4874987da915Sopenharmony_ci for (i = 0xc; i < 0x10; i++) { 4875987da915Sopenharmony_ci ntfs_log_verbose("Creating system file (mft record 0x%x)\n", i); 4876987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); 4877987da915Sopenharmony_ci err = add_attr_data(m, NULL, 0, CASE_SENSITIVE, 4878987da915Sopenharmony_ci const_cpu_to_le16(0), NULL, 0); 4879987da915Sopenharmony_ci if (!err) { 4880987da915Sopenharmony_ci init_system_file_sd(i, &sd, &j); 4881987da915Sopenharmony_ci err = add_attr_sd(m, sd, j); 4882987da915Sopenharmony_ci } 4883987da915Sopenharmony_ci if (err < 0) { 4884987da915Sopenharmony_ci ntfs_log_error("Couldn't create system file %i (0x%x): " 4885987da915Sopenharmony_ci "%s\n", i, i, strerror(-err)); 4886987da915Sopenharmony_ci return FALSE; 4887987da915Sopenharmony_ci } 4888987da915Sopenharmony_ci } 4889987da915Sopenharmony_ci /* create systemfiles for ntfs volumes (3.1) */ 4890987da915Sopenharmony_ci /* starting with file 24 (ignoring file 16-23) */ 4891987da915Sopenharmony_ci extend_flags = FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | 4892987da915Sopenharmony_ci FILE_ATTR_ARCHIVE | FILE_ATTR_VIEW_INDEX_PRESENT; 4893987da915Sopenharmony_ci ntfs_log_verbose("Creating $Quota (mft record 24)\n"); 4894987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 24 * g_vol->mft_record_size); 4895987da915Sopenharmony_ci m->flags |= MFT_RECORD_IS_4; 4896987da915Sopenharmony_ci m->flags |= MFT_RECORD_IS_VIEW_INDEX; 4897987da915Sopenharmony_ci if (!err) 4898987da915Sopenharmony_ci err = create_hardlink_res((MFT_RECORD*)(g_buf + 4899987da915Sopenharmony_ci 11 * g_vol->mft_record_size), extend_ref, m, 4900987da915Sopenharmony_ci MK_LE_MREF(24, 1), 0LL, 0LL, extend_flags, 4901987da915Sopenharmony_ci 0, 0, "$Quota", FILE_NAME_WIN32_AND_DOS); 4902987da915Sopenharmony_ci /* FIXME: This should be IGNORE_CASE */ 4903987da915Sopenharmony_ci if (!err) 4904987da915Sopenharmony_ci err = add_attr_index_root(m, "$Q", 2, CASE_SENSITIVE, AT_UNUSED, 4905987da915Sopenharmony_ci COLLATION_NTOFS_ULONG, g_vol->indx_record_size); 4906987da915Sopenharmony_ci /* FIXME: This should be IGNORE_CASE */ 4907987da915Sopenharmony_ci if (!err) 4908987da915Sopenharmony_ci err = add_attr_index_root(m, "$O", 2, CASE_SENSITIVE, AT_UNUSED, 4909987da915Sopenharmony_ci COLLATION_NTOFS_SID, g_vol->indx_record_size); 4910987da915Sopenharmony_ci if (!err) 4911987da915Sopenharmony_ci err = initialize_quota(m); 4912987da915Sopenharmony_ci if (err < 0) { 4913987da915Sopenharmony_ci ntfs_log_error("Couldn't create $Quota: %s\n", strerror(-err)); 4914987da915Sopenharmony_ci return FALSE; 4915987da915Sopenharmony_ci } 4916987da915Sopenharmony_ci ntfs_log_verbose("Creating $ObjId (mft record 25)\n"); 4917987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 25 * g_vol->mft_record_size); 4918987da915Sopenharmony_ci m->flags |= MFT_RECORD_IS_4; 4919987da915Sopenharmony_ci m->flags |= MFT_RECORD_IS_VIEW_INDEX; 4920987da915Sopenharmony_ci if (!err) 4921987da915Sopenharmony_ci err = create_hardlink_res((MFT_RECORD*)(g_buf + 4922987da915Sopenharmony_ci 11 * g_vol->mft_record_size), extend_ref, 4923987da915Sopenharmony_ci m, MK_LE_MREF(25, 1), 0LL, 0LL, 4924987da915Sopenharmony_ci extend_flags, 0, 0, "$ObjId", 4925987da915Sopenharmony_ci FILE_NAME_WIN32_AND_DOS); 4926987da915Sopenharmony_ci 4927987da915Sopenharmony_ci /* FIXME: This should be IGNORE_CASE */ 4928987da915Sopenharmony_ci if (!err) 4929987da915Sopenharmony_ci err = add_attr_index_root(m, "$O", 2, CASE_SENSITIVE, AT_UNUSED, 4930987da915Sopenharmony_ci COLLATION_NTOFS_ULONGS, 4931987da915Sopenharmony_ci g_vol->indx_record_size); 4932987da915Sopenharmony_ci if (!err && opts.with_uuid) 4933987da915Sopenharmony_ci err = index_obj_id_insert(m, &vol_guid, 4934987da915Sopenharmony_ci MK_LE_MREF(FILE_Volume, FILE_Volume)); 4935987da915Sopenharmony_ci if (err < 0) { 4936987da915Sopenharmony_ci ntfs_log_error("Couldn't create $ObjId: %s\n", 4937987da915Sopenharmony_ci strerror(-err)); 4938987da915Sopenharmony_ci return FALSE; 4939987da915Sopenharmony_ci } 4940987da915Sopenharmony_ci ntfs_log_verbose("Creating $Reparse (mft record 26)\n"); 4941987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 26 * g_vol->mft_record_size); 4942987da915Sopenharmony_ci m->flags |= MFT_RECORD_IS_4; 4943987da915Sopenharmony_ci m->flags |= MFT_RECORD_IS_VIEW_INDEX; 4944987da915Sopenharmony_ci if (!err) 4945987da915Sopenharmony_ci err = create_hardlink_res((MFT_RECORD*)(g_buf + 4946987da915Sopenharmony_ci 11 * g_vol->mft_record_size), 4947987da915Sopenharmony_ci extend_ref, m, MK_LE_MREF(26, 1), 4948987da915Sopenharmony_ci 0LL, 0LL, extend_flags, 0, 0, 4949987da915Sopenharmony_ci "$Reparse", FILE_NAME_WIN32_AND_DOS); 4950987da915Sopenharmony_ci /* FIXME: This should be IGNORE_CASE */ 4951987da915Sopenharmony_ci if (!err) 4952987da915Sopenharmony_ci err = add_attr_index_root(m, "$R", 2, CASE_SENSITIVE, AT_UNUSED, 4953987da915Sopenharmony_ci COLLATION_NTOFS_ULONGS, g_vol->indx_record_size); 4954987da915Sopenharmony_ci if (err < 0) { 4955987da915Sopenharmony_ci ntfs_log_error("Couldn't create $Reparse: %s\n", 4956987da915Sopenharmony_ci strerror(-err)); 4957987da915Sopenharmony_ci return FALSE; 4958987da915Sopenharmony_ci } 4959987da915Sopenharmony_ci return TRUE; 4960987da915Sopenharmony_ci} 4961987da915Sopenharmony_ci 4962987da915Sopenharmony_ci/** 4963987da915Sopenharmony_ci * mkntfs_redirect 4964987da915Sopenharmony_ci */ 4965987da915Sopenharmony_cistatic int mkntfs_redirect(struct mkntfs_options *opts2) 4966987da915Sopenharmony_ci{ 4967987da915Sopenharmony_ci u64 upcase_crc; 4968987da915Sopenharmony_ci int result = 1; 4969987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx = NULL; 4970987da915Sopenharmony_ci long long lw, pos; 4971987da915Sopenharmony_ci ATTR_RECORD *a; 4972987da915Sopenharmony_ci MFT_RECORD *m; 4973987da915Sopenharmony_ci int i, err; 4974987da915Sopenharmony_ci 4975987da915Sopenharmony_ci if (!opts2) { 4976987da915Sopenharmony_ci ntfs_log_error("Internal error: invalid parameters to mkntfs_options.\n"); 4977987da915Sopenharmony_ci goto done; 4978987da915Sopenharmony_ci } 4979987da915Sopenharmony_ci /* Initialize the random number generator with the current time. */ 4980987da915Sopenharmony_ci srandom(sle64_to_cpu(mkntfs_time())/10000000); 4981987da915Sopenharmony_ci /* Allocate and initialize ntfs_volume structure g_vol. */ 4982987da915Sopenharmony_ci g_vol = ntfs_volume_alloc(); 4983987da915Sopenharmony_ci if (!g_vol) { 4984987da915Sopenharmony_ci ntfs_log_perror("Could not create volume"); 4985987da915Sopenharmony_ci goto done; 4986987da915Sopenharmony_ci } 4987987da915Sopenharmony_ci /* Create NTFS 3.1 (Windows XP/Vista) volumes. */ 4988987da915Sopenharmony_ci g_vol->major_ver = 3; 4989987da915Sopenharmony_ci g_vol->minor_ver = 1; 4990987da915Sopenharmony_ci /* Transfer some options to the volume. */ 4991987da915Sopenharmony_ci if (opts.label) { 4992987da915Sopenharmony_ci g_vol->vol_name = strdup(opts.label); 4993987da915Sopenharmony_ci if (!g_vol->vol_name) { 4994987da915Sopenharmony_ci ntfs_log_perror("Could not copy volume name"); 4995987da915Sopenharmony_ci goto done; 4996987da915Sopenharmony_ci } 4997987da915Sopenharmony_ci } 4998987da915Sopenharmony_ci if (opts.cluster_size >= 0) 4999987da915Sopenharmony_ci g_vol->cluster_size = opts.cluster_size; 5000987da915Sopenharmony_ci /* Length is in unicode characters. */ 5001987da915Sopenharmony_ci g_vol->upcase_len = ntfs_upcase_build_default(&g_vol->upcase); 5002987da915Sopenharmony_ci /* Since Windows 8, there is a $Info stream in $UpCase */ 5003987da915Sopenharmony_ci g_upcaseinfo = 5004987da915Sopenharmony_ci (struct UPCASEINFO*)ntfs_malloc(sizeof(struct UPCASEINFO)); 5005987da915Sopenharmony_ci if (!g_vol->upcase_len || !g_upcaseinfo) 5006987da915Sopenharmony_ci goto done; 5007987da915Sopenharmony_ci /* If the CRC is correct, chkdsk does not warn about obsolete table */ 5008987da915Sopenharmony_ci crc64(0,(byte*)NULL,0); /* initialize the crc computation */ 5009987da915Sopenharmony_ci upcase_crc = crc64(0,(byte*)g_vol->upcase, 5010987da915Sopenharmony_ci g_vol->upcase_len * sizeof(ntfschar)); 5011987da915Sopenharmony_ci /* keep the version fields as zero */ 5012987da915Sopenharmony_ci memset(g_upcaseinfo, 0, sizeof(struct UPCASEINFO)); 5013987da915Sopenharmony_ci g_upcaseinfo->len = const_cpu_to_le32(sizeof(struct UPCASEINFO)); 5014987da915Sopenharmony_ci g_upcaseinfo->crc = cpu_to_le64(upcase_crc); 5015987da915Sopenharmony_ci g_vol->attrdef = ntfs_malloc(sizeof(attrdef_ntfs3x_array)); 5016987da915Sopenharmony_ci if (!g_vol->attrdef) { 5017987da915Sopenharmony_ci ntfs_log_perror("Could not create attrdef structure"); 5018987da915Sopenharmony_ci goto done; 5019987da915Sopenharmony_ci } 5020987da915Sopenharmony_ci memcpy(g_vol->attrdef, attrdef_ntfs3x_array, 5021987da915Sopenharmony_ci sizeof(attrdef_ntfs3x_array)); 5022987da915Sopenharmony_ci g_vol->attrdef_len = sizeof(attrdef_ntfs3x_array); 5023987da915Sopenharmony_ci /* Open the partition. */ 5024987da915Sopenharmony_ci if (!mkntfs_open_partition(g_vol)) 5025987da915Sopenharmony_ci goto done; 5026987da915Sopenharmony_ci /* 5027987da915Sopenharmony_ci * Decide on the sector size, cluster size, mft record and index record 5028987da915Sopenharmony_ci * sizes as well as the number of sectors/tracks/heads/size, etc. 5029987da915Sopenharmony_ci */ 5030987da915Sopenharmony_ci if (!mkntfs_override_vol_params(g_vol)) 5031987da915Sopenharmony_ci goto done; 5032987da915Sopenharmony_ci /* Initialize $Bitmap and $MFT/$BITMAP related stuff. */ 5033987da915Sopenharmony_ci if (!mkntfs_initialize_bitmaps()) 5034987da915Sopenharmony_ci goto done; 5035987da915Sopenharmony_ci /* Initialize MFT & set g_logfile_lcn. */ 5036987da915Sopenharmony_ci if (!mkntfs_initialize_rl_mft()) 5037987da915Sopenharmony_ci goto done; 5038987da915Sopenharmony_ci /* Initialize $LogFile. */ 5039987da915Sopenharmony_ci if (!mkntfs_initialize_rl_logfile()) 5040987da915Sopenharmony_ci goto done; 5041987da915Sopenharmony_ci /* Initialize $Boot. */ 5042987da915Sopenharmony_ci if (!mkntfs_initialize_rl_boot()) 5043987da915Sopenharmony_ci goto done; 5044987da915Sopenharmony_ci /* Allocate a buffer large enough to hold the mft. */ 5045987da915Sopenharmony_ci g_buf = ntfs_calloc(g_mft_size); 5046987da915Sopenharmony_ci if (!g_buf) 5047987da915Sopenharmony_ci goto done; 5048987da915Sopenharmony_ci /* Create runlist for $BadClus, $DATA named stream $Bad. */ 5049987da915Sopenharmony_ci if (!mkntfs_initialize_rl_bad()) 5050987da915Sopenharmony_ci goto done; 5051987da915Sopenharmony_ci /* If not quick format, fill the device with 0s. */ 5052987da915Sopenharmony_ci if (!opts.quick_format) { 5053987da915Sopenharmony_ci if (!mkntfs_fill_device_with_zeroes()) 5054987da915Sopenharmony_ci goto done; 5055987da915Sopenharmony_ci } 5056987da915Sopenharmony_ci /* Create NTFS volume structures. */ 5057987da915Sopenharmony_ci if (!mkntfs_create_root_structures()) 5058987da915Sopenharmony_ci goto done; 5059987da915Sopenharmony_ci /* 5060987da915Sopenharmony_ci * - Do not step onto bad blocks!!! 5061987da915Sopenharmony_ci * - If any bad blocks were specified or found, modify $BadClus, 5062987da915Sopenharmony_ci * allocating the bad clusters in $Bitmap. 5063987da915Sopenharmony_ci * - C&w bootsector backup bootsector (backup in last sector of the 5064987da915Sopenharmony_ci * partition). 5065987da915Sopenharmony_ci * - If NTFS 3.0+, c&w $Secure file and $Extend directory with the 5066987da915Sopenharmony_ci * corresponding special files in it, i.e. $ObjId, $Quota, $Reparse, 5067987da915Sopenharmony_ci * and $UsnJrnl. And others? Or not all necessary? 5068987da915Sopenharmony_ci * - RE: Populate $root with the system files (and $Extend directory if 5069987da915Sopenharmony_ci * applicable). Possibly should move this as far to the top as 5070987da915Sopenharmony_ci * possible and update during each subsequent c&w of each system file. 5071987da915Sopenharmony_ci */ 5072987da915Sopenharmony_ci ntfs_log_verbose("Syncing root directory index record.\n"); 5073987da915Sopenharmony_ci if (!mkntfs_sync_index_record(g_index_block, (MFT_RECORD*)(g_buf + 5 * 5074987da915Sopenharmony_ci g_vol->mft_record_size), NTFS_INDEX_I30, 4)) 5075987da915Sopenharmony_ci goto done; 5076987da915Sopenharmony_ci 5077987da915Sopenharmony_ci ntfs_log_verbose("Syncing $Bitmap.\n"); 5078987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + 6 * g_vol->mft_record_size); 5079987da915Sopenharmony_ci 5080987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(NULL, m); 5081987da915Sopenharmony_ci if (!ctx) { 5082987da915Sopenharmony_ci ntfs_log_perror("Could not create an attribute search context"); 5083987da915Sopenharmony_ci goto done; 5084987da915Sopenharmony_ci } 5085987da915Sopenharmony_ci 5086987da915Sopenharmony_ci if (mkntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, CASE_SENSITIVE, 5087987da915Sopenharmony_ci 0, NULL, 0, ctx)) { 5088987da915Sopenharmony_ci ntfs_log_error("BUG: $DATA attribute not found.\n"); 5089987da915Sopenharmony_ci goto done; 5090987da915Sopenharmony_ci } 5091987da915Sopenharmony_ci 5092987da915Sopenharmony_ci a = ctx->attr; 5093987da915Sopenharmony_ci if (a->non_resident) { 5094987da915Sopenharmony_ci runlist *rl = ntfs_mapping_pairs_decompress(g_vol, a, NULL); 5095987da915Sopenharmony_ci if (!rl) { 5096987da915Sopenharmony_ci ntfs_log_error("ntfs_mapping_pairs_decompress() failed\n"); 5097987da915Sopenharmony_ci goto done; 5098987da915Sopenharmony_ci } 5099987da915Sopenharmony_ci lw = ntfs_rlwrite(g_vol->dev, rl, (const u8*)NULL, 5100987da915Sopenharmony_ci g_lcn_bitmap_byte_size, NULL, WRITE_BITMAP); 5101987da915Sopenharmony_ci err = errno; 5102987da915Sopenharmony_ci free(rl); 5103987da915Sopenharmony_ci if (lw != g_lcn_bitmap_byte_size) { 5104987da915Sopenharmony_ci ntfs_log_error("ntfs_rlwrite: %s\n", lw == -1 ? 5105987da915Sopenharmony_ci strerror(err) : "unknown error"); 5106987da915Sopenharmony_ci goto done; 5107987da915Sopenharmony_ci } 5108987da915Sopenharmony_ci } else { 5109987da915Sopenharmony_ci /* Error : the bitmap must be created non resident */ 5110987da915Sopenharmony_ci ntfs_log_error("Error : the global bitmap is resident\n"); 5111987da915Sopenharmony_ci goto done; 5112987da915Sopenharmony_ci } 5113987da915Sopenharmony_ci 5114987da915Sopenharmony_ci /* 5115987da915Sopenharmony_ci * No need to sync $MFT/$BITMAP as that has never been modified since 5116987da915Sopenharmony_ci * its creation. 5117987da915Sopenharmony_ci */ 5118987da915Sopenharmony_ci ntfs_log_verbose("Syncing $MFT.\n"); 5119987da915Sopenharmony_ci pos = g_mft_lcn * g_vol->cluster_size; 5120987da915Sopenharmony_ci lw = 1; 5121987da915Sopenharmony_ci for (i = 0; i < g_mft_size / (s32)g_vol->mft_record_size; i++) { 5122987da915Sopenharmony_ci if (!opts.no_action) 5123987da915Sopenharmony_ci lw = ntfs_mst_pwrite(g_vol->dev, pos, 1, g_vol->mft_record_size, g_buf + i * g_vol->mft_record_size); 5124987da915Sopenharmony_ci if (lw != 1) { 5125987da915Sopenharmony_ci ntfs_log_error("ntfs_mst_pwrite: %s\n", lw == -1 ? 5126987da915Sopenharmony_ci strerror(errno) : "unknown error"); 5127987da915Sopenharmony_ci goto done; 5128987da915Sopenharmony_ci } 5129987da915Sopenharmony_ci pos += g_vol->mft_record_size; 5130987da915Sopenharmony_ci } 5131987da915Sopenharmony_ci ntfs_log_verbose("Updating $MFTMirr.\n"); 5132987da915Sopenharmony_ci pos = g_mftmirr_lcn * g_vol->cluster_size; 5133987da915Sopenharmony_ci lw = 1; 5134987da915Sopenharmony_ci for (i = 0; i < g_rl_mftmirr[0].length * g_vol->cluster_size / g_vol->mft_record_size; i++) { 5135987da915Sopenharmony_ci m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); 5136987da915Sopenharmony_ci /* 5137987da915Sopenharmony_ci * Decrement the usn by one, so it becomes the same as the one 5138987da915Sopenharmony_ci * in $MFT once it is mst protected. - This is as we need the 5139987da915Sopenharmony_ci * $MFTMirr to have the exact same byte by byte content as 5140987da915Sopenharmony_ci * $MFT, rather than just equivalent meaning content. 5141987da915Sopenharmony_ci */ 5142987da915Sopenharmony_ci if (ntfs_mft_usn_dec(m)) { 5143987da915Sopenharmony_ci ntfs_log_error("ntfs_mft_usn_dec"); 5144987da915Sopenharmony_ci goto done; 5145987da915Sopenharmony_ci } 5146987da915Sopenharmony_ci if (!opts.no_action) 5147987da915Sopenharmony_ci lw = ntfs_mst_pwrite(g_vol->dev, pos, 1, g_vol->mft_record_size, g_buf + i * g_vol->mft_record_size); 5148987da915Sopenharmony_ci if (lw != 1) { 5149987da915Sopenharmony_ci ntfs_log_error("ntfs_mst_pwrite: %s\n", lw == -1 ? 5150987da915Sopenharmony_ci strerror(errno) : "unknown error"); 5151987da915Sopenharmony_ci goto done; 5152987da915Sopenharmony_ci } 5153987da915Sopenharmony_ci pos += g_vol->mft_record_size; 5154987da915Sopenharmony_ci } 5155987da915Sopenharmony_ci ntfs_log_verbose("Syncing device.\n"); 5156987da915Sopenharmony_ci if (g_vol->dev->d_ops->sync(g_vol->dev)) { 5157987da915Sopenharmony_ci ntfs_log_error("Syncing device. FAILED"); 5158987da915Sopenharmony_ci goto done; 5159987da915Sopenharmony_ci } 5160987da915Sopenharmony_ci ntfs_log_quiet("mkntfs completed successfully. Have a nice day.\n"); 5161987da915Sopenharmony_ci result = 0; 5162987da915Sopenharmony_cidone: 5163987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 5164987da915Sopenharmony_ci mkntfs_cleanup(); /* Device is unlocked and closed here */ 5165987da915Sopenharmony_ci return result; 5166987da915Sopenharmony_ci} 5167987da915Sopenharmony_ci 5168987da915Sopenharmony_ci 5169987da915Sopenharmony_ci/** 5170987da915Sopenharmony_ci * main - Begin here 5171987da915Sopenharmony_ci * 5172987da915Sopenharmony_ci * Start from here. 5173987da915Sopenharmony_ci * 5174987da915Sopenharmony_ci * Return: 0 Success, the program worked 5175987da915Sopenharmony_ci * 1 Error, something went wrong 5176987da915Sopenharmony_ci */ 5177987da915Sopenharmony_ciint main(int argc, char *argv[]) 5178987da915Sopenharmony_ci{ 5179987da915Sopenharmony_ci int result = 1; 5180987da915Sopenharmony_ci 5181987da915Sopenharmony_ci ntfs_log_set_handler(ntfs_log_handler_outerr); 5182987da915Sopenharmony_ci utils_set_locale(); 5183987da915Sopenharmony_ci 5184987da915Sopenharmony_ci mkntfs_init_options(&opts); /* Set up the options */ 5185987da915Sopenharmony_ci 5186987da915Sopenharmony_ci /* Read the command line options */ 5187987da915Sopenharmony_ci result = mkntfs_parse_options(argc, argv, &opts); 5188987da915Sopenharmony_ci 5189987da915Sopenharmony_ci if (result < 0) 5190987da915Sopenharmony_ci result = mkntfs_redirect(&opts); 5191987da915Sopenharmony_ci 5192987da915Sopenharmony_ci return result; 5193987da915Sopenharmony_ci} 5194