1987da915Sopenharmony_ci/** 2987da915Sopenharmony_ci * mft.c - Mft record handling code. Originated from the Linux-NTFS project. 3987da915Sopenharmony_ci * 4987da915Sopenharmony_ci * Copyright (c) 2000-2004 Anton Altaparmakov 5987da915Sopenharmony_ci * Copyright (c) 2004-2005 Richard Russon 6987da915Sopenharmony_ci * Copyright (c) 2004-2008 Szabolcs Szakacsits 7987da915Sopenharmony_ci * Copyright (c) 2005 Yura Pakhuchiy 8987da915Sopenharmony_ci * Copyright (c) 2014-2021 Jean-Pierre Andre 9987da915Sopenharmony_ci * 10987da915Sopenharmony_ci * This program/include file is free software; you can redistribute it and/or 11987da915Sopenharmony_ci * modify it under the terms of the GNU General Public License as published 12987da915Sopenharmony_ci * by the Free Software Foundation; either version 2 of the License, or 13987da915Sopenharmony_ci * (at your option) any later version. 14987da915Sopenharmony_ci * 15987da915Sopenharmony_ci * This program/include file is distributed in the hope that it will be 16987da915Sopenharmony_ci * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 17987da915Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18987da915Sopenharmony_ci * GNU General Public License for more details. 19987da915Sopenharmony_ci * 20987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License 21987da915Sopenharmony_ci * along with this program (in the main directory of the NTFS-3G 22987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software 23987da915Sopenharmony_ci * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24987da915Sopenharmony_ci */ 25987da915Sopenharmony_ci 26987da915Sopenharmony_ci#ifdef HAVE_CONFIG_H 27987da915Sopenharmony_ci#include "config.h" 28987da915Sopenharmony_ci#endif 29987da915Sopenharmony_ci 30987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H 31987da915Sopenharmony_ci#include <stdlib.h> 32987da915Sopenharmony_ci#endif 33987da915Sopenharmony_ci#ifdef HAVE_STDIO_H 34987da915Sopenharmony_ci#include <stdio.h> 35987da915Sopenharmony_ci#endif 36987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H 37987da915Sopenharmony_ci#include <errno.h> 38987da915Sopenharmony_ci#endif 39987da915Sopenharmony_ci#ifdef HAVE_STRING_H 40987da915Sopenharmony_ci#include <string.h> 41987da915Sopenharmony_ci#endif 42987da915Sopenharmony_ci#ifdef HAVE_LIMITS_H 43987da915Sopenharmony_ci#include <limits.h> 44987da915Sopenharmony_ci#endif 45987da915Sopenharmony_ci#include <time.h> 46987da915Sopenharmony_ci 47987da915Sopenharmony_ci#include "compat.h" 48987da915Sopenharmony_ci#include "types.h" 49987da915Sopenharmony_ci#include "device.h" 50987da915Sopenharmony_ci#include "debug.h" 51987da915Sopenharmony_ci#include "bitmap.h" 52987da915Sopenharmony_ci#include "attrib.h" 53987da915Sopenharmony_ci#include "inode.h" 54987da915Sopenharmony_ci#include "volume.h" 55987da915Sopenharmony_ci#include "layout.h" 56987da915Sopenharmony_ci#include "lcnalloc.h" 57987da915Sopenharmony_ci#include "mft.h" 58987da915Sopenharmony_ci#include "logging.h" 59987da915Sopenharmony_ci#include "misc.h" 60987da915Sopenharmony_ci 61987da915Sopenharmony_ci/** 62987da915Sopenharmony_ci * ntfs_mft_records_read - read records from the mft from disk 63987da915Sopenharmony_ci * @vol: volume to read from 64987da915Sopenharmony_ci * @mref: starting mft record number to read 65987da915Sopenharmony_ci * @count: number of mft records to read 66987da915Sopenharmony_ci * @b: output data buffer 67987da915Sopenharmony_ci * 68987da915Sopenharmony_ci * Read @count mft records starting at @mref from volume @vol into buffer 69987da915Sopenharmony_ci * @b. Return 0 on success or -1 on error, with errno set to the error 70987da915Sopenharmony_ci * code. 71987da915Sopenharmony_ci * 72987da915Sopenharmony_ci * If any of the records exceed the initialized size of the $MFT/$DATA 73987da915Sopenharmony_ci * attribute, i.e. they cannot possibly be allocated mft records, assume this 74987da915Sopenharmony_ci * is a bug and return error code ESPIPE. 75987da915Sopenharmony_ci * 76987da915Sopenharmony_ci * The read mft records are mst deprotected and are hence ready to use. The 77987da915Sopenharmony_ci * caller should check each record with is_baad_record() in case mst 78987da915Sopenharmony_ci * deprotection failed. 79987da915Sopenharmony_ci * 80987da915Sopenharmony_ci * NOTE: @b has to be at least of size @count * vol->mft_record_size. 81987da915Sopenharmony_ci */ 82987da915Sopenharmony_ciint ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref, 83987da915Sopenharmony_ci const s64 count, MFT_RECORD *b) 84987da915Sopenharmony_ci{ 85987da915Sopenharmony_ci s64 br; 86987da915Sopenharmony_ci VCN m; 87987da915Sopenharmony_ci 88987da915Sopenharmony_ci ntfs_log_trace("inode %llu\n", (unsigned long long)MREF(mref)); 89987da915Sopenharmony_ci 90987da915Sopenharmony_ci if (!vol || !vol->mft_na || !b || count < 0) { 91987da915Sopenharmony_ci errno = EINVAL; 92987da915Sopenharmony_ci ntfs_log_perror("%s: b=%p count=%lld mft=%llu", __FUNCTION__, 93987da915Sopenharmony_ci b, (long long)count, (unsigned long long)MREF(mref)); 94987da915Sopenharmony_ci return -1; 95987da915Sopenharmony_ci } 96987da915Sopenharmony_ci m = MREF(mref); 97987da915Sopenharmony_ci /* Refuse to read non-allocated mft records. */ 98987da915Sopenharmony_ci if (m + count > vol->mft_na->initialized_size >> 99987da915Sopenharmony_ci vol->mft_record_size_bits) { 100987da915Sopenharmony_ci errno = ESPIPE; 101987da915Sopenharmony_ci ntfs_log_perror("Trying to read non-allocated mft records " 102987da915Sopenharmony_ci "(%lld > %lld)", (long long)m + count, 103987da915Sopenharmony_ci (long long)vol->mft_na->initialized_size >> 104987da915Sopenharmony_ci vol->mft_record_size_bits); 105987da915Sopenharmony_ci return -1; 106987da915Sopenharmony_ci } 107987da915Sopenharmony_ci br = ntfs_attr_mst_pread(vol->mft_na, m << vol->mft_record_size_bits, 108987da915Sopenharmony_ci count, vol->mft_record_size, b); 109987da915Sopenharmony_ci if (br != count) { 110987da915Sopenharmony_ci if (br != -1) 111987da915Sopenharmony_ci errno = EIO; 112987da915Sopenharmony_ci ntfs_log_perror("Failed to read of MFT, mft=%llu count=%lld " 113987da915Sopenharmony_ci "br=%lld", (long long)m, (long long)count, 114987da915Sopenharmony_ci (long long)br); 115987da915Sopenharmony_ci return -1; 116987da915Sopenharmony_ci } 117987da915Sopenharmony_ci return 0; 118987da915Sopenharmony_ci} 119987da915Sopenharmony_ci 120987da915Sopenharmony_ci/** 121987da915Sopenharmony_ci * ntfs_mft_records_write - write mft records to disk 122987da915Sopenharmony_ci * @vol: volume to write to 123987da915Sopenharmony_ci * @mref: starting mft record number to write 124987da915Sopenharmony_ci * @count: number of mft records to write 125987da915Sopenharmony_ci * @b: data buffer containing the mft records to write 126987da915Sopenharmony_ci * 127987da915Sopenharmony_ci * Write @count mft records starting at @mref from data buffer @b to volume 128987da915Sopenharmony_ci * @vol. Return 0 on success or -1 on error, with errno set to the error code. 129987da915Sopenharmony_ci * 130987da915Sopenharmony_ci * If any of the records exceed the initialized size of the $MFT/$DATA 131987da915Sopenharmony_ci * attribute, i.e. they cannot possibly be allocated mft records, assume this 132987da915Sopenharmony_ci * is a bug and return error code ESPIPE. 133987da915Sopenharmony_ci * 134987da915Sopenharmony_ci * Before the mft records are written, they are mst protected. After the write, 135987da915Sopenharmony_ci * they are deprotected again, thus resulting in an increase in the update 136987da915Sopenharmony_ci * sequence number inside the data buffer @b. 137987da915Sopenharmony_ci * 138987da915Sopenharmony_ci * If any mft records are written which are also represented in the mft mirror 139987da915Sopenharmony_ci * $MFTMirr, we make a copy of the relevant parts of the data buffer @b into a 140987da915Sopenharmony_ci * temporary buffer before we do the actual write. Then if at least one mft 141987da915Sopenharmony_ci * record was successfully written, we write the appropriate mft records from 142987da915Sopenharmony_ci * the copied buffer to the mft mirror, too. 143987da915Sopenharmony_ci */ 144987da915Sopenharmony_ciint ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref, 145987da915Sopenharmony_ci const s64 count, MFT_RECORD *b) 146987da915Sopenharmony_ci{ 147987da915Sopenharmony_ci s64 bw; 148987da915Sopenharmony_ci VCN m; 149987da915Sopenharmony_ci void *bmirr = NULL; 150987da915Sopenharmony_ci int cnt = 0, res = 0; 151987da915Sopenharmony_ci 152987da915Sopenharmony_ci if (!vol || !vol->mft_na || vol->mftmirr_size <= 0 || !b || count < 0) { 153987da915Sopenharmony_ci errno = EINVAL; 154987da915Sopenharmony_ci return -1; 155987da915Sopenharmony_ci } 156987da915Sopenharmony_ci m = MREF(mref); 157987da915Sopenharmony_ci /* Refuse to write non-allocated mft records. */ 158987da915Sopenharmony_ci if (m + count > vol->mft_na->initialized_size >> 159987da915Sopenharmony_ci vol->mft_record_size_bits) { 160987da915Sopenharmony_ci errno = ESPIPE; 161987da915Sopenharmony_ci ntfs_log_perror("Trying to write non-allocated mft records " 162987da915Sopenharmony_ci "(%lld > %lld)", (long long)m + count, 163987da915Sopenharmony_ci (long long)vol->mft_na->initialized_size >> 164987da915Sopenharmony_ci vol->mft_record_size_bits); 165987da915Sopenharmony_ci return -1; 166987da915Sopenharmony_ci } 167987da915Sopenharmony_ci if (m < vol->mftmirr_size) { 168987da915Sopenharmony_ci if (!vol->mftmirr_na) { 169987da915Sopenharmony_ci errno = EINVAL; 170987da915Sopenharmony_ci return -1; 171987da915Sopenharmony_ci } 172987da915Sopenharmony_ci cnt = vol->mftmirr_size - m; 173987da915Sopenharmony_ci if (cnt > count) 174987da915Sopenharmony_ci cnt = count; 175987da915Sopenharmony_ci if ((m + cnt) > vol->mftmirr_na->initialized_size >> 176987da915Sopenharmony_ci vol->mft_record_size_bits) { 177987da915Sopenharmony_ci errno = ESPIPE; 178987da915Sopenharmony_ci ntfs_log_perror("Trying to write non-allocated mftmirr" 179987da915Sopenharmony_ci " records (%lld > %lld)", (long long)m + cnt, 180987da915Sopenharmony_ci (long long)vol->mftmirr_na->initialized_size >> 181987da915Sopenharmony_ci vol->mft_record_size_bits); 182987da915Sopenharmony_ci return -1; 183987da915Sopenharmony_ci } 184987da915Sopenharmony_ci bmirr = ntfs_malloc(cnt * vol->mft_record_size); 185987da915Sopenharmony_ci if (!bmirr) 186987da915Sopenharmony_ci return -1; 187987da915Sopenharmony_ci memcpy(bmirr, b, cnt * vol->mft_record_size); 188987da915Sopenharmony_ci } 189987da915Sopenharmony_ci bw = ntfs_attr_mst_pwrite(vol->mft_na, m << vol->mft_record_size_bits, 190987da915Sopenharmony_ci count, vol->mft_record_size, b); 191987da915Sopenharmony_ci if (bw != count) { 192987da915Sopenharmony_ci if (bw != -1) 193987da915Sopenharmony_ci errno = EIO; 194987da915Sopenharmony_ci if (bw >= 0) 195987da915Sopenharmony_ci ntfs_log_debug("Error: partial write while writing $Mft " 196987da915Sopenharmony_ci "record(s)!\n"); 197987da915Sopenharmony_ci else 198987da915Sopenharmony_ci ntfs_log_perror("Error writing $Mft record(s)"); 199987da915Sopenharmony_ci res = errno; 200987da915Sopenharmony_ci } 201987da915Sopenharmony_ci if (bmirr && bw > 0) { 202987da915Sopenharmony_ci if (bw < cnt) 203987da915Sopenharmony_ci cnt = bw; 204987da915Sopenharmony_ci bw = ntfs_attr_mst_pwrite(vol->mftmirr_na, 205987da915Sopenharmony_ci m << vol->mft_record_size_bits, cnt, 206987da915Sopenharmony_ci vol->mft_record_size, bmirr); 207987da915Sopenharmony_ci if (bw != cnt) { 208987da915Sopenharmony_ci if (bw != -1) 209987da915Sopenharmony_ci errno = EIO; 210987da915Sopenharmony_ci ntfs_log_debug("Error: failed to sync $MFTMirr! Run " 211987da915Sopenharmony_ci "chkdsk.\n"); 212987da915Sopenharmony_ci res = errno; 213987da915Sopenharmony_ci } 214987da915Sopenharmony_ci } 215987da915Sopenharmony_ci free(bmirr); 216987da915Sopenharmony_ci if (!res) 217987da915Sopenharmony_ci return res; 218987da915Sopenharmony_ci errno = res; 219987da915Sopenharmony_ci return -1; 220987da915Sopenharmony_ci} 221987da915Sopenharmony_ci 222987da915Sopenharmony_ci/* 223987da915Sopenharmony_ci * Check the consistency of an MFT record 224987da915Sopenharmony_ci * 225987da915Sopenharmony_ci * Make sure its general fields are safe, then examine all its 226987da915Sopenharmony_ci * attributes and apply generic checks to them. 227987da915Sopenharmony_ci * The attribute checks are skipped when a record is being read in 228987da915Sopenharmony_ci * order to collect its sequence number for creating a new record. 229987da915Sopenharmony_ci * 230987da915Sopenharmony_ci * Returns 0 if the checks are successful 231987da915Sopenharmony_ci * -1 with errno = EIO otherwise 232987da915Sopenharmony_ci */ 233987da915Sopenharmony_ci 234987da915Sopenharmony_ciint ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref, 235987da915Sopenharmony_ci MFT_RECORD *m) 236987da915Sopenharmony_ci{ 237987da915Sopenharmony_ci ATTR_RECORD *a; 238987da915Sopenharmony_ci ATTR_TYPES previous_type; 239987da915Sopenharmony_ci int ret = -1; 240987da915Sopenharmony_ci u32 offset; 241987da915Sopenharmony_ci s32 space; 242987da915Sopenharmony_ci 243987da915Sopenharmony_ci if (!ntfs_is_file_record(m->magic)) { 244987da915Sopenharmony_ci if (!NVolNoFixupWarn(vol)) 245987da915Sopenharmony_ci ntfs_log_error("Record %llu has no FILE magic (0x%x)\n", 246987da915Sopenharmony_ci (unsigned long long)MREF(mref), 247987da915Sopenharmony_ci (int)le32_to_cpu(*(le32*)m)); 248987da915Sopenharmony_ci goto err_out; 249987da915Sopenharmony_ci } 250987da915Sopenharmony_ci 251987da915Sopenharmony_ci if (le32_to_cpu(m->bytes_allocated) != vol->mft_record_size) { 252987da915Sopenharmony_ci ntfs_log_error("Record %llu has corrupt allocation size " 253987da915Sopenharmony_ci "(%u <> %u)\n", (unsigned long long)MREF(mref), 254987da915Sopenharmony_ci vol->mft_record_size, 255987da915Sopenharmony_ci le32_to_cpu(m->bytes_allocated)); 256987da915Sopenharmony_ci goto err_out; 257987da915Sopenharmony_ci } 258987da915Sopenharmony_ci if (!NVolNoFixupWarn(vol) 259987da915Sopenharmony_ci && (le32_to_cpu(m->bytes_in_use) > vol->mft_record_size)) { 260987da915Sopenharmony_ci ntfs_log_error("Record %llu has corrupt in-use size " 261987da915Sopenharmony_ci "(%u > %u)\n", (unsigned long long)MREF(mref), 262987da915Sopenharmony_ci (int)le32_to_cpu(m->bytes_in_use), 263987da915Sopenharmony_ci (int)vol->mft_record_size); 264987da915Sopenharmony_ci goto err_out; 265987da915Sopenharmony_ci } 266987da915Sopenharmony_ci if (le16_to_cpu(m->attrs_offset) & 7) { 267987da915Sopenharmony_ci ntfs_log_error("Attributes badly aligned in record %llu\n", 268987da915Sopenharmony_ci (unsigned long long)MREF(mref)); 269987da915Sopenharmony_ci goto err_out; 270987da915Sopenharmony_ci } 271987da915Sopenharmony_ci 272987da915Sopenharmony_ci a = (ATTR_RECORD *)((char *)m + le16_to_cpu(m->attrs_offset)); 273987da915Sopenharmony_ci if (p2n(a) < p2n(m) || (char *)a > (char *)m + vol->mft_record_size) { 274987da915Sopenharmony_ci ntfs_log_error("Record %llu is corrupt\n", 275987da915Sopenharmony_ci (unsigned long long)MREF(mref)); 276987da915Sopenharmony_ci goto err_out; 277987da915Sopenharmony_ci } 278987da915Sopenharmony_ci 279987da915Sopenharmony_ci if (!NVolNoFixupWarn(vol)) { 280987da915Sopenharmony_ci offset = le16_to_cpu(m->attrs_offset); 281987da915Sopenharmony_ci space = le32_to_cpu(m->bytes_in_use) - offset; 282987da915Sopenharmony_ci a = (ATTR_RECORD*)((char*)m + offset); 283987da915Sopenharmony_ci previous_type = AT_STANDARD_INFORMATION; 284987da915Sopenharmony_ci while ((space >= (s32)offsetof(ATTR_RECORD, resident_end)) 285987da915Sopenharmony_ci && (a->type != AT_END) 286987da915Sopenharmony_ci && (le32_to_cpu(a->type) >= le32_to_cpu(previous_type))) { 287987da915Sopenharmony_ci if ((le32_to_cpu(a->length) <= (u32)space) 288987da915Sopenharmony_ci && !(le32_to_cpu(a->length) & 7)) { 289987da915Sopenharmony_ci if (!ntfs_attr_inconsistent(a, mref)) { 290987da915Sopenharmony_ci previous_type = a->type; 291987da915Sopenharmony_ci offset += le32_to_cpu(a->length); 292987da915Sopenharmony_ci space -= le32_to_cpu(a->length); 293987da915Sopenharmony_ci a = (ATTR_RECORD*)((char*)m + offset); 294987da915Sopenharmony_ci } else 295987da915Sopenharmony_ci goto err_out; 296987da915Sopenharmony_ci } else { 297987da915Sopenharmony_ci ntfs_log_error("Corrupted MFT record %llu\n", 298987da915Sopenharmony_ci (unsigned long long)MREF(mref)); 299987da915Sopenharmony_ci goto err_out; 300987da915Sopenharmony_ci } 301987da915Sopenharmony_ci } 302987da915Sopenharmony_ci /* We are supposed to reach an AT_END */ 303987da915Sopenharmony_ci if ((space < 4) || (a->type != AT_END)) { 304987da915Sopenharmony_ci ntfs_log_error("Bad end of MFT record %llu\n", 305987da915Sopenharmony_ci (unsigned long long)MREF(mref)); 306987da915Sopenharmony_ci goto err_out; 307987da915Sopenharmony_ci } 308987da915Sopenharmony_ci } 309987da915Sopenharmony_ci 310987da915Sopenharmony_ci ret = 0; 311987da915Sopenharmony_cierr_out: 312987da915Sopenharmony_ci if (ret) 313987da915Sopenharmony_ci errno = EIO; 314987da915Sopenharmony_ci return ret; 315987da915Sopenharmony_ci} 316987da915Sopenharmony_ci 317987da915Sopenharmony_ci/** 318987da915Sopenharmony_ci * ntfs_file_record_read - read a FILE record from the mft from disk 319987da915Sopenharmony_ci * @vol: volume to read from 320987da915Sopenharmony_ci * @mref: mft reference specifying mft record to read 321987da915Sopenharmony_ci * @mrec: address of pointer in which to return the mft record 322987da915Sopenharmony_ci * @attr: address of pointer in which to return the first attribute 323987da915Sopenharmony_ci * 324987da915Sopenharmony_ci * Read a FILE record from the mft of @vol from the storage medium. @mref 325987da915Sopenharmony_ci * specifies the mft record to read, including the sequence number, which can 326987da915Sopenharmony_ci * be 0 if no sequence number checking is to be performed. 327987da915Sopenharmony_ci * 328987da915Sopenharmony_ci * The function allocates a buffer large enough to hold the mft record and 329987da915Sopenharmony_ci * reads the record into the buffer (mst deprotecting it in the process). 330987da915Sopenharmony_ci * *@mrec is then set to point to the buffer. 331987da915Sopenharmony_ci * 332987da915Sopenharmony_ci * If @attr is not NULL, *@attr is set to point to the first attribute in the 333987da915Sopenharmony_ci * mft record, i.e. *@attr is a pointer into *@mrec. 334987da915Sopenharmony_ci * 335987da915Sopenharmony_ci * Return 0 on success, or -1 on error, with errno set to the error code. 336987da915Sopenharmony_ci * 337987da915Sopenharmony_ci * The read mft record is checked for having the magic FILE, 338987da915Sopenharmony_ci * and for having a matching sequence number (if MSEQNO(*@mref) != 0). 339987da915Sopenharmony_ci * If either of these fails, -1 is returned and errno is set to EIO. If you get 340987da915Sopenharmony_ci * this, but you still want to read the mft record (e.g. in order to correct 341987da915Sopenharmony_ci * it), use ntfs_mft_record_read() directly. 342987da915Sopenharmony_ci * 343987da915Sopenharmony_ci * Note: Caller has to free *@mrec when finished. 344987da915Sopenharmony_ci * 345987da915Sopenharmony_ci * Note: We do not check if the mft record is flagged in use. The caller can 346987da915Sopenharmony_ci * check if desired. 347987da915Sopenharmony_ci */ 348987da915Sopenharmony_ciint ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref, 349987da915Sopenharmony_ci MFT_RECORD **mrec, ATTR_RECORD **attr) 350987da915Sopenharmony_ci{ 351987da915Sopenharmony_ci MFT_RECORD *m; 352987da915Sopenharmony_ci 353987da915Sopenharmony_ci if (!vol || !mrec) { 354987da915Sopenharmony_ci errno = EINVAL; 355987da915Sopenharmony_ci ntfs_log_perror("%s: mrec=%p", __FUNCTION__, mrec); 356987da915Sopenharmony_ci return -1; 357987da915Sopenharmony_ci } 358987da915Sopenharmony_ci 359987da915Sopenharmony_ci m = *mrec; 360987da915Sopenharmony_ci if (!m) { 361987da915Sopenharmony_ci m = ntfs_malloc(vol->mft_record_size); 362987da915Sopenharmony_ci if (!m) 363987da915Sopenharmony_ci return -1; 364987da915Sopenharmony_ci } 365987da915Sopenharmony_ci if (ntfs_mft_record_read(vol, mref, m)) 366987da915Sopenharmony_ci goto err_out; 367987da915Sopenharmony_ci 368987da915Sopenharmony_ci if (ntfs_mft_record_check(vol, mref, m)) 369987da915Sopenharmony_ci goto err_out; 370987da915Sopenharmony_ci 371987da915Sopenharmony_ci if (MSEQNO(mref) && MSEQNO(mref) != le16_to_cpu(m->sequence_number)) { 372987da915Sopenharmony_ci ntfs_log_error("Record %llu has wrong SeqNo (%d <> %d)\n", 373987da915Sopenharmony_ci (unsigned long long)MREF(mref), MSEQNO(mref), 374987da915Sopenharmony_ci le16_to_cpu(m->sequence_number)); 375987da915Sopenharmony_ci errno = EIO; 376987da915Sopenharmony_ci goto err_out; 377987da915Sopenharmony_ci } 378987da915Sopenharmony_ci *mrec = m; 379987da915Sopenharmony_ci if (attr) 380987da915Sopenharmony_ci *attr = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset)); 381987da915Sopenharmony_ci return 0; 382987da915Sopenharmony_cierr_out: 383987da915Sopenharmony_ci if (m != *mrec) 384987da915Sopenharmony_ci free(m); 385987da915Sopenharmony_ci return -1; 386987da915Sopenharmony_ci} 387987da915Sopenharmony_ci 388987da915Sopenharmony_ci/** 389987da915Sopenharmony_ci * ntfs_mft_record_layout - layout an mft record into a memory buffer 390987da915Sopenharmony_ci * @vol: volume to which the mft record will belong 391987da915Sopenharmony_ci * @mref: mft reference specifying the mft record number 392987da915Sopenharmony_ci * @mrec: destination buffer of size >= @vol->mft_record_size bytes 393987da915Sopenharmony_ci * 394987da915Sopenharmony_ci * Layout an empty, unused mft record with the mft reference @mref into the 395987da915Sopenharmony_ci * buffer @m. The volume @vol is needed because the mft record structure was 396987da915Sopenharmony_ci * modified in NTFS 3.1 so we need to know which volume version this mft record 397987da915Sopenharmony_ci * will be used on. 398987da915Sopenharmony_ci * 399987da915Sopenharmony_ci * On success return 0 and on error return -1 with errno set to the error code. 400987da915Sopenharmony_ci */ 401987da915Sopenharmony_ciint ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref, 402987da915Sopenharmony_ci MFT_RECORD *mrec) 403987da915Sopenharmony_ci{ 404987da915Sopenharmony_ci ATTR_RECORD *a; 405987da915Sopenharmony_ci 406987da915Sopenharmony_ci if (!vol || !mrec) { 407987da915Sopenharmony_ci errno = EINVAL; 408987da915Sopenharmony_ci ntfs_log_perror("%s: mrec=%p", __FUNCTION__, mrec); 409987da915Sopenharmony_ci return -1; 410987da915Sopenharmony_ci } 411987da915Sopenharmony_ci /* Aligned to 2-byte boundary. */ 412987da915Sopenharmony_ci if (vol->major_ver < 3 || (vol->major_ver == 3 && !vol->minor_ver)) 413987da915Sopenharmony_ci mrec->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD_OLD) + 1) & ~1); 414987da915Sopenharmony_ci else { 415987da915Sopenharmony_ci /* Abort if mref is > 32 bits. */ 416987da915Sopenharmony_ci if (MREF(mref) & 0x0000ffff00000000ull) { 417987da915Sopenharmony_ci errno = ERANGE; 418987da915Sopenharmony_ci ntfs_log_perror("Mft reference exceeds 32 bits"); 419987da915Sopenharmony_ci return -1; 420987da915Sopenharmony_ci } 421987da915Sopenharmony_ci mrec->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD) + 1) & ~1); 422987da915Sopenharmony_ci /* 423987da915Sopenharmony_ci * Set the NTFS 3.1+ specific fields while we know that the 424987da915Sopenharmony_ci * volume version is 3.1+. 425987da915Sopenharmony_ci */ 426987da915Sopenharmony_ci mrec->reserved = const_cpu_to_le16(0); 427987da915Sopenharmony_ci mrec->mft_record_number = cpu_to_le32(MREF(mref)); 428987da915Sopenharmony_ci } 429987da915Sopenharmony_ci mrec->magic = magic_FILE; 430987da915Sopenharmony_ci if (vol->mft_record_size >= NTFS_BLOCK_SIZE) 431987da915Sopenharmony_ci mrec->usa_count = cpu_to_le16(vol->mft_record_size / 432987da915Sopenharmony_ci NTFS_BLOCK_SIZE + 1); 433987da915Sopenharmony_ci else { 434987da915Sopenharmony_ci mrec->usa_count = const_cpu_to_le16(1); 435987da915Sopenharmony_ci ntfs_log_error("Sector size is bigger than MFT record size. " 436987da915Sopenharmony_ci "Setting usa_count to 1. If Windows chkdsk " 437987da915Sopenharmony_ci "reports this as corruption, please email %s " 438987da915Sopenharmony_ci "stating that you saw this message and that " 439987da915Sopenharmony_ci "the file system created was corrupt. " 440987da915Sopenharmony_ci "Thank you.\n", NTFS_DEV_LIST); 441987da915Sopenharmony_ci } 442987da915Sopenharmony_ci /* Set the update sequence number to 1. */ 443987da915Sopenharmony_ci *(le16*)((u8*)mrec + le16_to_cpu(mrec->usa_ofs)) = const_cpu_to_le16(1); 444987da915Sopenharmony_ci mrec->lsn = const_cpu_to_sle64(0ll); 445987da915Sopenharmony_ci mrec->sequence_number = const_cpu_to_le16(1); 446987da915Sopenharmony_ci mrec->link_count = const_cpu_to_le16(0); 447987da915Sopenharmony_ci /* Aligned to 8-byte boundary. */ 448987da915Sopenharmony_ci mrec->attrs_offset = cpu_to_le16((le16_to_cpu(mrec->usa_ofs) + 449987da915Sopenharmony_ci (le16_to_cpu(mrec->usa_count) << 1) + 7) & ~7); 450987da915Sopenharmony_ci mrec->flags = const_cpu_to_le16(0); 451987da915Sopenharmony_ci /* 452987da915Sopenharmony_ci * Using attrs_offset plus eight bytes (for the termination attribute), 453987da915Sopenharmony_ci * aligned to 8-byte boundary. 454987da915Sopenharmony_ci */ 455987da915Sopenharmony_ci mrec->bytes_in_use = cpu_to_le32((le16_to_cpu(mrec->attrs_offset) + 8 + 456987da915Sopenharmony_ci 7) & ~7); 457987da915Sopenharmony_ci mrec->bytes_allocated = cpu_to_le32(vol->mft_record_size); 458987da915Sopenharmony_ci mrec->base_mft_record = const_cpu_to_le64((MFT_REF)0); 459987da915Sopenharmony_ci mrec->next_attr_instance = const_cpu_to_le16(0); 460987da915Sopenharmony_ci a = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset)); 461987da915Sopenharmony_ci a->type = AT_END; 462987da915Sopenharmony_ci a->length = const_cpu_to_le32(0); 463987da915Sopenharmony_ci /* Finally, clear the unused part of the mft record. */ 464987da915Sopenharmony_ci memset((u8*)a + 8, 0, vol->mft_record_size - ((u8*)a + 8 - (u8*)mrec)); 465987da915Sopenharmony_ci return 0; 466987da915Sopenharmony_ci} 467987da915Sopenharmony_ci 468987da915Sopenharmony_ci/** 469987da915Sopenharmony_ci * ntfs_mft_record_format - format an mft record on an ntfs volume 470987da915Sopenharmony_ci * @vol: volume on which to format the mft record 471987da915Sopenharmony_ci * @mref: mft reference specifying mft record to format 472987da915Sopenharmony_ci * 473987da915Sopenharmony_ci * Format the mft record with the mft reference @mref in $MFT/$DATA, i.e. lay 474987da915Sopenharmony_ci * out an empty, unused mft record in memory and write it to the volume @vol. 475987da915Sopenharmony_ci * 476987da915Sopenharmony_ci * On success return 0 and on error return -1 with errno set to the error code. 477987da915Sopenharmony_ci */ 478987da915Sopenharmony_ciint ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref) 479987da915Sopenharmony_ci{ 480987da915Sopenharmony_ci MFT_RECORD *m; 481987da915Sopenharmony_ci int ret = -1; 482987da915Sopenharmony_ci 483987da915Sopenharmony_ci ntfs_log_enter("Entering\n"); 484987da915Sopenharmony_ci 485987da915Sopenharmony_ci m = ntfs_calloc(vol->mft_record_size); 486987da915Sopenharmony_ci if (!m) 487987da915Sopenharmony_ci goto out; 488987da915Sopenharmony_ci 489987da915Sopenharmony_ci if (ntfs_mft_record_layout(vol, mref, m)) 490987da915Sopenharmony_ci goto free_m; 491987da915Sopenharmony_ci 492987da915Sopenharmony_ci if (ntfs_mft_record_write(vol, mref, m)) 493987da915Sopenharmony_ci goto free_m; 494987da915Sopenharmony_ci 495987da915Sopenharmony_ci ret = 0; 496987da915Sopenharmony_cifree_m: 497987da915Sopenharmony_ci free(m); 498987da915Sopenharmony_ciout: 499987da915Sopenharmony_ci ntfs_log_leave("\n"); 500987da915Sopenharmony_ci return ret; 501987da915Sopenharmony_ci} 502987da915Sopenharmony_ci 503987da915Sopenharmony_cistatic const char *es = " Leaving inconsistent metadata. Run chkdsk."; 504987da915Sopenharmony_ci 505987da915Sopenharmony_ci/** 506987da915Sopenharmony_ci * ntfs_ffz - Find the first unset (zero) bit in a word 507987da915Sopenharmony_ci * @word: 508987da915Sopenharmony_ci * 509987da915Sopenharmony_ci * Description... 510987da915Sopenharmony_ci * 511987da915Sopenharmony_ci * Returns: 512987da915Sopenharmony_ci */ 513987da915Sopenharmony_cistatic inline unsigned int ntfs_ffz(unsigned int word) 514987da915Sopenharmony_ci{ 515987da915Sopenharmony_ci return ffs(~word) - 1; 516987da915Sopenharmony_ci} 517987da915Sopenharmony_ci 518987da915Sopenharmony_cistatic int ntfs_is_mft(ntfs_inode *ni) 519987da915Sopenharmony_ci{ 520987da915Sopenharmony_ci if (ni && ni->mft_no == FILE_MFT) 521987da915Sopenharmony_ci return 1; 522987da915Sopenharmony_ci return 0; 523987da915Sopenharmony_ci} 524987da915Sopenharmony_ci 525987da915Sopenharmony_ci#ifndef PAGE_SIZE 526987da915Sopenharmony_ci#define PAGE_SIZE 4096 527987da915Sopenharmony_ci#endif 528987da915Sopenharmony_ci 529987da915Sopenharmony_ci#define RESERVED_MFT_RECORDS 64 530987da915Sopenharmony_ci 531987da915Sopenharmony_ci/** 532987da915Sopenharmony_ci * ntfs_mft_bitmap_find_free_rec - find a free mft record in the mft bitmap 533987da915Sopenharmony_ci * @vol: volume on which to search for a free mft record 534987da915Sopenharmony_ci * @base_ni: open base inode if allocating an extent mft record or NULL 535987da915Sopenharmony_ci * 536987da915Sopenharmony_ci * Search for a free mft record in the mft bitmap attribute on the ntfs volume 537987da915Sopenharmony_ci * @vol. 538987da915Sopenharmony_ci * 539987da915Sopenharmony_ci * If @base_ni is NULL start the search at the default allocator position. 540987da915Sopenharmony_ci * 541987da915Sopenharmony_ci * If @base_ni is not NULL start the search at the mft record after the base 542987da915Sopenharmony_ci * mft record @base_ni. 543987da915Sopenharmony_ci * 544987da915Sopenharmony_ci * Return the free mft record on success and -1 on error with errno set to the 545987da915Sopenharmony_ci * error code. An error code of ENOSPC means that there are no free mft 546987da915Sopenharmony_ci * records in the currently initialized mft bitmap. 547987da915Sopenharmony_ci */ 548987da915Sopenharmony_cistatic int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni) 549987da915Sopenharmony_ci{ 550987da915Sopenharmony_ci s64 pass_end, ll, data_pos, pass_start, ofs, bit; 551987da915Sopenharmony_ci ntfs_attr *mftbmp_na; 552987da915Sopenharmony_ci u8 *buf, *byte; 553987da915Sopenharmony_ci unsigned int size; 554987da915Sopenharmony_ci u8 pass, b; 555987da915Sopenharmony_ci int ret = -1; 556987da915Sopenharmony_ci 557987da915Sopenharmony_ci ntfs_log_enter("Entering\n"); 558987da915Sopenharmony_ci 559987da915Sopenharmony_ci mftbmp_na = vol->mftbmp_na; 560987da915Sopenharmony_ci /* 561987da915Sopenharmony_ci * Set the end of the pass making sure we do not overflow the mft 562987da915Sopenharmony_ci * bitmap. 563987da915Sopenharmony_ci */ 564987da915Sopenharmony_ci size = PAGE_SIZE; 565987da915Sopenharmony_ci pass_end = vol->mft_na->allocated_size >> vol->mft_record_size_bits; 566987da915Sopenharmony_ci ll = mftbmp_na->initialized_size << 3; 567987da915Sopenharmony_ci if (pass_end > ll) 568987da915Sopenharmony_ci pass_end = ll; 569987da915Sopenharmony_ci pass = 1; 570987da915Sopenharmony_ci if (!base_ni) 571987da915Sopenharmony_ci data_pos = vol->mft_data_pos; 572987da915Sopenharmony_ci else 573987da915Sopenharmony_ci data_pos = base_ni->mft_no + 1; 574987da915Sopenharmony_ci if (data_pos < RESERVED_MFT_RECORDS) 575987da915Sopenharmony_ci data_pos = RESERVED_MFT_RECORDS; 576987da915Sopenharmony_ci if (data_pos >= pass_end) { 577987da915Sopenharmony_ci data_pos = RESERVED_MFT_RECORDS; 578987da915Sopenharmony_ci pass = 2; 579987da915Sopenharmony_ci /* This happens on a freshly formatted volume. */ 580987da915Sopenharmony_ci if (data_pos >= pass_end) { 581987da915Sopenharmony_ci errno = ENOSPC; 582987da915Sopenharmony_ci goto leave; 583987da915Sopenharmony_ci } 584987da915Sopenharmony_ci } 585987da915Sopenharmony_ci if (ntfs_is_mft(base_ni)) { 586987da915Sopenharmony_ci data_pos = 0; 587987da915Sopenharmony_ci pass = 2; 588987da915Sopenharmony_ci } 589987da915Sopenharmony_ci pass_start = data_pos; 590987da915Sopenharmony_ci buf = ntfs_malloc(PAGE_SIZE); 591987da915Sopenharmony_ci if (!buf) 592987da915Sopenharmony_ci goto leave; 593987da915Sopenharmony_ci 594987da915Sopenharmony_ci ntfs_log_debug("Starting bitmap search: pass %u, pass_start 0x%llx, " 595987da915Sopenharmony_ci "pass_end 0x%llx, data_pos 0x%llx.\n", pass, 596987da915Sopenharmony_ci (long long)pass_start, (long long)pass_end, 597987da915Sopenharmony_ci (long long)data_pos); 598987da915Sopenharmony_ci#ifdef DEBUG 599987da915Sopenharmony_ci byte = NULL; 600987da915Sopenharmony_ci b = 0; 601987da915Sopenharmony_ci#endif 602987da915Sopenharmony_ci /* Loop until a free mft record is found. */ 603987da915Sopenharmony_ci for (; pass <= 2; size = PAGE_SIZE) { 604987da915Sopenharmony_ci /* Cap size to pass_end. */ 605987da915Sopenharmony_ci ofs = data_pos >> 3; 606987da915Sopenharmony_ci ll = ((pass_end + 7) >> 3) - ofs; 607987da915Sopenharmony_ci if (size > ll) 608987da915Sopenharmony_ci size = ll; 609987da915Sopenharmony_ci ll = ntfs_attr_pread(mftbmp_na, ofs, size, buf); 610987da915Sopenharmony_ci if (ll < 0) { 611987da915Sopenharmony_ci ntfs_log_perror("Failed to read $MFT bitmap"); 612987da915Sopenharmony_ci free(buf); 613987da915Sopenharmony_ci goto leave; 614987da915Sopenharmony_ci } 615987da915Sopenharmony_ci ntfs_log_debug("Read 0x%llx bytes.\n", (long long)ll); 616987da915Sopenharmony_ci /* If we read at least one byte, search @buf for a zero bit. */ 617987da915Sopenharmony_ci if (ll) { 618987da915Sopenharmony_ci size = ll << 3; 619987da915Sopenharmony_ci bit = data_pos & 7; 620987da915Sopenharmony_ci data_pos &= ~7ull; 621987da915Sopenharmony_ci ntfs_log_debug("Before inner for loop: size 0x%x, " 622987da915Sopenharmony_ci "data_pos 0x%llx, bit 0x%llx, " 623987da915Sopenharmony_ci "*byte 0x%hhx, b %u.\n", size, 624987da915Sopenharmony_ci (long long)data_pos, (long long)bit, 625987da915Sopenharmony_ci (u8) (byte ? *byte : -1), b); 626987da915Sopenharmony_ci for (; bit < size && data_pos + bit < pass_end; 627987da915Sopenharmony_ci bit &= ~7ull, bit += 8) { 628987da915Sopenharmony_ci /* 629987da915Sopenharmony_ci * If we're extending $MFT and running out of the first 630987da915Sopenharmony_ci * mft record (base record) then give up searching since 631987da915Sopenharmony_ci * no guarantee that the found record will be accessible. 632987da915Sopenharmony_ci */ 633987da915Sopenharmony_ci if (ntfs_is_mft(base_ni) && bit > 400) 634987da915Sopenharmony_ci goto out; 635987da915Sopenharmony_ci 636987da915Sopenharmony_ci byte = buf + (bit >> 3); 637987da915Sopenharmony_ci if (*byte == 0xff) 638987da915Sopenharmony_ci continue; 639987da915Sopenharmony_ci 640987da915Sopenharmony_ci /* Note: ffz() result must be zero based. */ 641987da915Sopenharmony_ci b = ntfs_ffz((unsigned long)*byte); 642987da915Sopenharmony_ci if (b < 8 && b >= (bit & 7)) { 643987da915Sopenharmony_ci free(buf); 644987da915Sopenharmony_ci ret = data_pos + (bit & ~7ull) + b; 645987da915Sopenharmony_ci goto leave; 646987da915Sopenharmony_ci } 647987da915Sopenharmony_ci } 648987da915Sopenharmony_ci ntfs_log_debug("After inner for loop: size 0x%x, " 649987da915Sopenharmony_ci "data_pos 0x%llx, bit 0x%llx, " 650987da915Sopenharmony_ci "*byte 0x%hhx, b %u.\n", size, 651987da915Sopenharmony_ci (long long)data_pos, (long long)bit, 652987da915Sopenharmony_ci (u8) (byte ? *byte : -1), b); 653987da915Sopenharmony_ci data_pos += size; 654987da915Sopenharmony_ci /* 655987da915Sopenharmony_ci * If the end of the pass has not been reached yet, 656987da915Sopenharmony_ci * continue searching the mft bitmap for a zero bit. 657987da915Sopenharmony_ci */ 658987da915Sopenharmony_ci if (data_pos < pass_end) 659987da915Sopenharmony_ci continue; 660987da915Sopenharmony_ci } 661987da915Sopenharmony_ci /* Do the next pass. */ 662987da915Sopenharmony_ci pass++; 663987da915Sopenharmony_ci if (pass == 2) { 664987da915Sopenharmony_ci /* 665987da915Sopenharmony_ci * Starting the second pass, in which we scan the first 666987da915Sopenharmony_ci * part of the zone which we omitted earlier. 667987da915Sopenharmony_ci */ 668987da915Sopenharmony_ci pass_end = pass_start; 669987da915Sopenharmony_ci data_pos = pass_start = RESERVED_MFT_RECORDS; 670987da915Sopenharmony_ci ntfs_log_debug("pass %i, pass_start 0x%llx, pass_end " 671987da915Sopenharmony_ci "0x%llx.\n", pass, (long long)pass_start, 672987da915Sopenharmony_ci (long long)pass_end); 673987da915Sopenharmony_ci if (data_pos >= pass_end) 674987da915Sopenharmony_ci break; 675987da915Sopenharmony_ci } 676987da915Sopenharmony_ci } 677987da915Sopenharmony_ci /* No free mft records in currently initialized mft bitmap. */ 678987da915Sopenharmony_ciout: 679987da915Sopenharmony_ci free(buf); 680987da915Sopenharmony_ci errno = ENOSPC; 681987da915Sopenharmony_cileave: 682987da915Sopenharmony_ci ntfs_log_leave("\n"); 683987da915Sopenharmony_ci return ret; 684987da915Sopenharmony_ci} 685987da915Sopenharmony_ci 686987da915Sopenharmony_cistatic int ntfs_mft_attr_extend(ntfs_attr *na) 687987da915Sopenharmony_ci{ 688987da915Sopenharmony_ci int ret = STATUS_ERROR; 689987da915Sopenharmony_ci ntfs_log_enter("Entering\n"); 690987da915Sopenharmony_ci 691987da915Sopenharmony_ci if (!NInoAttrList(na->ni)) { 692987da915Sopenharmony_ci if (ntfs_inode_add_attrlist(na->ni)) { 693987da915Sopenharmony_ci ntfs_log_perror("%s: Can not add attrlist #3", __FUNCTION__); 694987da915Sopenharmony_ci goto out; 695987da915Sopenharmony_ci } 696987da915Sopenharmony_ci /* We can't sync the $MFT inode since its runlist is bogus. */ 697987da915Sopenharmony_ci ret = STATUS_KEEP_SEARCHING; 698987da915Sopenharmony_ci goto out; 699987da915Sopenharmony_ci } 700987da915Sopenharmony_ci 701987da915Sopenharmony_ci if (ntfs_attr_update_mapping_pairs(na, 0)) { 702987da915Sopenharmony_ci ntfs_log_perror("%s: MP update failed", __FUNCTION__); 703987da915Sopenharmony_ci goto out; 704987da915Sopenharmony_ci } 705987da915Sopenharmony_ci 706987da915Sopenharmony_ci ret = STATUS_OK; 707987da915Sopenharmony_ciout: 708987da915Sopenharmony_ci ntfs_log_leave("\n"); 709987da915Sopenharmony_ci return ret; 710987da915Sopenharmony_ci} 711987da915Sopenharmony_ci 712987da915Sopenharmony_ci/** 713987da915Sopenharmony_ci * ntfs_mft_bitmap_extend_allocation_i - see ntfs_mft_bitmap_extend_allocation 714987da915Sopenharmony_ci */ 715987da915Sopenharmony_cistatic int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol) 716987da915Sopenharmony_ci{ 717987da915Sopenharmony_ci LCN lcn; 718987da915Sopenharmony_ci s64 ll = 0; /* silence compiler warning */ 719987da915Sopenharmony_ci ntfs_attr *mftbmp_na; 720987da915Sopenharmony_ci runlist_element *rl, *rl2 = NULL; /* silence compiler warning */ 721987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 722987da915Sopenharmony_ci MFT_RECORD *m = NULL; /* silence compiler warning */ 723987da915Sopenharmony_ci ATTR_RECORD *a = NULL; /* silence compiler warning */ 724987da915Sopenharmony_ci int err, mp_size; 725987da915Sopenharmony_ci int ret = STATUS_ERROR; 726987da915Sopenharmony_ci u32 old_alen = 0; /* silence compiler warning */ 727987da915Sopenharmony_ci BOOL mp_rebuilt = FALSE; 728987da915Sopenharmony_ci BOOL update_mp = FALSE; 729987da915Sopenharmony_ci 730987da915Sopenharmony_ci mftbmp_na = vol->mftbmp_na; 731987da915Sopenharmony_ci /* 732987da915Sopenharmony_ci * Determine the last lcn of the mft bitmap. The allocated size of the 733987da915Sopenharmony_ci * mft bitmap cannot be zero so we are ok to do this. 734987da915Sopenharmony_ci */ 735987da915Sopenharmony_ci rl = ntfs_attr_find_vcn(mftbmp_na, (mftbmp_na->allocated_size - 1) >> 736987da915Sopenharmony_ci vol->cluster_size_bits); 737987da915Sopenharmony_ci if (!rl || !rl->length || rl->lcn < 0) { 738987da915Sopenharmony_ci ntfs_log_error("Failed to determine last allocated " 739987da915Sopenharmony_ci "cluster of mft bitmap attribute.\n"); 740987da915Sopenharmony_ci if (rl) 741987da915Sopenharmony_ci errno = EIO; 742987da915Sopenharmony_ci return STATUS_ERROR; 743987da915Sopenharmony_ci } 744987da915Sopenharmony_ci lcn = rl->lcn + rl->length; 745987da915Sopenharmony_ci 746987da915Sopenharmony_ci rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE); 747987da915Sopenharmony_ci if (!rl2) { 748987da915Sopenharmony_ci ntfs_log_error("Failed to allocate a cluster for " 749987da915Sopenharmony_ci "the mft bitmap.\n"); 750987da915Sopenharmony_ci return STATUS_ERROR; 751987da915Sopenharmony_ci } 752987da915Sopenharmony_ci rl = ntfs_runlists_merge(mftbmp_na->rl, rl2); 753987da915Sopenharmony_ci if (!rl) { 754987da915Sopenharmony_ci err = errno; 755987da915Sopenharmony_ci ntfs_log_error("Failed to merge runlists for mft " 756987da915Sopenharmony_ci "bitmap.\n"); 757987da915Sopenharmony_ci if (ntfs_cluster_free_from_rl(vol, rl2)) 758987da915Sopenharmony_ci ntfs_log_error("Failed to deallocate " 759987da915Sopenharmony_ci "cluster.%s\n", es); 760987da915Sopenharmony_ci free(rl2); 761987da915Sopenharmony_ci errno = err; 762987da915Sopenharmony_ci return STATUS_ERROR; 763987da915Sopenharmony_ci } 764987da915Sopenharmony_ci mftbmp_na->rl = rl; 765987da915Sopenharmony_ci ntfs_log_debug("Adding one run to mft bitmap.\n"); 766987da915Sopenharmony_ci /* Find the last run in the new runlist. */ 767987da915Sopenharmony_ci for (; rl[1].length; rl++) 768987da915Sopenharmony_ci ; 769987da915Sopenharmony_ci /* 770987da915Sopenharmony_ci * Update the attribute record as well. Note: @rl is the last 771987da915Sopenharmony_ci * (non-terminator) runlist element of mft bitmap. 772987da915Sopenharmony_ci */ 773987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL); 774987da915Sopenharmony_ci if (!ctx) 775987da915Sopenharmony_ci goto undo_alloc; 776987da915Sopenharmony_ci 777987da915Sopenharmony_ci if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, 778987da915Sopenharmony_ci mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) { 779987da915Sopenharmony_ci ntfs_log_error("Failed to find last attribute extent of " 780987da915Sopenharmony_ci "mft bitmap attribute.\n"); 781987da915Sopenharmony_ci goto undo_alloc; 782987da915Sopenharmony_ci } 783987da915Sopenharmony_ci m = ctx->mrec; 784987da915Sopenharmony_ci a = ctx->attr; 785987da915Sopenharmony_ci ll = sle64_to_cpu(a->lowest_vcn); 786987da915Sopenharmony_ci rl2 = ntfs_attr_find_vcn(mftbmp_na, ll); 787987da915Sopenharmony_ci if (!rl2 || !rl2->length) { 788987da915Sopenharmony_ci ntfs_log_error("Failed to determine previous last " 789987da915Sopenharmony_ci "allocated cluster of mft bitmap attribute.\n"); 790987da915Sopenharmony_ci if (rl2) 791987da915Sopenharmony_ci errno = EIO; 792987da915Sopenharmony_ci goto undo_alloc; 793987da915Sopenharmony_ci } 794987da915Sopenharmony_ci /* Get the size for the new mapping pairs array for this extent. */ 795987da915Sopenharmony_ci mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, INT_MAX); 796987da915Sopenharmony_ci if (mp_size <= 0) { 797987da915Sopenharmony_ci ntfs_log_error("Get size for mapping pairs failed for " 798987da915Sopenharmony_ci "mft bitmap attribute extent.\n"); 799987da915Sopenharmony_ci goto undo_alloc; 800987da915Sopenharmony_ci } 801987da915Sopenharmony_ci /* Expand the attribute record if necessary. */ 802987da915Sopenharmony_ci old_alen = le32_to_cpu(a->length); 803987da915Sopenharmony_ci if (ntfs_attr_record_resize(m, a, mp_size + 804987da915Sopenharmony_ci le16_to_cpu(a->mapping_pairs_offset))) { 805987da915Sopenharmony_ci ntfs_log_info("extending $MFT bitmap\n"); 806987da915Sopenharmony_ci ret = ntfs_mft_attr_extend(vol->mftbmp_na); 807987da915Sopenharmony_ci if (ret == STATUS_OK) 808987da915Sopenharmony_ci goto ok; 809987da915Sopenharmony_ci if (ret == STATUS_ERROR) { 810987da915Sopenharmony_ci ntfs_log_perror("%s: ntfs_mft_attr_extend failed", __FUNCTION__); 811987da915Sopenharmony_ci update_mp = TRUE; 812987da915Sopenharmony_ci } 813987da915Sopenharmony_ci goto undo_alloc; 814987da915Sopenharmony_ci } 815987da915Sopenharmony_ci mp_rebuilt = TRUE; 816987da915Sopenharmony_ci /* Generate the mapping pairs array directly into the attr record. */ 817987da915Sopenharmony_ci if (ntfs_mapping_pairs_build(vol, (u8*)a + 818987da915Sopenharmony_ci le16_to_cpu(a->mapping_pairs_offset), mp_size, rl2, ll, 819987da915Sopenharmony_ci NULL)) { 820987da915Sopenharmony_ci ntfs_log_error("Failed to build mapping pairs array for " 821987da915Sopenharmony_ci "mft bitmap attribute.\n"); 822987da915Sopenharmony_ci errno = EIO; 823987da915Sopenharmony_ci goto undo_alloc; 824987da915Sopenharmony_ci } 825987da915Sopenharmony_ci /* Update the highest_vcn. */ 826987da915Sopenharmony_ci a->highest_vcn = cpu_to_sle64(rl[1].vcn - 1); 827987da915Sopenharmony_ci /* 828987da915Sopenharmony_ci * We now have extended the mft bitmap allocated_size by one cluster. 829987da915Sopenharmony_ci * Reflect this in the ntfs_attr structure and the attribute record. 830987da915Sopenharmony_ci */ 831987da915Sopenharmony_ci if (a->lowest_vcn) { 832987da915Sopenharmony_ci /* 833987da915Sopenharmony_ci * We are not in the first attribute extent, switch to it, but 834987da915Sopenharmony_ci * first ensure the changes will make it to disk later. 835987da915Sopenharmony_ci */ 836987da915Sopenharmony_ci ntfs_inode_mark_dirty(ctx->ntfs_ino); 837987da915Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 838987da915Sopenharmony_ci if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, 839987da915Sopenharmony_ci mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) { 840987da915Sopenharmony_ci ntfs_log_error("Failed to find first attribute " 841987da915Sopenharmony_ci "extent of mft bitmap attribute.\n"); 842987da915Sopenharmony_ci goto restore_undo_alloc; 843987da915Sopenharmony_ci } 844987da915Sopenharmony_ci a = ctx->attr; 845987da915Sopenharmony_ci } 846987da915Sopenharmony_ciok: 847987da915Sopenharmony_ci mftbmp_na->allocated_size += vol->cluster_size; 848987da915Sopenharmony_ci a->allocated_size = cpu_to_sle64(mftbmp_na->allocated_size); 849987da915Sopenharmony_ci /* Ensure the changes make it to disk. */ 850987da915Sopenharmony_ci ntfs_inode_mark_dirty(ctx->ntfs_ino); 851987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 852987da915Sopenharmony_ci return STATUS_OK; 853987da915Sopenharmony_ci 854987da915Sopenharmony_cirestore_undo_alloc: 855987da915Sopenharmony_ci err = errno; 856987da915Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 857987da915Sopenharmony_ci if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, 858987da915Sopenharmony_ci mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) { 859987da915Sopenharmony_ci ntfs_log_error("Failed to find last attribute extent of " 860987da915Sopenharmony_ci "mft bitmap attribute.%s\n", es); 861987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 862987da915Sopenharmony_ci mftbmp_na->allocated_size += vol->cluster_size; 863987da915Sopenharmony_ci /* 864987da915Sopenharmony_ci * The only thing that is now wrong is ->allocated_size of the 865987da915Sopenharmony_ci * base attribute extent which chkdsk should be able to fix. 866987da915Sopenharmony_ci */ 867987da915Sopenharmony_ci errno = err; 868987da915Sopenharmony_ci return STATUS_ERROR; 869987da915Sopenharmony_ci } 870987da915Sopenharmony_ci m = ctx->mrec; 871987da915Sopenharmony_ci a = ctx->attr; 872987da915Sopenharmony_ci a->highest_vcn = cpu_to_sle64(rl[1].vcn - 2); 873987da915Sopenharmony_ci errno = err; 874987da915Sopenharmony_ciundo_alloc: 875987da915Sopenharmony_ci err = errno; 876987da915Sopenharmony_ci 877987da915Sopenharmony_ci /* Remove the last run from the runlist. */ 878987da915Sopenharmony_ci lcn = rl->lcn; 879987da915Sopenharmony_ci rl->lcn = rl[1].lcn; 880987da915Sopenharmony_ci rl->length = 0; 881987da915Sopenharmony_ci 882987da915Sopenharmony_ci /* FIXME: use an ntfs_cluster_free_* function */ 883987da915Sopenharmony_ci if (ntfs_bitmap_clear_bit(vol->lcnbmp_na, lcn)) 884987da915Sopenharmony_ci ntfs_log_error("Failed to free cluster.%s\n", es); 885987da915Sopenharmony_ci else 886987da915Sopenharmony_ci vol->free_clusters++; 887987da915Sopenharmony_ci if (mp_rebuilt) { 888987da915Sopenharmony_ci if (ntfs_mapping_pairs_build(vol, (u8*)a + 889987da915Sopenharmony_ci le16_to_cpu(a->mapping_pairs_offset), 890987da915Sopenharmony_ci old_alen - le16_to_cpu(a->mapping_pairs_offset), 891987da915Sopenharmony_ci rl2, ll, NULL)) 892987da915Sopenharmony_ci ntfs_log_error("Failed to restore mapping " 893987da915Sopenharmony_ci "pairs array.%s\n", es); 894987da915Sopenharmony_ci if (ntfs_attr_record_resize(m, a, old_alen)) 895987da915Sopenharmony_ci ntfs_log_error("Failed to restore attribute " 896987da915Sopenharmony_ci "record.%s\n", es); 897987da915Sopenharmony_ci ntfs_inode_mark_dirty(ctx->ntfs_ino); 898987da915Sopenharmony_ci } 899987da915Sopenharmony_ci if (update_mp) { 900987da915Sopenharmony_ci if (ntfs_attr_update_mapping_pairs(vol->mftbmp_na, 0)) 901987da915Sopenharmony_ci ntfs_log_perror("%s: MP update failed", __FUNCTION__); 902987da915Sopenharmony_ci } 903987da915Sopenharmony_ci if (ctx) 904987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 905987da915Sopenharmony_ci errno = err; 906987da915Sopenharmony_ci return ret; 907987da915Sopenharmony_ci} 908987da915Sopenharmony_ci 909987da915Sopenharmony_ci/** 910987da915Sopenharmony_ci * ntfs_mft_bitmap_extend_allocation - extend mft bitmap attribute by a cluster 911987da915Sopenharmony_ci * @vol: volume on which to extend the mft bitmap attribute 912987da915Sopenharmony_ci * 913987da915Sopenharmony_ci * Extend the mft bitmap attribute on the ntfs volume @vol by one cluster. 914987da915Sopenharmony_ci * 915987da915Sopenharmony_ci * Note: Only changes allocated_size, i.e. does not touch initialized_size or 916987da915Sopenharmony_ci * data_size. 917987da915Sopenharmony_ci * 918987da915Sopenharmony_ci * Return 0 on success and -1 on error with errno set to the error code. 919987da915Sopenharmony_ci */ 920987da915Sopenharmony_cistatic int ntfs_mft_bitmap_extend_allocation(ntfs_volume *vol) 921987da915Sopenharmony_ci{ 922987da915Sopenharmony_ci int ret; 923987da915Sopenharmony_ci 924987da915Sopenharmony_ci ntfs_log_enter("Entering\n"); 925987da915Sopenharmony_ci ret = ntfs_mft_bitmap_extend_allocation_i(vol); 926987da915Sopenharmony_ci ntfs_log_leave("\n"); 927987da915Sopenharmony_ci return ret; 928987da915Sopenharmony_ci} 929987da915Sopenharmony_ci/** 930987da915Sopenharmony_ci * ntfs_mft_bitmap_extend_initialized - extend mft bitmap initialized data 931987da915Sopenharmony_ci * @vol: volume on which to extend the mft bitmap attribute 932987da915Sopenharmony_ci * 933987da915Sopenharmony_ci * Extend the initialized portion of the mft bitmap attribute on the ntfs 934987da915Sopenharmony_ci * volume @vol by 8 bytes. 935987da915Sopenharmony_ci * 936987da915Sopenharmony_ci * Note: Only changes initialized_size and data_size, i.e. requires that 937987da915Sopenharmony_ci * allocated_size is big enough to fit the new initialized_size. 938987da915Sopenharmony_ci * 939987da915Sopenharmony_ci * Return 0 on success and -1 on error with errno set to the error code. 940987da915Sopenharmony_ci */ 941987da915Sopenharmony_cistatic int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol) 942987da915Sopenharmony_ci{ 943987da915Sopenharmony_ci s64 old_data_size, old_initialized_size, ll; 944987da915Sopenharmony_ci ntfs_attr *mftbmp_na; 945987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 946987da915Sopenharmony_ci ATTR_RECORD *a; 947987da915Sopenharmony_ci int err; 948987da915Sopenharmony_ci int ret = -1; 949987da915Sopenharmony_ci 950987da915Sopenharmony_ci ntfs_log_enter("Entering\n"); 951987da915Sopenharmony_ci 952987da915Sopenharmony_ci mftbmp_na = vol->mftbmp_na; 953987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL); 954987da915Sopenharmony_ci if (!ctx) 955987da915Sopenharmony_ci goto out; 956987da915Sopenharmony_ci 957987da915Sopenharmony_ci if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, 958987da915Sopenharmony_ci mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) { 959987da915Sopenharmony_ci ntfs_log_error("Failed to find first attribute extent of " 960987da915Sopenharmony_ci "mft bitmap attribute.\n"); 961987da915Sopenharmony_ci err = errno; 962987da915Sopenharmony_ci goto put_err_out; 963987da915Sopenharmony_ci } 964987da915Sopenharmony_ci a = ctx->attr; 965987da915Sopenharmony_ci old_data_size = mftbmp_na->data_size; 966987da915Sopenharmony_ci old_initialized_size = mftbmp_na->initialized_size; 967987da915Sopenharmony_ci mftbmp_na->initialized_size += 8; 968987da915Sopenharmony_ci a->initialized_size = cpu_to_sle64(mftbmp_na->initialized_size); 969987da915Sopenharmony_ci if (mftbmp_na->initialized_size > mftbmp_na->data_size) { 970987da915Sopenharmony_ci mftbmp_na->data_size = mftbmp_na->initialized_size; 971987da915Sopenharmony_ci a->data_size = cpu_to_sle64(mftbmp_na->data_size); 972987da915Sopenharmony_ci } 973987da915Sopenharmony_ci /* Ensure the changes make it to disk. */ 974987da915Sopenharmony_ci ntfs_inode_mark_dirty(ctx->ntfs_ino); 975987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 976987da915Sopenharmony_ci /* Initialize the mft bitmap attribute value with zeroes. */ 977987da915Sopenharmony_ci ll = 0; 978987da915Sopenharmony_ci ll = ntfs_attr_pwrite(mftbmp_na, old_initialized_size, 8, &ll); 979987da915Sopenharmony_ci if (ll == 8) { 980987da915Sopenharmony_ci ntfs_log_debug("Wrote eight initialized bytes to mft bitmap.\n"); 981987da915Sopenharmony_ci vol->free_mft_records += (8 * 8); 982987da915Sopenharmony_ci ret = 0; 983987da915Sopenharmony_ci goto out; 984987da915Sopenharmony_ci } 985987da915Sopenharmony_ci ntfs_log_error("Failed to write to mft bitmap.\n"); 986987da915Sopenharmony_ci err = errno; 987987da915Sopenharmony_ci if (ll >= 0) 988987da915Sopenharmony_ci err = EIO; 989987da915Sopenharmony_ci /* Try to recover from the error. */ 990987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL); 991987da915Sopenharmony_ci if (!ctx) 992987da915Sopenharmony_ci goto err_out; 993987da915Sopenharmony_ci 994987da915Sopenharmony_ci if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, 995987da915Sopenharmony_ci mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) { 996987da915Sopenharmony_ci ntfs_log_error("Failed to find first attribute extent of " 997987da915Sopenharmony_ci "mft bitmap attribute.%s\n", es); 998987da915Sopenharmony_ciput_err_out: 999987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1000987da915Sopenharmony_ci goto err_out; 1001987da915Sopenharmony_ci } 1002987da915Sopenharmony_ci a = ctx->attr; 1003987da915Sopenharmony_ci mftbmp_na->initialized_size = old_initialized_size; 1004987da915Sopenharmony_ci a->initialized_size = cpu_to_sle64(old_initialized_size); 1005987da915Sopenharmony_ci if (mftbmp_na->data_size != old_data_size) { 1006987da915Sopenharmony_ci mftbmp_na->data_size = old_data_size; 1007987da915Sopenharmony_ci a->data_size = cpu_to_sle64(old_data_size); 1008987da915Sopenharmony_ci } 1009987da915Sopenharmony_ci ntfs_inode_mark_dirty(ctx->ntfs_ino); 1010987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1011987da915Sopenharmony_ci ntfs_log_debug("Restored status of mftbmp: allocated_size 0x%llx, " 1012987da915Sopenharmony_ci "data_size 0x%llx, initialized_size 0x%llx.\n", 1013987da915Sopenharmony_ci (long long)mftbmp_na->allocated_size, 1014987da915Sopenharmony_ci (long long)mftbmp_na->data_size, 1015987da915Sopenharmony_ci (long long)mftbmp_na->initialized_size); 1016987da915Sopenharmony_cierr_out: 1017987da915Sopenharmony_ci errno = err; 1018987da915Sopenharmony_ciout: 1019987da915Sopenharmony_ci ntfs_log_leave("\n"); 1020987da915Sopenharmony_ci return ret; 1021987da915Sopenharmony_ci} 1022987da915Sopenharmony_ci 1023987da915Sopenharmony_ci/** 1024987da915Sopenharmony_ci * ntfs_mft_data_extend_allocation - extend mft data attribute 1025987da915Sopenharmony_ci * @vol: volume on which to extend the mft data attribute 1026987da915Sopenharmony_ci * 1027987da915Sopenharmony_ci * Extend the mft data attribute on the ntfs volume @vol by 16 mft records 1028987da915Sopenharmony_ci * worth of clusters or if not enough space for this by one mft record worth 1029987da915Sopenharmony_ci * of clusters. 1030987da915Sopenharmony_ci * 1031987da915Sopenharmony_ci * Note: Only changes allocated_size, i.e. does not touch initialized_size or 1032987da915Sopenharmony_ci * data_size. 1033987da915Sopenharmony_ci * 1034987da915Sopenharmony_ci * Return 0 on success and -1 on error with errno set to the error code. 1035987da915Sopenharmony_ci */ 1036987da915Sopenharmony_cistatic int ntfs_mft_data_extend_allocation(ntfs_volume *vol) 1037987da915Sopenharmony_ci{ 1038987da915Sopenharmony_ci LCN lcn; 1039987da915Sopenharmony_ci VCN old_last_vcn; 1040987da915Sopenharmony_ci s64 min_nr, nr, ll = 0; /* silence compiler warning */ 1041987da915Sopenharmony_ci ntfs_attr *mft_na; 1042987da915Sopenharmony_ci runlist_element *rl, *rl2; 1043987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 1044987da915Sopenharmony_ci MFT_RECORD *m = NULL; /* silence compiler warning */ 1045987da915Sopenharmony_ci ATTR_RECORD *a = NULL; /* silence compiler warning */ 1046987da915Sopenharmony_ci int err, mp_size; 1047987da915Sopenharmony_ci int ret = STATUS_ERROR; 1048987da915Sopenharmony_ci u32 old_alen = 0; /* silence compiler warning */ 1049987da915Sopenharmony_ci BOOL mp_rebuilt = FALSE; 1050987da915Sopenharmony_ci BOOL update_mp = FALSE; 1051987da915Sopenharmony_ci 1052987da915Sopenharmony_ci ntfs_log_enter("Extending mft data allocation.\n"); 1053987da915Sopenharmony_ci 1054987da915Sopenharmony_ci mft_na = vol->mft_na; 1055987da915Sopenharmony_ci /* 1056987da915Sopenharmony_ci * Determine the preferred allocation location, i.e. the last lcn of 1057987da915Sopenharmony_ci * the mft data attribute. The allocated size of the mft data 1058987da915Sopenharmony_ci * attribute cannot be zero so we are ok to do this. 1059987da915Sopenharmony_ci */ 1060987da915Sopenharmony_ci rl = ntfs_attr_find_vcn(mft_na, 1061987da915Sopenharmony_ci (mft_na->allocated_size - 1) >> vol->cluster_size_bits); 1062987da915Sopenharmony_ci 1063987da915Sopenharmony_ci if (!rl || !rl->length || rl->lcn < 0) { 1064987da915Sopenharmony_ci ntfs_log_error("Failed to determine last allocated " 1065987da915Sopenharmony_ci "cluster of mft data attribute.\n"); 1066987da915Sopenharmony_ci if (rl) 1067987da915Sopenharmony_ci errno = EIO; 1068987da915Sopenharmony_ci goto out; 1069987da915Sopenharmony_ci } 1070987da915Sopenharmony_ci 1071987da915Sopenharmony_ci lcn = rl->lcn + rl->length; 1072987da915Sopenharmony_ci ntfs_log_debug("Last lcn of mft data attribute is 0x%llx.\n", (long long)lcn); 1073987da915Sopenharmony_ci /* Minimum allocation is one mft record worth of clusters. */ 1074987da915Sopenharmony_ci min_nr = vol->mft_record_size >> vol->cluster_size_bits; 1075987da915Sopenharmony_ci if (!min_nr) 1076987da915Sopenharmony_ci min_nr = 1; 1077987da915Sopenharmony_ci /* Want to allocate 16 mft records worth of clusters. */ 1078987da915Sopenharmony_ci nr = vol->mft_record_size << 4 >> vol->cluster_size_bits; 1079987da915Sopenharmony_ci if (!nr) 1080987da915Sopenharmony_ci nr = min_nr; 1081987da915Sopenharmony_ci 1082987da915Sopenharmony_ci old_last_vcn = rl[1].vcn; 1083987da915Sopenharmony_ci do { 1084987da915Sopenharmony_ci rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE); 1085987da915Sopenharmony_ci if (rl2) 1086987da915Sopenharmony_ci break; 1087987da915Sopenharmony_ci if (errno != ENOSPC || nr == min_nr) { 1088987da915Sopenharmony_ci ntfs_log_perror("Failed to allocate (%lld) clusters " 1089987da915Sopenharmony_ci "for $MFT", (long long)nr); 1090987da915Sopenharmony_ci goto out; 1091987da915Sopenharmony_ci } 1092987da915Sopenharmony_ci /* 1093987da915Sopenharmony_ci * There is not enough space to do the allocation, but there 1094987da915Sopenharmony_ci * might be enough space to do a minimal allocation so try that 1095987da915Sopenharmony_ci * before failing. 1096987da915Sopenharmony_ci */ 1097987da915Sopenharmony_ci nr = min_nr; 1098987da915Sopenharmony_ci ntfs_log_debug("Retrying mft data allocation with minimal cluster " 1099987da915Sopenharmony_ci "count %lli.\n", (long long)nr); 1100987da915Sopenharmony_ci } while (1); 1101987da915Sopenharmony_ci 1102987da915Sopenharmony_ci ntfs_log_debug("Allocated %lld clusters.\n", (long long)nr); 1103987da915Sopenharmony_ci 1104987da915Sopenharmony_ci rl = ntfs_runlists_merge(mft_na->rl, rl2); 1105987da915Sopenharmony_ci if (!rl) { 1106987da915Sopenharmony_ci err = errno; 1107987da915Sopenharmony_ci ntfs_log_error("Failed to merge runlists for mft data " 1108987da915Sopenharmony_ci "attribute.\n"); 1109987da915Sopenharmony_ci if (ntfs_cluster_free_from_rl(vol, rl2)) 1110987da915Sopenharmony_ci ntfs_log_error("Failed to deallocate clusters " 1111987da915Sopenharmony_ci "from the mft data attribute.%s\n", es); 1112987da915Sopenharmony_ci free(rl2); 1113987da915Sopenharmony_ci errno = err; 1114987da915Sopenharmony_ci goto out; 1115987da915Sopenharmony_ci } 1116987da915Sopenharmony_ci mft_na->rl = rl; 1117987da915Sopenharmony_ci 1118987da915Sopenharmony_ci /* Find the last run in the new runlist. */ 1119987da915Sopenharmony_ci for (; rl[1].length; rl++) 1120987da915Sopenharmony_ci ; 1121987da915Sopenharmony_ci /* Update the attribute record as well. */ 1122987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL); 1123987da915Sopenharmony_ci if (!ctx) 1124987da915Sopenharmony_ci goto undo_alloc; 1125987da915Sopenharmony_ci 1126987da915Sopenharmony_ci if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, 1127987da915Sopenharmony_ci rl[1].vcn, NULL, 0, ctx)) { 1128987da915Sopenharmony_ci ntfs_log_error("Failed to find last attribute extent of " 1129987da915Sopenharmony_ci "mft data attribute.\n"); 1130987da915Sopenharmony_ci goto undo_alloc; 1131987da915Sopenharmony_ci } 1132987da915Sopenharmony_ci m = ctx->mrec; 1133987da915Sopenharmony_ci a = ctx->attr; 1134987da915Sopenharmony_ci ll = sle64_to_cpu(a->lowest_vcn); 1135987da915Sopenharmony_ci rl2 = ntfs_attr_find_vcn(mft_na, ll); 1136987da915Sopenharmony_ci if (!rl2 || !rl2->length) { 1137987da915Sopenharmony_ci ntfs_log_error("Failed to determine previous last " 1138987da915Sopenharmony_ci "allocated cluster of mft data attribute.\n"); 1139987da915Sopenharmony_ci if (rl2) 1140987da915Sopenharmony_ci errno = EIO; 1141987da915Sopenharmony_ci goto undo_alloc; 1142987da915Sopenharmony_ci } 1143987da915Sopenharmony_ci /* Get the size for the new mapping pairs array for this extent. */ 1144987da915Sopenharmony_ci mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, INT_MAX); 1145987da915Sopenharmony_ci if (mp_size <= 0) { 1146987da915Sopenharmony_ci ntfs_log_error("Get size for mapping pairs failed for " 1147987da915Sopenharmony_ci "mft data attribute extent.\n"); 1148987da915Sopenharmony_ci goto undo_alloc; 1149987da915Sopenharmony_ci } 1150987da915Sopenharmony_ci /* Expand the attribute record if necessary. */ 1151987da915Sopenharmony_ci old_alen = le32_to_cpu(a->length); 1152987da915Sopenharmony_ci if (ntfs_attr_record_resize(m, a, 1153987da915Sopenharmony_ci mp_size + le16_to_cpu(a->mapping_pairs_offset))) { 1154987da915Sopenharmony_ci ret = ntfs_mft_attr_extend(vol->mft_na); 1155987da915Sopenharmony_ci if (ret == STATUS_OK) 1156987da915Sopenharmony_ci goto ok; 1157987da915Sopenharmony_ci if (ret == STATUS_ERROR) { 1158987da915Sopenharmony_ci ntfs_log_perror("%s: ntfs_mft_attr_extend failed", __FUNCTION__); 1159987da915Sopenharmony_ci update_mp = TRUE; 1160987da915Sopenharmony_ci } 1161987da915Sopenharmony_ci goto undo_alloc; 1162987da915Sopenharmony_ci } 1163987da915Sopenharmony_ci mp_rebuilt = TRUE; 1164987da915Sopenharmony_ci /* 1165987da915Sopenharmony_ci * Generate the mapping pairs array directly into the attribute record. 1166987da915Sopenharmony_ci */ 1167987da915Sopenharmony_ci if (ntfs_mapping_pairs_build(vol, 1168987da915Sopenharmony_ci (u8*)a + le16_to_cpu(a->mapping_pairs_offset), mp_size, 1169987da915Sopenharmony_ci rl2, ll, NULL)) { 1170987da915Sopenharmony_ci ntfs_log_error("Failed to build mapping pairs array of " 1171987da915Sopenharmony_ci "mft data attribute.\n"); 1172987da915Sopenharmony_ci errno = EIO; 1173987da915Sopenharmony_ci goto undo_alloc; 1174987da915Sopenharmony_ci } 1175987da915Sopenharmony_ci /* Update the highest_vcn. */ 1176987da915Sopenharmony_ci a->highest_vcn = cpu_to_sle64(rl[1].vcn - 1); 1177987da915Sopenharmony_ci /* 1178987da915Sopenharmony_ci * We now have extended the mft data allocated_size by nr clusters. 1179987da915Sopenharmony_ci * Reflect this in the ntfs_attr structure and the attribute record. 1180987da915Sopenharmony_ci * @rl is the last (non-terminator) runlist element of mft data 1181987da915Sopenharmony_ci * attribute. 1182987da915Sopenharmony_ci */ 1183987da915Sopenharmony_ci if (a->lowest_vcn) { 1184987da915Sopenharmony_ci /* 1185987da915Sopenharmony_ci * We are not in the first attribute extent, switch to it, but 1186987da915Sopenharmony_ci * first ensure the changes will make it to disk later. 1187987da915Sopenharmony_ci */ 1188987da915Sopenharmony_ci ntfs_inode_mark_dirty(ctx->ntfs_ino); 1189987da915Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 1190987da915Sopenharmony_ci if (ntfs_attr_lookup(mft_na->type, mft_na->name, 1191987da915Sopenharmony_ci mft_na->name_len, 0, 0, NULL, 0, ctx)) { 1192987da915Sopenharmony_ci ntfs_log_error("Failed to find first attribute " 1193987da915Sopenharmony_ci "extent of mft data attribute.\n"); 1194987da915Sopenharmony_ci goto restore_undo_alloc; 1195987da915Sopenharmony_ci } 1196987da915Sopenharmony_ci a = ctx->attr; 1197987da915Sopenharmony_ci } 1198987da915Sopenharmony_ciok: 1199987da915Sopenharmony_ci mft_na->allocated_size += nr << vol->cluster_size_bits; 1200987da915Sopenharmony_ci a->allocated_size = cpu_to_sle64(mft_na->allocated_size); 1201987da915Sopenharmony_ci /* Ensure the changes make it to disk. */ 1202987da915Sopenharmony_ci ntfs_inode_mark_dirty(ctx->ntfs_ino); 1203987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1204987da915Sopenharmony_ci ret = STATUS_OK; 1205987da915Sopenharmony_ciout: 1206987da915Sopenharmony_ci ntfs_log_leave("\n"); 1207987da915Sopenharmony_ci return ret; 1208987da915Sopenharmony_ci 1209987da915Sopenharmony_cirestore_undo_alloc: 1210987da915Sopenharmony_ci err = errno; 1211987da915Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 1212987da915Sopenharmony_ci if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, 1213987da915Sopenharmony_ci rl[1].vcn, NULL, 0, ctx)) { 1214987da915Sopenharmony_ci ntfs_log_error("Failed to find last attribute extent of " 1215987da915Sopenharmony_ci "mft data attribute.%s\n", es); 1216987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1217987da915Sopenharmony_ci mft_na->allocated_size += nr << vol->cluster_size_bits; 1218987da915Sopenharmony_ci /* 1219987da915Sopenharmony_ci * The only thing that is now wrong is ->allocated_size of the 1220987da915Sopenharmony_ci * base attribute extent which chkdsk should be able to fix. 1221987da915Sopenharmony_ci */ 1222987da915Sopenharmony_ci errno = err; 1223987da915Sopenharmony_ci ret = STATUS_ERROR; 1224987da915Sopenharmony_ci goto out; 1225987da915Sopenharmony_ci } 1226987da915Sopenharmony_ci m = ctx->mrec; 1227987da915Sopenharmony_ci a = ctx->attr; 1228987da915Sopenharmony_ci a->highest_vcn = cpu_to_sle64(old_last_vcn - 1); 1229987da915Sopenharmony_ci errno = err; 1230987da915Sopenharmony_ciundo_alloc: 1231987da915Sopenharmony_ci err = errno; 1232987da915Sopenharmony_ci if (ntfs_cluster_free(vol, mft_na, old_last_vcn, -1) < 0) 1233987da915Sopenharmony_ci ntfs_log_error("Failed to free clusters from mft data " 1234987da915Sopenharmony_ci "attribute.%s\n", es); 1235987da915Sopenharmony_ci if (ntfs_rl_truncate(&mft_na->rl, old_last_vcn)) 1236987da915Sopenharmony_ci ntfs_log_error("Failed to truncate mft data attribute " 1237987da915Sopenharmony_ci "runlist.%s\n", es); 1238987da915Sopenharmony_ci if (mp_rebuilt) { 1239987da915Sopenharmony_ci if (ntfs_mapping_pairs_build(vol, (u8*)a + 1240987da915Sopenharmony_ci le16_to_cpu(a->mapping_pairs_offset), 1241987da915Sopenharmony_ci old_alen - le16_to_cpu(a->mapping_pairs_offset), 1242987da915Sopenharmony_ci rl2, ll, NULL)) 1243987da915Sopenharmony_ci ntfs_log_error("Failed to restore mapping pairs " 1244987da915Sopenharmony_ci "array.%s\n", es); 1245987da915Sopenharmony_ci if (ntfs_attr_record_resize(m, a, old_alen)) 1246987da915Sopenharmony_ci ntfs_log_error("Failed to restore attribute " 1247987da915Sopenharmony_ci "record.%s\n", es); 1248987da915Sopenharmony_ci ntfs_inode_mark_dirty(ctx->ntfs_ino); 1249987da915Sopenharmony_ci } 1250987da915Sopenharmony_ci if (update_mp) { 1251987da915Sopenharmony_ci if (ntfs_attr_update_mapping_pairs(vol->mft_na, 0)) 1252987da915Sopenharmony_ci ntfs_log_perror("%s: MP update failed", __FUNCTION__); 1253987da915Sopenharmony_ci } 1254987da915Sopenharmony_ci if (ctx) 1255987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1256987da915Sopenharmony_ci errno = err; 1257987da915Sopenharmony_ci goto out; 1258987da915Sopenharmony_ci} 1259987da915Sopenharmony_ci 1260987da915Sopenharmony_ci 1261987da915Sopenharmony_cistatic int ntfs_mft_record_init(ntfs_volume *vol, s64 size) 1262987da915Sopenharmony_ci{ 1263987da915Sopenharmony_ci int ret = -1; 1264987da915Sopenharmony_ci ntfs_attr *mft_na; 1265987da915Sopenharmony_ci s64 old_data_initialized, old_data_size; 1266987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 1267987da915Sopenharmony_ci 1268987da915Sopenharmony_ci ntfs_log_enter("Entering\n"); 1269987da915Sopenharmony_ci 1270987da915Sopenharmony_ci /* NOTE: Caller must sanity check vol, vol->mft_na and vol->mftbmp_na */ 1271987da915Sopenharmony_ci 1272987da915Sopenharmony_ci mft_na = vol->mft_na; 1273987da915Sopenharmony_ci 1274987da915Sopenharmony_ci /* 1275987da915Sopenharmony_ci * The mft record is outside the initialized data. Extend the mft data 1276987da915Sopenharmony_ci * attribute until it covers the allocated record. The loop is only 1277987da915Sopenharmony_ci * actually traversed more than once when a freshly formatted volume 1278987da915Sopenharmony_ci * is first written to so it optimizes away nicely in the common case. 1279987da915Sopenharmony_ci */ 1280987da915Sopenharmony_ci ntfs_log_debug("Status of mft data before extension: " 1281987da915Sopenharmony_ci "allocated_size 0x%llx, data_size 0x%llx, " 1282987da915Sopenharmony_ci "initialized_size 0x%llx.\n", 1283987da915Sopenharmony_ci (long long)mft_na->allocated_size, 1284987da915Sopenharmony_ci (long long)mft_na->data_size, 1285987da915Sopenharmony_ci (long long)mft_na->initialized_size); 1286987da915Sopenharmony_ci while (size > mft_na->allocated_size) { 1287987da915Sopenharmony_ci if (ntfs_mft_data_extend_allocation(vol) == STATUS_ERROR) 1288987da915Sopenharmony_ci goto out; 1289987da915Sopenharmony_ci ntfs_log_debug("Status of mft data after allocation extension: " 1290987da915Sopenharmony_ci "allocated_size 0x%llx, data_size 0x%llx, " 1291987da915Sopenharmony_ci "initialized_size 0x%llx.\n", 1292987da915Sopenharmony_ci (long long)mft_na->allocated_size, 1293987da915Sopenharmony_ci (long long)mft_na->data_size, 1294987da915Sopenharmony_ci (long long)mft_na->initialized_size); 1295987da915Sopenharmony_ci } 1296987da915Sopenharmony_ci 1297987da915Sopenharmony_ci old_data_initialized = mft_na->initialized_size; 1298987da915Sopenharmony_ci old_data_size = mft_na->data_size; 1299987da915Sopenharmony_ci 1300987da915Sopenharmony_ci /* 1301987da915Sopenharmony_ci * Extend mft data initialized size (and data size of course) to reach 1302987da915Sopenharmony_ci * the allocated mft record, formatting the mft records along the way. 1303987da915Sopenharmony_ci * Note: We only modify the ntfs_attr structure as that is all that is 1304987da915Sopenharmony_ci * needed by ntfs_mft_record_format(). We will update the attribute 1305987da915Sopenharmony_ci * record itself in one fell swoop later on. 1306987da915Sopenharmony_ci */ 1307987da915Sopenharmony_ci while (size > mft_na->initialized_size) { 1308987da915Sopenharmony_ci s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits; 1309987da915Sopenharmony_ci mft_na->initialized_size += vol->mft_record_size; 1310987da915Sopenharmony_ci if (mft_na->initialized_size > mft_na->data_size) 1311987da915Sopenharmony_ci mft_na->data_size = mft_na->initialized_size; 1312987da915Sopenharmony_ci ntfs_log_debug("Initializing mft record 0x%llx.\n", (long long)ll2); 1313987da915Sopenharmony_ci if (ntfs_mft_record_format(vol, ll2) < 0) { 1314987da915Sopenharmony_ci ntfs_log_perror("Failed to format mft record"); 1315987da915Sopenharmony_ci goto undo_data_init; 1316987da915Sopenharmony_ci } 1317987da915Sopenharmony_ci } 1318987da915Sopenharmony_ci 1319987da915Sopenharmony_ci /* Update the mft data attribute record to reflect the new sizes. */ 1320987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL); 1321987da915Sopenharmony_ci if (!ctx) 1322987da915Sopenharmony_ci goto undo_data_init; 1323987da915Sopenharmony_ci 1324987da915Sopenharmony_ci if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, 1325987da915Sopenharmony_ci 0, NULL, 0, ctx)) { 1326987da915Sopenharmony_ci ntfs_log_error("Failed to find first attribute extent of " 1327987da915Sopenharmony_ci "mft data attribute.\n"); 1328987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1329987da915Sopenharmony_ci goto undo_data_init; 1330987da915Sopenharmony_ci } 1331987da915Sopenharmony_ci ctx->attr->initialized_size = cpu_to_sle64(mft_na->initialized_size); 1332987da915Sopenharmony_ci ctx->attr->data_size = cpu_to_sle64(mft_na->data_size); 1333987da915Sopenharmony_ci ctx->attr->allocated_size = cpu_to_sle64(mft_na->allocated_size); 1334987da915Sopenharmony_ci 1335987da915Sopenharmony_ci /* Ensure the changes make it to disk. */ 1336987da915Sopenharmony_ci ntfs_inode_mark_dirty(ctx->ntfs_ino); 1337987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1338987da915Sopenharmony_ci ntfs_log_debug("Status of mft data after mft record initialization: " 1339987da915Sopenharmony_ci "allocated_size 0x%llx, data_size 0x%llx, " 1340987da915Sopenharmony_ci "initialized_size 0x%llx.\n", 1341987da915Sopenharmony_ci (long long)mft_na->allocated_size, 1342987da915Sopenharmony_ci (long long)mft_na->data_size, 1343987da915Sopenharmony_ci (long long)mft_na->initialized_size); 1344987da915Sopenharmony_ci 1345987da915Sopenharmony_ci /* Sanity checks. */ 1346987da915Sopenharmony_ci if (mft_na->data_size > mft_na->allocated_size || 1347987da915Sopenharmony_ci mft_na->initialized_size > mft_na->data_size) 1348987da915Sopenharmony_ci NTFS_BUG("mft_na sanity checks failed"); 1349987da915Sopenharmony_ci 1350987da915Sopenharmony_ci /* Sync MFT to minimize data loss if there won't be clean unmount. */ 1351987da915Sopenharmony_ci if (ntfs_inode_sync(mft_na->ni)) 1352987da915Sopenharmony_ci goto undo_data_init; 1353987da915Sopenharmony_ci 1354987da915Sopenharmony_ci ret = 0; 1355987da915Sopenharmony_ciout: 1356987da915Sopenharmony_ci ntfs_log_leave("\n"); 1357987da915Sopenharmony_ci return ret; 1358987da915Sopenharmony_ci 1359987da915Sopenharmony_ciundo_data_init: 1360987da915Sopenharmony_ci mft_na->initialized_size = old_data_initialized; 1361987da915Sopenharmony_ci mft_na->data_size = old_data_size; 1362987da915Sopenharmony_ci goto out; 1363987da915Sopenharmony_ci} 1364987da915Sopenharmony_ci 1365987da915Sopenharmony_cistatic int ntfs_mft_rec_init(ntfs_volume *vol, s64 size) 1366987da915Sopenharmony_ci{ 1367987da915Sopenharmony_ci int ret = -1; 1368987da915Sopenharmony_ci ntfs_attr *mft_na; 1369987da915Sopenharmony_ci s64 old_data_initialized, old_data_size; 1370987da915Sopenharmony_ci ntfs_attr_search_ctx *ctx; 1371987da915Sopenharmony_ci 1372987da915Sopenharmony_ci ntfs_log_enter("Entering\n"); 1373987da915Sopenharmony_ci 1374987da915Sopenharmony_ci mft_na = vol->mft_na; 1375987da915Sopenharmony_ci 1376987da915Sopenharmony_ci if (size > mft_na->allocated_size || size > mft_na->initialized_size) { 1377987da915Sopenharmony_ci errno = EIO; 1378987da915Sopenharmony_ci ntfs_log_perror("%s: unexpected $MFT sizes, see below", __FUNCTION__); 1379987da915Sopenharmony_ci ntfs_log_error("$MFT: size=%lld allocated_size=%lld " 1380987da915Sopenharmony_ci "data_size=%lld initialized_size=%lld\n", 1381987da915Sopenharmony_ci (long long)size, 1382987da915Sopenharmony_ci (long long)mft_na->allocated_size, 1383987da915Sopenharmony_ci (long long)mft_na->data_size, 1384987da915Sopenharmony_ci (long long)mft_na->initialized_size); 1385987da915Sopenharmony_ci goto out; 1386987da915Sopenharmony_ci } 1387987da915Sopenharmony_ci 1388987da915Sopenharmony_ci old_data_initialized = mft_na->initialized_size; 1389987da915Sopenharmony_ci old_data_size = mft_na->data_size; 1390987da915Sopenharmony_ci 1391987da915Sopenharmony_ci /* Update the mft data attribute record to reflect the new sizes. */ 1392987da915Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL); 1393987da915Sopenharmony_ci if (!ctx) 1394987da915Sopenharmony_ci goto undo_data_init; 1395987da915Sopenharmony_ci 1396987da915Sopenharmony_ci if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, 1397987da915Sopenharmony_ci 0, NULL, 0, ctx)) { 1398987da915Sopenharmony_ci ntfs_log_error("Failed to find first attribute extent of " 1399987da915Sopenharmony_ci "mft data attribute.\n"); 1400987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1401987da915Sopenharmony_ci goto undo_data_init; 1402987da915Sopenharmony_ci } 1403987da915Sopenharmony_ci ctx->attr->initialized_size = cpu_to_sle64(mft_na->initialized_size); 1404987da915Sopenharmony_ci ctx->attr->data_size = cpu_to_sle64(mft_na->data_size); 1405987da915Sopenharmony_ci 1406987da915Sopenharmony_ci /* CHECKME: ctx->attr->allocation_size is already ok? */ 1407987da915Sopenharmony_ci 1408987da915Sopenharmony_ci /* Ensure the changes make it to disk. */ 1409987da915Sopenharmony_ci ntfs_inode_mark_dirty(ctx->ntfs_ino); 1410987da915Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 1411987da915Sopenharmony_ci 1412987da915Sopenharmony_ci /* Sanity checks. */ 1413987da915Sopenharmony_ci if (mft_na->data_size > mft_na->allocated_size || 1414987da915Sopenharmony_ci mft_na->initialized_size > mft_na->data_size) 1415987da915Sopenharmony_ci NTFS_BUG("mft_na sanity checks failed"); 1416987da915Sopenharmony_ciout: 1417987da915Sopenharmony_ci ntfs_log_leave("\n"); 1418987da915Sopenharmony_ci return ret; 1419987da915Sopenharmony_ci 1420987da915Sopenharmony_ciundo_data_init: 1421987da915Sopenharmony_ci mft_na->initialized_size = old_data_initialized; 1422987da915Sopenharmony_ci mft_na->data_size = old_data_size; 1423987da915Sopenharmony_ci goto out; 1424987da915Sopenharmony_ci} 1425987da915Sopenharmony_ci 1426987da915Sopenharmony_cintfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol, BOOL mft_data) 1427987da915Sopenharmony_ci{ 1428987da915Sopenharmony_ci s64 ll, bit; 1429987da915Sopenharmony_ci ntfs_attr *mft_na, *mftbmp_na; 1430987da915Sopenharmony_ci MFT_RECORD *m; 1431987da915Sopenharmony_ci ntfs_inode *ni = NULL; 1432987da915Sopenharmony_ci ntfs_inode *base_ni; 1433987da915Sopenharmony_ci int err; 1434987da915Sopenharmony_ci le16 seq_no, usn; 1435987da915Sopenharmony_ci BOOL forced_mft_data; 1436987da915Sopenharmony_ci 1437987da915Sopenharmony_ci ntfs_log_enter("Entering\n"); 1438987da915Sopenharmony_ci 1439987da915Sopenharmony_ci mft_na = vol->mft_na; 1440987da915Sopenharmony_ci mftbmp_na = vol->mftbmp_na; 1441987da915Sopenharmony_ci 1442987da915Sopenharmony_ci base_ni = mft_na->ni; 1443987da915Sopenharmony_ci 1444987da915Sopenharmony_ci /* 1445987da915Sopenharmony_ci * The first extent containing $MFT:$AT_DATA is better located 1446987da915Sopenharmony_ci * in record 15 to make sure it can be read at mount time. 1447987da915Sopenharmony_ci * The record 15 is prereserved as a base inode with no 1448987da915Sopenharmony_ci * extents and no name, and it is marked in use. 1449987da915Sopenharmony_ci */ 1450987da915Sopenharmony_ci forced_mft_data = FALSE; 1451987da915Sopenharmony_ci if (mft_data) { 1452987da915Sopenharmony_ci ntfs_inode *ext_ni = ntfs_inode_open(vol, FILE_mft_data); 1453987da915Sopenharmony_ci /* 1454987da915Sopenharmony_ci * If record 15 cannot be opened, it is probably in 1455987da915Sopenharmony_ci * use as an extent. Apply standard procedure for 1456987da915Sopenharmony_ci * further extents. 1457987da915Sopenharmony_ci */ 1458987da915Sopenharmony_ci if (ext_ni) { 1459987da915Sopenharmony_ci /* 1460987da915Sopenharmony_ci * Make sure record 15 is a base extent and it has 1461987da915Sopenharmony_ci * no name. A base inode with no name cannot be in use. 1462987da915Sopenharmony_ci * The test based on base_mft_record fails for 1463987da915Sopenharmony_ci * extents of MFT, so we need a special check. 1464987da915Sopenharmony_ci * If already used, apply standard procedure. 1465987da915Sopenharmony_ci */ 1466987da915Sopenharmony_ci if (!ext_ni->mrec->base_mft_record 1467987da915Sopenharmony_ci && !ext_ni->mrec->link_count) 1468987da915Sopenharmony_ci forced_mft_data = TRUE; 1469987da915Sopenharmony_ci ntfs_inode_close(ext_ni); 1470987da915Sopenharmony_ci /* Double-check, in case it is used for MFT */ 1471987da915Sopenharmony_ci if (forced_mft_data && base_ni->nr_extents) { 1472987da915Sopenharmony_ci int i; 1473987da915Sopenharmony_ci 1474987da915Sopenharmony_ci for (i=0; i<base_ni->nr_extents; i++) { 1475987da915Sopenharmony_ci if (base_ni->extent_nis[i] 1476987da915Sopenharmony_ci && (base_ni->extent_nis[i]->mft_no 1477987da915Sopenharmony_ci == FILE_mft_data)) 1478987da915Sopenharmony_ci forced_mft_data = FALSE; 1479987da915Sopenharmony_ci } 1480987da915Sopenharmony_ci } 1481987da915Sopenharmony_ci } 1482987da915Sopenharmony_ci } 1483987da915Sopenharmony_ci if (forced_mft_data) 1484987da915Sopenharmony_ci bit = FILE_mft_data; 1485987da915Sopenharmony_ci else 1486987da915Sopenharmony_ci bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni); 1487987da915Sopenharmony_ci if (bit >= 0) 1488987da915Sopenharmony_ci goto found_free_rec; 1489987da915Sopenharmony_ci 1490987da915Sopenharmony_ci if (errno != ENOSPC) 1491987da915Sopenharmony_ci goto out; 1492987da915Sopenharmony_ci 1493987da915Sopenharmony_ci errno = ENOSPC; 1494987da915Sopenharmony_ci /* strerror() is intentionally used below, we want to log this error. */ 1495987da915Sopenharmony_ci ntfs_log_error("No free mft record for $MFT: %s\n", strerror(errno)); 1496987da915Sopenharmony_ci goto err_out; 1497987da915Sopenharmony_ci 1498987da915Sopenharmony_cifound_free_rec: 1499987da915Sopenharmony_ci if (ntfs_bitmap_set_bit(mftbmp_na, bit)) { 1500987da915Sopenharmony_ci ntfs_log_error("Failed to allocate bit in mft bitmap #2\n"); 1501987da915Sopenharmony_ci goto err_out; 1502987da915Sopenharmony_ci } 1503987da915Sopenharmony_ci 1504987da915Sopenharmony_ci ll = (bit + 1) << vol->mft_record_size_bits; 1505987da915Sopenharmony_ci if (ll > mft_na->initialized_size) 1506987da915Sopenharmony_ci if (ntfs_mft_rec_init(vol, ll) < 0) 1507987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1508987da915Sopenharmony_ci /* 1509987da915Sopenharmony_ci * We now have allocated and initialized the mft record. Need to read 1510987da915Sopenharmony_ci * it from disk and re-format it, preserving the sequence number if it 1511987da915Sopenharmony_ci * is not zero as well as the update sequence number if it is not zero 1512987da915Sopenharmony_ci * or -1 (0xffff). 1513987da915Sopenharmony_ci */ 1514987da915Sopenharmony_ci m = ntfs_malloc(vol->mft_record_size); 1515987da915Sopenharmony_ci if (!m) 1516987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1517987da915Sopenharmony_ci 1518987da915Sopenharmony_ci if (ntfs_mft_record_read(vol, bit, m)) { 1519987da915Sopenharmony_ci free(m); 1520987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1521987da915Sopenharmony_ci } 1522987da915Sopenharmony_ci /* Sanity check that the mft record is really not in use. */ 1523987da915Sopenharmony_ci if (!forced_mft_data 1524987da915Sopenharmony_ci && (ntfs_is_file_record(m->magic) 1525987da915Sopenharmony_ci && (m->flags & MFT_RECORD_IN_USE))) { 1526987da915Sopenharmony_ci ntfs_log_error("Inode %lld is used but it wasn't marked in " 1527987da915Sopenharmony_ci "$MFT bitmap. Fixed.\n", (long long)bit); 1528987da915Sopenharmony_ci free(m); 1529987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1530987da915Sopenharmony_ci } 1531987da915Sopenharmony_ci 1532987da915Sopenharmony_ci /* 1533987da915Sopenharmony_ci * Retrieve the former seq_no and usn so that the new record 1534987da915Sopenharmony_ci * cannot be mistaken for the former one. 1535987da915Sopenharmony_ci * However the original record may just be garbage, so 1536987da915Sopenharmony_ci * use some sensible value when they cannot be retrieved. 1537987da915Sopenharmony_ci */ 1538987da915Sopenharmony_ci seq_no = m->sequence_number; 1539987da915Sopenharmony_ci if (le16_to_cpu(m->usa_ofs) <= (NTFS_BLOCK_SIZE - 2)) 1540987da915Sopenharmony_ci usn = *(le16*)((u8*)m + (le16_to_cpu(m->usa_ofs) & -2)); 1541987da915Sopenharmony_ci else 1542987da915Sopenharmony_ci usn = const_cpu_to_le16(1); 1543987da915Sopenharmony_ci if (ntfs_mft_record_layout(vol, bit, m)) { 1544987da915Sopenharmony_ci ntfs_log_error("Failed to re-format mft record.\n"); 1545987da915Sopenharmony_ci free(m); 1546987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1547987da915Sopenharmony_ci } 1548987da915Sopenharmony_ci if (seq_no) 1549987da915Sopenharmony_ci m->sequence_number = seq_no; 1550987da915Sopenharmony_ci seq_no = usn; 1551987da915Sopenharmony_ci if (seq_no && seq_no != const_cpu_to_le16(0xffff)) 1552987da915Sopenharmony_ci *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = usn; 1553987da915Sopenharmony_ci /* Set the mft record itself in use. */ 1554987da915Sopenharmony_ci m->flags |= MFT_RECORD_IN_USE; 1555987da915Sopenharmony_ci /* Now need to open an ntfs inode for the mft record. */ 1556987da915Sopenharmony_ci ni = ntfs_inode_allocate(vol); 1557987da915Sopenharmony_ci if (!ni) { 1558987da915Sopenharmony_ci ntfs_log_error("Failed to allocate buffer for inode.\n"); 1559987da915Sopenharmony_ci free(m); 1560987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1561987da915Sopenharmony_ci } 1562987da915Sopenharmony_ci ni->mft_no = bit; 1563987da915Sopenharmony_ci ni->mrec = m; 1564987da915Sopenharmony_ci /* 1565987da915Sopenharmony_ci * If we are allocating an extent mft record, make the opened inode an 1566987da915Sopenharmony_ci * extent inode and attach it to the base inode. Also, set the base 1567987da915Sopenharmony_ci * mft record reference in the extent inode. 1568987da915Sopenharmony_ci */ 1569987da915Sopenharmony_ci ni->nr_extents = -1; 1570987da915Sopenharmony_ci ni->base_ni = base_ni; 1571987da915Sopenharmony_ci m->base_mft_record = MK_LE_MREF(base_ni->mft_no, 1572987da915Sopenharmony_ci le16_to_cpu(base_ni->mrec->sequence_number)); 1573987da915Sopenharmony_ci /* 1574987da915Sopenharmony_ci * Attach the extent inode to the base inode, reallocating 1575987da915Sopenharmony_ci * memory if needed. 1576987da915Sopenharmony_ci */ 1577987da915Sopenharmony_ci if (!(base_ni->nr_extents & 3)) { 1578987da915Sopenharmony_ci ntfs_inode **extent_nis; 1579987da915Sopenharmony_ci int i; 1580987da915Sopenharmony_ci 1581987da915Sopenharmony_ci i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *); 1582987da915Sopenharmony_ci extent_nis = ntfs_malloc(i); 1583987da915Sopenharmony_ci if (!extent_nis) { 1584987da915Sopenharmony_ci free(m); 1585987da915Sopenharmony_ci free(ni); 1586987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1587987da915Sopenharmony_ci } 1588987da915Sopenharmony_ci if (base_ni->nr_extents) { 1589987da915Sopenharmony_ci memcpy(extent_nis, base_ni->extent_nis, 1590987da915Sopenharmony_ci i - 4 * sizeof(ntfs_inode *)); 1591987da915Sopenharmony_ci free(base_ni->extent_nis); 1592987da915Sopenharmony_ci } 1593987da915Sopenharmony_ci base_ni->extent_nis = extent_nis; 1594987da915Sopenharmony_ci } 1595987da915Sopenharmony_ci base_ni->extent_nis[base_ni->nr_extents++] = ni; 1596987da915Sopenharmony_ci 1597987da915Sopenharmony_ci /* Make sure the allocated inode is written out to disk later. */ 1598987da915Sopenharmony_ci ntfs_inode_mark_dirty(ni); 1599987da915Sopenharmony_ci /* Initialize time, allocated and data size in ntfs_inode struct. */ 1600987da915Sopenharmony_ci ni->data_size = ni->allocated_size = 0; 1601987da915Sopenharmony_ci ni->flags = const_cpu_to_le32(0); 1602987da915Sopenharmony_ci ni->creation_time = ni->last_data_change_time = 1603987da915Sopenharmony_ci ni->last_mft_change_time = 1604987da915Sopenharmony_ci ni->last_access_time = ntfs_current_time(); 1605987da915Sopenharmony_ci /* Update the default mft allocation position if it was used. */ 1606987da915Sopenharmony_ci if (!base_ni) 1607987da915Sopenharmony_ci vol->mft_data_pos = bit + 1; 1608987da915Sopenharmony_ci /* Return the opened, allocated inode of the allocated mft record. */ 1609987da915Sopenharmony_ci ntfs_log_error("allocated %sinode %lld\n", 1610987da915Sopenharmony_ci base_ni ? "extent " : "", (long long)bit); 1611987da915Sopenharmony_ciout: 1612987da915Sopenharmony_ci ntfs_log_leave("\n"); 1613987da915Sopenharmony_ci return ni; 1614987da915Sopenharmony_ci 1615987da915Sopenharmony_ciundo_mftbmp_alloc: 1616987da915Sopenharmony_ci err = errno; 1617987da915Sopenharmony_ci if (ntfs_bitmap_clear_bit(mftbmp_na, bit)) 1618987da915Sopenharmony_ci ntfs_log_error("Failed to clear bit in mft bitmap.%s\n", es); 1619987da915Sopenharmony_ci errno = err; 1620987da915Sopenharmony_cierr_out: 1621987da915Sopenharmony_ci if (!errno) 1622987da915Sopenharmony_ci errno = EIO; 1623987da915Sopenharmony_ci ni = NULL; 1624987da915Sopenharmony_ci goto out; 1625987da915Sopenharmony_ci} 1626987da915Sopenharmony_ci 1627987da915Sopenharmony_ci/** 1628987da915Sopenharmony_ci * ntfs_mft_record_alloc - allocate an mft record on an ntfs volume 1629987da915Sopenharmony_ci * @vol: volume on which to allocate the mft record 1630987da915Sopenharmony_ci * @base_ni: open base inode if allocating an extent mft record or NULL 1631987da915Sopenharmony_ci * 1632987da915Sopenharmony_ci * Allocate an mft record in $MFT/$DATA of an open ntfs volume @vol. 1633987da915Sopenharmony_ci * 1634987da915Sopenharmony_ci * If @base_ni is NULL make the mft record a base mft record and allocate it at 1635987da915Sopenharmony_ci * the default allocator position. 1636987da915Sopenharmony_ci * 1637987da915Sopenharmony_ci * If @base_ni is not NULL make the allocated mft record an extent record, 1638987da915Sopenharmony_ci * allocate it starting at the mft record after the base mft record and attach 1639987da915Sopenharmony_ci * the allocated and opened ntfs inode to the base inode @base_ni. 1640987da915Sopenharmony_ci * 1641987da915Sopenharmony_ci * On success return the now opened ntfs (extent) inode of the mft record. 1642987da915Sopenharmony_ci * 1643987da915Sopenharmony_ci * On error return NULL with errno set to the error code. 1644987da915Sopenharmony_ci * 1645987da915Sopenharmony_ci * To find a free mft record, we scan the mft bitmap for a zero bit. To 1646987da915Sopenharmony_ci * optimize this we start scanning at the place specified by @base_ni or if 1647987da915Sopenharmony_ci * @base_ni is NULL we start where we last stopped and we perform wrap around 1648987da915Sopenharmony_ci * when we reach the end. Note, we do not try to allocate mft records below 1649987da915Sopenharmony_ci * number 24 because numbers 0 to 15 are the defined system files anyway and 16 1650987da915Sopenharmony_ci * to 24 are used for storing extension mft records or used by chkdsk to store 1651987da915Sopenharmony_ci * its log. However the record number 15 is dedicated to the first extent to 1652987da915Sopenharmony_ci * the $DATA attribute of $MFT. This is required to avoid the possibility 1653987da915Sopenharmony_ci * of creating a run list with a circular dependence which once written to disk 1654987da915Sopenharmony_ci * can never be read in again. Windows will only use records 16 to 24 for 1655987da915Sopenharmony_ci * normal files if the volume is completely out of space. We never use them 1656987da915Sopenharmony_ci * which means that when the volume is really out of space we cannot create any 1657987da915Sopenharmony_ci * more files while Windows can still create up to 8 small files. We can start 1658987da915Sopenharmony_ci * doing this at some later time, it does not matter much for now. 1659987da915Sopenharmony_ci * 1660987da915Sopenharmony_ci * When scanning the mft bitmap, we only search up to the last allocated mft 1661987da915Sopenharmony_ci * record. If there are no free records left in the range 24 to number of 1662987da915Sopenharmony_ci * allocated mft records, then we extend the $MFT/$DATA attribute in order to 1663987da915Sopenharmony_ci * create free mft records. We extend the allocated size of $MFT/$DATA by 16 1664987da915Sopenharmony_ci * records at a time or one cluster, if cluster size is above 16kiB. If there 1665987da915Sopenharmony_ci * is not sufficient space to do this, we try to extend by a single mft record 1666987da915Sopenharmony_ci * or one cluster, if cluster size is above the mft record size, but we only do 1667987da915Sopenharmony_ci * this if there is enough free space, which we know from the values returned 1668987da915Sopenharmony_ci * by the failed cluster allocation function when we tried to do the first 1669987da915Sopenharmony_ci * allocation. 1670987da915Sopenharmony_ci * 1671987da915Sopenharmony_ci * No matter how many mft records we allocate, we initialize only the first 1672987da915Sopenharmony_ci * allocated mft record, incrementing mft data size and initialized size 1673987da915Sopenharmony_ci * accordingly, open an ntfs_inode for it and return it to the caller, unless 1674987da915Sopenharmony_ci * there are less than 24 mft records, in which case we allocate and initialize 1675987da915Sopenharmony_ci * mft records until we reach record 24 which we consider as the first free mft 1676987da915Sopenharmony_ci * record for use by normal files. 1677987da915Sopenharmony_ci * 1678987da915Sopenharmony_ci * If during any stage we overflow the initialized data in the mft bitmap, we 1679987da915Sopenharmony_ci * extend the initialized size (and data size) by 8 bytes, allocating another 1680987da915Sopenharmony_ci * cluster if required. The bitmap data size has to be at least equal to the 1681987da915Sopenharmony_ci * number of mft records in the mft, but it can be bigger, in which case the 1682987da915Sopenharmony_ci * superfluous bits are padded with zeroes. 1683987da915Sopenharmony_ci * 1684987da915Sopenharmony_ci * Thus, when we return successfully (return value non-zero), we will have: 1685987da915Sopenharmony_ci * - initialized / extended the mft bitmap if necessary, 1686987da915Sopenharmony_ci * - initialized / extended the mft data if necessary, 1687987da915Sopenharmony_ci * - set the bit corresponding to the mft record being allocated in the 1688987da915Sopenharmony_ci * mft bitmap, 1689987da915Sopenharmony_ci * - open an ntfs_inode for the allocated mft record, and we will 1690987da915Sopenharmony_ci * - return the ntfs_inode. 1691987da915Sopenharmony_ci * 1692987da915Sopenharmony_ci * On error (return value zero), nothing will have changed. If we had changed 1693987da915Sopenharmony_ci * anything before the error occurred, we will have reverted back to the 1694987da915Sopenharmony_ci * starting state before returning to the caller. Thus, except for bugs, we 1695987da915Sopenharmony_ci * should always leave the volume in a consistent state when returning from 1696987da915Sopenharmony_ci * this function. 1697987da915Sopenharmony_ci * 1698987da915Sopenharmony_ci * Note, this function cannot make use of most of the normal functions, like 1699987da915Sopenharmony_ci * for example for attribute resizing, etc, because when the run list overflows 1700987da915Sopenharmony_ci * the base mft record and an attribute list is used, it is very important that 1701987da915Sopenharmony_ci * the extension mft records used to store the $DATA attribute of $MFT can be 1702987da915Sopenharmony_ci * reached without having to read the information contained inside them, as 1703987da915Sopenharmony_ci * this would make it impossible to find them in the first place after the 1704987da915Sopenharmony_ci * volume is dismounted. $MFT/$BITMAP probably does not need to follow this 1705987da915Sopenharmony_ci * rule because the bitmap is not essential for finding the mft records, but on 1706987da915Sopenharmony_ci * the other hand, handling the bitmap in this special way would make life 1707987da915Sopenharmony_ci * easier because otherwise there might be circular invocations of functions 1708987da915Sopenharmony_ci * when reading the bitmap but if we are careful, we should be able to avoid 1709987da915Sopenharmony_ci * all problems. 1710987da915Sopenharmony_ci */ 1711987da915Sopenharmony_cintfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni) 1712987da915Sopenharmony_ci{ 1713987da915Sopenharmony_ci s64 ll, bit; 1714987da915Sopenharmony_ci ntfs_attr *mft_na, *mftbmp_na; 1715987da915Sopenharmony_ci MFT_RECORD *m; 1716987da915Sopenharmony_ci ntfs_inode *ni = NULL; 1717987da915Sopenharmony_ci int err; 1718987da915Sopenharmony_ci u32 usa_ofs; 1719987da915Sopenharmony_ci le16 seq_no, usn; 1720987da915Sopenharmony_ci BOOL oldwarn; 1721987da915Sopenharmony_ci 1722987da915Sopenharmony_ci if (base_ni) 1723987da915Sopenharmony_ci ntfs_log_enter("Entering (allocating an extent mft record for " 1724987da915Sopenharmony_ci "base mft record %lld).\n", 1725987da915Sopenharmony_ci (long long)base_ni->mft_no); 1726987da915Sopenharmony_ci else 1727987da915Sopenharmony_ci ntfs_log_enter("Entering (allocating a base mft record)\n"); 1728987da915Sopenharmony_ci if (!vol || !vol->mft_na || !vol->mftbmp_na) { 1729987da915Sopenharmony_ci errno = EINVAL; 1730987da915Sopenharmony_ci goto out; 1731987da915Sopenharmony_ci } 1732987da915Sopenharmony_ci 1733987da915Sopenharmony_ci if (ntfs_is_mft(base_ni)) { 1734987da915Sopenharmony_ci ni = ntfs_mft_rec_alloc(vol, FALSE); 1735987da915Sopenharmony_ci goto out; 1736987da915Sopenharmony_ci } 1737987da915Sopenharmony_ci 1738987da915Sopenharmony_ci mft_na = vol->mft_na; 1739987da915Sopenharmony_ci mftbmp_na = vol->mftbmp_na; 1740987da915Sopenharmony_ciretry: 1741987da915Sopenharmony_ci bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni); 1742987da915Sopenharmony_ci if (bit >= 0) { 1743987da915Sopenharmony_ci ntfs_log_debug("found free record (#1) at %lld\n", 1744987da915Sopenharmony_ci (long long)bit); 1745987da915Sopenharmony_ci goto found_free_rec; 1746987da915Sopenharmony_ci } 1747987da915Sopenharmony_ci if (errno != ENOSPC) 1748987da915Sopenharmony_ci goto out; 1749987da915Sopenharmony_ci /* 1750987da915Sopenharmony_ci * No free mft records left. If the mft bitmap already covers more 1751987da915Sopenharmony_ci * than the currently used mft records, the next records are all free, 1752987da915Sopenharmony_ci * so we can simply allocate the first unused mft record. 1753987da915Sopenharmony_ci * Note: We also have to make sure that the mft bitmap at least covers 1754987da915Sopenharmony_ci * the first 24 mft records as they are special and whilst they may not 1755987da915Sopenharmony_ci * be in use, we do not allocate from them. 1756987da915Sopenharmony_ci */ 1757987da915Sopenharmony_ci ll = mft_na->initialized_size >> vol->mft_record_size_bits; 1758987da915Sopenharmony_ci if (mftbmp_na->initialized_size << 3 > ll && 1759987da915Sopenharmony_ci mftbmp_na->initialized_size > RESERVED_MFT_RECORDS / 8) { 1760987da915Sopenharmony_ci bit = ll; 1761987da915Sopenharmony_ci if (bit < RESERVED_MFT_RECORDS) 1762987da915Sopenharmony_ci bit = RESERVED_MFT_RECORDS; 1763987da915Sopenharmony_ci ntfs_log_debug("found free record (#2) at %lld\n", 1764987da915Sopenharmony_ci (long long)bit); 1765987da915Sopenharmony_ci goto found_free_rec; 1766987da915Sopenharmony_ci } 1767987da915Sopenharmony_ci /* 1768987da915Sopenharmony_ci * The mft bitmap needs to be expanded until it covers the first unused 1769987da915Sopenharmony_ci * mft record that we can allocate. 1770987da915Sopenharmony_ci * Note: The smallest mft record we allocate is mft record 24. 1771987da915Sopenharmony_ci */ 1772987da915Sopenharmony_ci ntfs_log_debug("Status of mftbmp before extension: allocated_size 0x%llx, " 1773987da915Sopenharmony_ci "data_size 0x%llx, initialized_size 0x%llx.\n", 1774987da915Sopenharmony_ci (long long)mftbmp_na->allocated_size, 1775987da915Sopenharmony_ci (long long)mftbmp_na->data_size, 1776987da915Sopenharmony_ci (long long)mftbmp_na->initialized_size); 1777987da915Sopenharmony_ci if (mftbmp_na->initialized_size + 8 > mftbmp_na->allocated_size) { 1778987da915Sopenharmony_ci 1779987da915Sopenharmony_ci int ret = ntfs_mft_bitmap_extend_allocation(vol); 1780987da915Sopenharmony_ci 1781987da915Sopenharmony_ci if (ret == STATUS_ERROR) 1782987da915Sopenharmony_ci goto err_out; 1783987da915Sopenharmony_ci if (ret == STATUS_KEEP_SEARCHING) { 1784987da915Sopenharmony_ci ret = ntfs_mft_bitmap_extend_allocation(vol); 1785987da915Sopenharmony_ci if (ret != STATUS_OK) 1786987da915Sopenharmony_ci goto err_out; 1787987da915Sopenharmony_ci } 1788987da915Sopenharmony_ci 1789987da915Sopenharmony_ci ntfs_log_debug("Status of mftbmp after allocation extension: " 1790987da915Sopenharmony_ci "allocated_size 0x%llx, data_size 0x%llx, " 1791987da915Sopenharmony_ci "initialized_size 0x%llx.\n", 1792987da915Sopenharmony_ci (long long)mftbmp_na->allocated_size, 1793987da915Sopenharmony_ci (long long)mftbmp_na->data_size, 1794987da915Sopenharmony_ci (long long)mftbmp_na->initialized_size); 1795987da915Sopenharmony_ci } 1796987da915Sopenharmony_ci /* 1797987da915Sopenharmony_ci * We now have sufficient allocated space, extend the initialized_size 1798987da915Sopenharmony_ci * as well as the data_size if necessary and fill the new space with 1799987da915Sopenharmony_ci * zeroes. 1800987da915Sopenharmony_ci */ 1801987da915Sopenharmony_ci bit = mftbmp_na->initialized_size << 3; 1802987da915Sopenharmony_ci if (ntfs_mft_bitmap_extend_initialized(vol)) 1803987da915Sopenharmony_ci goto err_out; 1804987da915Sopenharmony_ci ntfs_log_debug("Status of mftbmp after initialized extension: " 1805987da915Sopenharmony_ci "allocated_size 0x%llx, data_size 0x%llx, " 1806987da915Sopenharmony_ci "initialized_size 0x%llx.\n", 1807987da915Sopenharmony_ci (long long)mftbmp_na->allocated_size, 1808987da915Sopenharmony_ci (long long)mftbmp_na->data_size, 1809987da915Sopenharmony_ci (long long)mftbmp_na->initialized_size); 1810987da915Sopenharmony_ci ntfs_log_debug("found free record (#3) at %lld\n", (long long)bit); 1811987da915Sopenharmony_cifound_free_rec: 1812987da915Sopenharmony_ci /* @bit is the found free mft record, allocate it in the mft bitmap. */ 1813987da915Sopenharmony_ci if (ntfs_bitmap_set_bit(mftbmp_na, bit)) { 1814987da915Sopenharmony_ci ntfs_log_error("Failed to allocate bit in mft bitmap.\n"); 1815987da915Sopenharmony_ci goto err_out; 1816987da915Sopenharmony_ci } 1817987da915Sopenharmony_ci 1818987da915Sopenharmony_ci /* The mft bitmap is now uptodate. Deal with mft data attribute now. */ 1819987da915Sopenharmony_ci ll = (bit + 1) << vol->mft_record_size_bits; 1820987da915Sopenharmony_ci if (ll > mft_na->initialized_size) 1821987da915Sopenharmony_ci if (ntfs_mft_record_init(vol, ll) < 0) 1822987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1823987da915Sopenharmony_ci 1824987da915Sopenharmony_ci /* 1825987da915Sopenharmony_ci * We now have allocated and initialized the mft record. Need to read 1826987da915Sopenharmony_ci * it from disk and re-format it, preserving the sequence number if it 1827987da915Sopenharmony_ci * is not zero as well as the update sequence number if it is not zero 1828987da915Sopenharmony_ci * or -1 (0xffff). 1829987da915Sopenharmony_ci */ 1830987da915Sopenharmony_ci m = ntfs_malloc(vol->mft_record_size); 1831987da915Sopenharmony_ci if (!m) 1832987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1833987da915Sopenharmony_ci 1834987da915Sopenharmony_ci /* 1835987da915Sopenharmony_ci * As this is allocating a new record, do not expect it to have 1836987da915Sopenharmony_ci * been initialized previously, so do not warn over bad fixups 1837987da915Sopenharmony_ci * (hence avoid warn flooding when an NTFS partition has been wiped). 1838987da915Sopenharmony_ci */ 1839987da915Sopenharmony_ci oldwarn = !NVolNoFixupWarn(vol); 1840987da915Sopenharmony_ci NVolSetNoFixupWarn(vol); 1841987da915Sopenharmony_ci if (ntfs_mft_record_read(vol, bit, m)) { 1842987da915Sopenharmony_ci if (oldwarn) 1843987da915Sopenharmony_ci NVolClearNoFixupWarn(vol); 1844987da915Sopenharmony_ci free(m); 1845987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1846987da915Sopenharmony_ci } 1847987da915Sopenharmony_ci if (oldwarn) 1848987da915Sopenharmony_ci NVolClearNoFixupWarn(vol); 1849987da915Sopenharmony_ci 1850987da915Sopenharmony_ci /* Sanity check that the mft record is really not in use. */ 1851987da915Sopenharmony_ci if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) { 1852987da915Sopenharmony_ci ntfs_log_error("Inode %lld is used but it wasn't marked in " 1853987da915Sopenharmony_ci "$MFT bitmap. Fixed.\n", (long long)bit); 1854987da915Sopenharmony_ci free(m); 1855987da915Sopenharmony_ci goto retry; 1856987da915Sopenharmony_ci } 1857987da915Sopenharmony_ci seq_no = m->sequence_number; 1858987da915Sopenharmony_ci /* 1859987da915Sopenharmony_ci * As ntfs_mft_record_read() returns what has been read 1860987da915Sopenharmony_ci * even when the fixups have been found bad, we have to 1861987da915Sopenharmony_ci * check where we fetch the initial usn from. 1862987da915Sopenharmony_ci */ 1863987da915Sopenharmony_ci usa_ofs = le16_to_cpu(m->usa_ofs); 1864987da915Sopenharmony_ci if (!(usa_ofs & 1) && (usa_ofs < NTFS_BLOCK_SIZE)) { 1865987da915Sopenharmony_ci usn = *(le16*)((u8*)m + usa_ofs); 1866987da915Sopenharmony_ci } else 1867987da915Sopenharmony_ci usn = const_cpu_to_le16(1); 1868987da915Sopenharmony_ci if (ntfs_mft_record_layout(vol, bit, m)) { 1869987da915Sopenharmony_ci ntfs_log_error("Failed to re-format mft record.\n"); 1870987da915Sopenharmony_ci free(m); 1871987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1872987da915Sopenharmony_ci } 1873987da915Sopenharmony_ci if (seq_no) 1874987da915Sopenharmony_ci m->sequence_number = seq_no; 1875987da915Sopenharmony_ci seq_no = usn; 1876987da915Sopenharmony_ci if (seq_no && seq_no != const_cpu_to_le16(0xffff)) 1877987da915Sopenharmony_ci *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = usn; 1878987da915Sopenharmony_ci /* Set the mft record itself in use. */ 1879987da915Sopenharmony_ci m->flags |= MFT_RECORD_IN_USE; 1880987da915Sopenharmony_ci /* Now need to open an ntfs inode for the mft record. */ 1881987da915Sopenharmony_ci ni = ntfs_inode_allocate(vol); 1882987da915Sopenharmony_ci if (!ni) { 1883987da915Sopenharmony_ci ntfs_log_error("Failed to allocate buffer for inode.\n"); 1884987da915Sopenharmony_ci free(m); 1885987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1886987da915Sopenharmony_ci } 1887987da915Sopenharmony_ci ni->mft_no = bit; 1888987da915Sopenharmony_ci ni->mrec = m; 1889987da915Sopenharmony_ci /* 1890987da915Sopenharmony_ci * If we are allocating an extent mft record, make the opened inode an 1891987da915Sopenharmony_ci * extent inode and attach it to the base inode. Also, set the base 1892987da915Sopenharmony_ci * mft record reference in the extent inode. 1893987da915Sopenharmony_ci */ 1894987da915Sopenharmony_ci if (base_ni) { 1895987da915Sopenharmony_ci ni->nr_extents = -1; 1896987da915Sopenharmony_ci ni->base_ni = base_ni; 1897987da915Sopenharmony_ci m->base_mft_record = MK_LE_MREF(base_ni->mft_no, 1898987da915Sopenharmony_ci le16_to_cpu(base_ni->mrec->sequence_number)); 1899987da915Sopenharmony_ci /* 1900987da915Sopenharmony_ci * Attach the extent inode to the base inode, reallocating 1901987da915Sopenharmony_ci * memory if needed. 1902987da915Sopenharmony_ci */ 1903987da915Sopenharmony_ci if (!(base_ni->nr_extents & 3)) { 1904987da915Sopenharmony_ci ntfs_inode **extent_nis; 1905987da915Sopenharmony_ci int i; 1906987da915Sopenharmony_ci 1907987da915Sopenharmony_ci i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *); 1908987da915Sopenharmony_ci extent_nis = ntfs_malloc(i); 1909987da915Sopenharmony_ci if (!extent_nis) { 1910987da915Sopenharmony_ci free(m); 1911987da915Sopenharmony_ci free(ni); 1912987da915Sopenharmony_ci goto undo_mftbmp_alloc; 1913987da915Sopenharmony_ci } 1914987da915Sopenharmony_ci if (base_ni->nr_extents) { 1915987da915Sopenharmony_ci memcpy(extent_nis, base_ni->extent_nis, 1916987da915Sopenharmony_ci i - 4 * sizeof(ntfs_inode *)); 1917987da915Sopenharmony_ci free(base_ni->extent_nis); 1918987da915Sopenharmony_ci } 1919987da915Sopenharmony_ci base_ni->extent_nis = extent_nis; 1920987da915Sopenharmony_ci } 1921987da915Sopenharmony_ci base_ni->extent_nis[base_ni->nr_extents++] = ni; 1922987da915Sopenharmony_ci } 1923987da915Sopenharmony_ci /* Make sure the allocated inode is written out to disk later. */ 1924987da915Sopenharmony_ci ntfs_inode_mark_dirty(ni); 1925987da915Sopenharmony_ci /* Initialize time, allocated and data size in ntfs_inode struct. */ 1926987da915Sopenharmony_ci ni->data_size = ni->allocated_size = 0; 1927987da915Sopenharmony_ci ni->flags = const_cpu_to_le32(0); 1928987da915Sopenharmony_ci ni->creation_time = ni->last_data_change_time = 1929987da915Sopenharmony_ci ni->last_mft_change_time = 1930987da915Sopenharmony_ci ni->last_access_time = ntfs_current_time(); 1931987da915Sopenharmony_ci /* Update the default mft allocation position if it was used. */ 1932987da915Sopenharmony_ci if (!base_ni) 1933987da915Sopenharmony_ci vol->mft_data_pos = bit + 1; 1934987da915Sopenharmony_ci /* Return the opened, allocated inode of the allocated mft record. */ 1935987da915Sopenharmony_ci ntfs_log_debug("allocated %sinode 0x%llx.\n", 1936987da915Sopenharmony_ci base_ni ? "extent " : "", (long long)bit); 1937987da915Sopenharmony_ci vol->free_mft_records--; 1938987da915Sopenharmony_ciout: 1939987da915Sopenharmony_ci ntfs_log_leave("\n"); 1940987da915Sopenharmony_ci return ni; 1941987da915Sopenharmony_ci 1942987da915Sopenharmony_ciundo_mftbmp_alloc: 1943987da915Sopenharmony_ci err = errno; 1944987da915Sopenharmony_ci if (ntfs_bitmap_clear_bit(mftbmp_na, bit)) 1945987da915Sopenharmony_ci ntfs_log_error("Failed to clear bit in mft bitmap.%s\n", es); 1946987da915Sopenharmony_ci errno = err; 1947987da915Sopenharmony_cierr_out: 1948987da915Sopenharmony_ci if (!errno) 1949987da915Sopenharmony_ci errno = EIO; 1950987da915Sopenharmony_ci ni = NULL; 1951987da915Sopenharmony_ci goto out; 1952987da915Sopenharmony_ci} 1953987da915Sopenharmony_ci 1954987da915Sopenharmony_ci/** 1955987da915Sopenharmony_ci * ntfs_mft_record_free - free an mft record on an ntfs volume 1956987da915Sopenharmony_ci * @vol: volume on which to free the mft record 1957987da915Sopenharmony_ci * @ni: open ntfs inode of the mft record to free 1958987da915Sopenharmony_ci * 1959987da915Sopenharmony_ci * Free the mft record of the open inode @ni on the mounted ntfs volume @vol. 1960987da915Sopenharmony_ci * Note that this function calls ntfs_inode_close() internally and hence you 1961987da915Sopenharmony_ci * cannot use the pointer @ni any more after this function returns success. 1962987da915Sopenharmony_ci * 1963987da915Sopenharmony_ci * On success return 0 and on error return -1 with errno set to the error code. 1964987da915Sopenharmony_ci */ 1965987da915Sopenharmony_ciint ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni) 1966987da915Sopenharmony_ci{ 1967987da915Sopenharmony_ci u64 mft_no; 1968987da915Sopenharmony_ci int err; 1969987da915Sopenharmony_ci u16 seq_no; 1970987da915Sopenharmony_ci le16 old_seq_no; 1971987da915Sopenharmony_ci 1972987da915Sopenharmony_ci ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); 1973987da915Sopenharmony_ci 1974987da915Sopenharmony_ci if (!vol || !vol->mftbmp_na || !ni) { 1975987da915Sopenharmony_ci errno = EINVAL; 1976987da915Sopenharmony_ci return -1; 1977987da915Sopenharmony_ci } 1978987da915Sopenharmony_ci 1979987da915Sopenharmony_ci /* Cache the mft reference for later. */ 1980987da915Sopenharmony_ci mft_no = ni->mft_no; 1981987da915Sopenharmony_ci 1982987da915Sopenharmony_ci /* Mark the mft record as not in use. */ 1983987da915Sopenharmony_ci ni->mrec->flags &= ~MFT_RECORD_IN_USE; 1984987da915Sopenharmony_ci 1985987da915Sopenharmony_ci /* Increment the sequence number, skipping zero, if it is not zero. */ 1986987da915Sopenharmony_ci old_seq_no = ni->mrec->sequence_number; 1987987da915Sopenharmony_ci seq_no = le16_to_cpu(old_seq_no); 1988987da915Sopenharmony_ci if (seq_no == 0xffff) 1989987da915Sopenharmony_ci seq_no = 1; 1990987da915Sopenharmony_ci else if (seq_no) 1991987da915Sopenharmony_ci seq_no++; 1992987da915Sopenharmony_ci ni->mrec->sequence_number = cpu_to_le16(seq_no); 1993987da915Sopenharmony_ci 1994987da915Sopenharmony_ci /* Set the inode dirty and write it out. */ 1995987da915Sopenharmony_ci ntfs_inode_mark_dirty(ni); 1996987da915Sopenharmony_ci if (ntfs_inode_sync(ni)) { 1997987da915Sopenharmony_ci err = errno; 1998987da915Sopenharmony_ci goto sync_rollback; 1999987da915Sopenharmony_ci } 2000987da915Sopenharmony_ci 2001987da915Sopenharmony_ci /* Clear the bit in the $MFT/$BITMAP corresponding to this record. */ 2002987da915Sopenharmony_ci if (ntfs_bitmap_clear_bit(vol->mftbmp_na, mft_no)) { 2003987da915Sopenharmony_ci err = errno; 2004987da915Sopenharmony_ci // FIXME: If ntfs_bitmap_clear_run() guarantees rollback on 2005987da915Sopenharmony_ci // error, this could be changed to goto sync_rollback; 2006987da915Sopenharmony_ci goto bitmap_rollback; 2007987da915Sopenharmony_ci } 2008987da915Sopenharmony_ci 2009987da915Sopenharmony_ci /* Throw away the now freed inode. */ 2010987da915Sopenharmony_ci#if CACHE_NIDATA_SIZE 2011987da915Sopenharmony_ci if (!ntfs_inode_real_close(ni)) { 2012987da915Sopenharmony_ci#else 2013987da915Sopenharmony_ci if (!ntfs_inode_close(ni)) { 2014987da915Sopenharmony_ci#endif 2015987da915Sopenharmony_ci vol->free_mft_records++; 2016987da915Sopenharmony_ci return 0; 2017987da915Sopenharmony_ci } 2018987da915Sopenharmony_ci err = errno; 2019987da915Sopenharmony_ci 2020987da915Sopenharmony_ci /* Rollback what we did... */ 2021987da915Sopenharmony_cibitmap_rollback: 2022987da915Sopenharmony_ci if (ntfs_bitmap_set_bit(vol->mftbmp_na, mft_no)) 2023987da915Sopenharmony_ci ntfs_log_debug("Eeek! Rollback failed in ntfs_mft_record_free(). " 2024987da915Sopenharmony_ci "Leaving inconsistent metadata!\n"); 2025987da915Sopenharmony_cisync_rollback: 2026987da915Sopenharmony_ci ni->mrec->flags |= MFT_RECORD_IN_USE; 2027987da915Sopenharmony_ci ni->mrec->sequence_number = old_seq_no; 2028987da915Sopenharmony_ci ntfs_inode_mark_dirty(ni); 2029987da915Sopenharmony_ci errno = err; 2030987da915Sopenharmony_ci return -1; 2031987da915Sopenharmony_ci} 2032987da915Sopenharmony_ci 2033987da915Sopenharmony_ci/** 2034987da915Sopenharmony_ci * ntfs_mft_usn_dec - Decrement USN by one 2035987da915Sopenharmony_ci * @mrec: pointer to an mft record 2036987da915Sopenharmony_ci * 2037987da915Sopenharmony_ci * On success return 0 and on error return -1 with errno set. 2038987da915Sopenharmony_ci */ 2039987da915Sopenharmony_ciint ntfs_mft_usn_dec(MFT_RECORD *mrec) 2040987da915Sopenharmony_ci{ 2041987da915Sopenharmony_ci u16 usn; 2042987da915Sopenharmony_ci le16 *usnp; 2043987da915Sopenharmony_ci 2044987da915Sopenharmony_ci if (!mrec) { 2045987da915Sopenharmony_ci errno = EINVAL; 2046987da915Sopenharmony_ci return -1; 2047987da915Sopenharmony_ci } 2048987da915Sopenharmony_ci usnp = (le16*)((char*)mrec + le16_to_cpu(mrec->usa_ofs)); 2049987da915Sopenharmony_ci usn = le16_to_cpup(usnp); 2050987da915Sopenharmony_ci if (usn-- <= 1) 2051987da915Sopenharmony_ci usn = 0xfffe; 2052987da915Sopenharmony_ci *usnp = cpu_to_le16(usn); 2053987da915Sopenharmony_ci 2054987da915Sopenharmony_ci return 0; 2055987da915Sopenharmony_ci} 2056987da915Sopenharmony_ci 2057