1N/A * mkntfs - Part of the Linux-NTFS project. 1N/A * Copyright (c) 2000-2007 Anton Altaparmakov 1N/A * Copyright (c) 2001-2005 Richard Russon 1N/A * Copyright (c) 2002-2006 Szabolcs Szakacsits 1N/A * Copyright (c) 2005 Erik Sornes 1N/A * Copyright (c) 2007 Yura Pakhuchiy 1N/A * This utility will create an NTFS 1.2 or 3.1 volume on a user 1N/A * specified (block) device. 1N/A * Some things (option handling and determination of mount status) have been 1N/A * This program is free software; you can redistribute it and/or modify 1N/A * it under the terms of the GNU General Public License as published by 1N/A * the Free Software Foundation; either version 2 of the License, or 1N/A * (at your option) any later version. 1N/A * This program is distributed in the hope that it will be useful, 1N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of 1N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1N/A * GNU General Public License for more details. 1N/A * You should have received a copy of the GNU General Public License 1N/A * along with this program (in the main directory of the Linux-NTFS source 1N/A * in the file COPYING); if not, write to the Free Software Foundation, 1N/A * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1N/A#
error "No default device io operations! Cannot build mkntfs. \ 1N/AYou need to run ./configure without the --disable-default-device-io-ops \ 1N/Aswitch if you want to be able to build the NTFS utilities." 1N/A/* Page size on ia32. Can change to 8192 on Alpha. */ 1N/Astatic long long g_mft_lcn = 0;
/* lcn of $MFT, $DATA attribute */ 1N/Astatic long long g_mft_zone_end = 0;
/* Determined from volume_size and mft_zone_multiplier, in clusters */ 1N/A * struct mkntfs_options 1N/A char *
dev_name;
/* Name of the device, or file, to use */ 1N/A long heads;
/* -H, number of heads on device */ 1N/A BOOL no_action;
/* -n, do not write to device, only display what would be done. */ 1N/A long sector_size;
/* -s, in bytes, power of 2, default is 512 bytes. */ 1N/A" -f, --fast Perform a quick format\n" 1N/A" -Q, --quick Perform a quick format\n" 1N/A" -L, --label STRING Set the volume label\n" 1N/A" -C, --enable-compression Enable compression on the volume\n" 1N/A" -I, --no-indexing Disable indexing on the volume\n" 1N/A" -n, --no-action Do not write to disk\n" 1N/A"Advanced options:\n" 1N/A" -c, --cluster-size BYTES Specify the cluster size for the volume\n" 1N/A" -s, --sector-size BYTES Specify the sector size for the device\n" 1N/A" -p, --partition-start SECTOR Specify the partition start sector\n" 1N/A" -H, --heads NUM Specify the number of heads\n" 1N/A" -S, --sectors-per-track NUM Specify the number of sectors per track\n" 1N/A" -z, --mft-zone-multiplier NUM Set the MFT zone multiplier\n" 1N/A" -T, --zero-time Fake the time to be 00:00 UTC, Jan 1, 1970\n" 1N/A" -F, --force Force execution despite errors\n" 1N/A" -q, --quiet Quiet execution\n" 1N/A" -v, --verbose Verbose execution\n" 1N/A" --debug Very verbose execution\n" 1N/A" -V, --version Display version\n" 1N/A" -l, --license Display licensing information\n" 1N/A" -h, --help Display this help\n" 1N/A * mkntfs_parse_llong 1N/A * mkntfs_init_options 1N/A /* Mark all the numeric options as "unset". */ 1N/A * mkntfs_parse_options 1N/A static const char *
sopt =
"-c:CfFhH:IlL:np:qQs:S:TvVz:";
1N/A "mkntfs_options.\n");
1N/A opterr = 0;
/* We'll handle the errors, thank you. */ 1N/A case 1:
/* A device, or a number of sectors */ 1N/A "number of sectors",
1N/A case 'f':
/* fast */ 1N/A case 'Q':
/* quick */ 1N/A lic++;
/* display the license */ 1N/A ver++;
/* display version info */ 1N/A case 'Z':
/* debug - turn on everything */ 1N/A * append_to_bad_blocks 1N/A * ntfs_rlwrite - Write data to disk on clusters found in a runlist. 1N/A * Write to disk the clusters contained in the runlist @rl taking the data 1N/A * from @val. Take @val_len bytes from @val and pad the rest with zeroes. 1N/A * If the @rl specifies a completely sparse file, @val is allowed to be NULL. 1N/A * @inited_size if not NULL points to an output variable which will contain 1N/A * the actual number of bytes written to disk. I.e. this will not include 1N/A * sparse bytes for example. 1N/A * Return the number of bytes written (minus padding) or -1 on error. Errno 1N/A * will be set to the error code. 1N/A /* Don't write sparse runs. */ 1N/A /* TODO: Check that *val is really zero at pos and len. */ 1N/A * Break up the write into the real data write and then a write 1N/A * of zeroes between the end of the real data and the end of 1N/A * make_room_for_attribute - make room for an attribute inside an mft record 1N/A * @pos: position at which to make space 1N/A * @size: byte size to make available at this position 1N/A * @pos points to the attribute in front of which we want to make space. 1N/A * Return 0 on success or -errno on error. Possible error codes are: 1N/A * -ENOSPC There is not enough space available to complete 1N/A * operation. The caller has to make space before calling 1N/A * -EINVAL Can only occur if mkntfs was compiled with -DDEBUG. Means 1N/A * the input parameters were faulty. 1N/A * Rigorous consistency checks. Always return -EINVAL even if more 1N/A * appropriate codes exist for simplicity of parsing the return value. 1N/A /* The -8 is for the attribute terminator. */ 1N/A /* Do we have enough space? */ 1N/A /* Move everything after pos to pos + size. */ 1N/A /* Update mft record. */ 1N/A * deallocate_scattered_clusters 1N/A /* Iterate over all runs in the runlist @rl. */ 1N/A /* Skip sparse runs. */ 1N/A /* Deallocate the current run. */ 1N/A * allocate_scattered_clusters 1N/A * @clusters: Amount of clusters to allocate. 1N/A * Allocate @clusters and create a runlist of the allocated clusters. 1N/A * Return the allocated runlist. Caller has to free the runlist when finished 1N/A * On error return NULL and errno is set to the error code. 1N/A * TODO: We should be returning the size as well, but for mkntfs this is not 1N/A /* Loop until all clusters are allocated. */ 1N/A /* Loop in current zone until we run out of free clusters. */ 1N/A * Reallocate memory if necessary. Make sure we have 1N/A * enough for the terminator entry as well. 1N/A /* Coalesce with previous run if adjacent LCNs. */ 1N/A /* Add terminator element and return. */ 1N/A /* Switch to next zone, decreasing mft zone by factor 2. */ 1N/A /* Have we run out of space on the volume? */ 1N/A /* Add terminator element. */ 1N/A /* Deallocate all allocated clusters. */ 1N/A /* Free the runlist. */ 1N/A * ntfs_attr_find - find (next) attribute in mft record 1N/A * @type: attribute type to find 1N/A * @name: attribute name to find (optional, i.e. NULL means don't care) 1N/A * @name_len: attribute name length (only needed if @name present) 1N/A * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 1N/A * @val: attribute value to find (optional, resident attributes only) 1N/A * @val_len: attribute value length 1N/A * @ctx: search context with mft record and attribute to search from 1N/A * You shouldn't need to call this function directly. Use lookup_attr() instead. 1N/A * ntfs_attr_find() takes a search context @ctx as parameter and searches the 1N/A * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an 1N/A * attribute of @type, optionally @name and @val. If found, ntfs_attr_find() 1N/A * returns 0 and @ctx->attr will point to the found attribute. 1N/A * If not found, ntfs_attr_find() returns -1, with errno set to ENOENT and 1N/A * @ctx->attr will point to the attribute before which the attribute being 1N/A * searched for would need to be inserted if such an action were to be desired. 1N/A * On actual error, ntfs_attr_find() returns -1 with errno set to the error 1N/A * code but not to ENOENT. In this case @ctx->attr is undefined and in 1N/A * particular do not rely on it not changing. 1N/A * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it 1N/A * is FALSE, the search begins after @ctx->attr. 1N/A * If @type is AT_UNUSED, return the first found attribute, i.e. one can 1N/A * enumerate all attributes by setting @type to AT_UNUSED and then calling 1N/A * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to 1N/A * indicate that there are no more entries. During the enumeration, each 1N/A * successful call of ntfs_attr_find() will return the next attribute in the 1N/A * mft record @ctx->mrec. 1N/A * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT. 1N/A * AT_END is not a valid attribute, its length is zero for example, thus it is 1N/A * safer to return error instead of success in this case. This also allows us 1N/A * to interoperate cleanly with ntfs_external_attr_find(). 1N/A * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present 1N/A * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, 1N/A * match both named and unnamed attributes. 1N/A * If @ic is IGNORE_CASE, the @name comparison is not case sensitive and 1N/A * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record 1N/A * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at 1N/A * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case 1N/A * sensitive. When @name is present, @name_len is the @name length in Unicode 1N/A * If @name is not present (NULL), we assume that the unnamed attribute is 1N/A * being searched for. 1N/A * Finally, the resident attribute value @val is looked for, if present. 1N/A * If @val is not present (NULL), @val_len is ignored. 1N/A * ntfs_attr_find() only searches the specified mft record and it ignores the 1N/A * presence of an attribute list attribute (unless it is the one being searched 1N/A * for, obviously). If you need to take attribute lists into consideration, use 1N/A * ntfs_attr_lookup() instead (see below). This also means that you cannot use 1N/A * ntfs_attr_find() to search for extent records of non-resident attributes, as 1N/A * extents with lowest_vcn != 0 are usually described by the attribute list 1N/A * attribute only. - Note that it is possible that the first extent is only in 1N/A * the attribute list while the last extent is in the base mft record, so don't 1N/A * rely on being able to find the first extent in the base mft record. 1N/A * Warning: Never use @val when looking for attribute types which can be 1N/A * non-resident as this most likely will result in a crash! 1N/A * Iterate over attributes in mft record starting at @ctx->attr, or the 1N/A * attribute following that, if @ctx->is_first is TRUE. 1N/A /* If this is an enumeration return this attribute. */ 1N/A * If @name is AT_UNNAMED we want an unnamed attribute. 1N/A * If @name is present, compare the two names. 1N/A * Otherwise, match any attribute. 1N/A /* The search failed if the found attribute is named. */ 1N/A * If @name collates before a->name, there is no 1N/A * matching attribute. 1N/A /* If the strings are not equal, continue search. */ 1N/A * The names match or @name not present and attribute is 1N/A * unnamed. If no @val specified, we have found the attribute 1N/A /* @val is present; compare values. */ 1N/A * If @val collates before the current attribute's 1N/A * value, there is no matching attribute. 1N/A * ntfs_attr_lookup - find an attribute in an ntfs inode 1N/A * @type: attribute type to find 1N/A * @name: attribute name to find (optional, i.e. NULL means don't care) 1N/A * @name_len: attribute name length (only needed if @name present) 1N/A * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 1N/A * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) 1N/A * @val: attribute value to find (optional, resident attributes only) 1N/A * @val_len: attribute value length 1N/A * @ctx: search context with mft record and attribute to search from 1N/A * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must 1N/A * be the base mft record and @ctx must have been obtained from a call to 1N/A * ntfs_attr_get_search_ctx(). 1N/A * This function transparently handles attribute lists and @ctx is used to 1N/A * continue searches where they were left off at. 1N/A * If @type is AT_UNUSED, return the first found attribute, i.e. one can 1N/A * enumerate all attributes by setting @type to AT_UNUSED and then calling 1N/A * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT 1N/A * to indicate that there are no more entries. During the enumeration, each 1N/A * successful call of ntfs_attr_lookup() will return the next attribute, with 1N/A * the current attribute being described by the search context @ctx. 1N/A * If @type is AT_END, seek to the end of the base mft record ignoring the 1N/A * attribute list completely and return -1 with errno set to ENOENT. AT_END is 1N/A * not a valid attribute, its length is zero for example, thus it is safer to 1N/A * return error instead of success in this case. It should never be needed to 1N/A * do this, but we implement the functionality because it allows for simpler 1N/A * code inside ntfs_external_attr_find(). 1N/A * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present 1N/A * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, 1N/A * match both named and unnamed attributes. 1N/A * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any 1N/A * mapped extent inodes, etc). 1N/A * Return 0 if the search was successful and -1 if not, with errno set to the 1N/A * On success, @ctx->attr is the found attribute, it is in mft record 1N/A * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this 1N/A * attribute with @ctx->base_* being the base mft record to which @ctx->attr 1N/A * belongs. If no attribute list attribute is present @ctx->al_entry and 1N/A * @ctx->base_* are NULL. 1N/A * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the 1N/A * attribute which collates just after the attribute being searched for in the 1N/A * base ntfs inode, i.e. if one wants to add the attribute to the mft record 1N/A * this is the correct place to insert it into, and if there is not enough 1N/A * space, the attribute should be placed in an extent mft record. 1N/A * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list 1N/A * at which the new attribute's attribute list entry should be inserted. The 1N/A * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. 1N/A * The only exception to this is when @type is AT_END, in which case 1N/A * @ctx->al_entry is set to NULL also (see above). 1N/A * The following error codes are defined: 1N/A * ENOENT Attribute not found, not an error as such. 1N/A * EINVAL Invalid arguments. 1N/A * EIO I/O error or corrupt data structures found. 1N/A * ENOMEM Not enough memory to allocate necessary buffers. 1N/A * insert_positioned_attr_in_mft_record 1N/A * Create a non-resident attribute with a predefined on disk location 1N/A * specified by the runlist @rl. The clusters specified by @rl are assumed to 1N/A * be allocated already. 1N/A * Return 0 on success and -errno on error. 1N/A /* Check if the attribute is already there. */ 1N/A /* FIXME: Compress attribute into a temporary buffer, set */ 1N/A /* val accordingly and save the compressed size. */ 1N/A /* FIXME: This compression stuff is all wrong. Never mind for */ 1N/A mpa_size = 0;
/* get_size_for_compressed_mapping_pairs(rl); */ 1N/A /* Mapping pairs array and next attribute must be 8-byte aligned. */ 1N/A /* Get the highest vcn. */ 1N/A /* Does the value fit inside the allocated size? */ 1N/A * FIXME: Make space! (AIA) 1N/A * can we make it non-resident? if yes, do that. 1N/A * does it fit now? yes -> do it. 1N/A * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? 1N/A * yes -> make non-resident 1N/A * does it fit now? yes -> do it. 1N/A * make all attributes non-resident 1N/A * does it fit now? yes -> do it. 1N/A * m is a base record? yes -> allocate extension record 1N/A * does the new attribute fit in there? yes -> do it. 1N/A * split up runlist into extents and place each in an extension 1N/A * FIXME: the check for needing extension records should be 1N/A * earlier on as it is very quick: asize > m->bytes_allocated? 1N/A "record(): make_room_for_attribute() returned " 1N/A "error: EINVAL!\n");
1N/A /* FIXME: Allocated size depends on compression. */ 1N/A "to standard compression.\n");
1N/A /* FIXME: Set the compressed size. */ 1N/A /* FIXME: Write out the compressed data. */ 1N/A /* FIXME: err = build_mapping_pairs_compressed(); */ 1N/A /* FIXME: Handle error. */ 1N/A /* deallocate clusters */ 1N/A /* remove attribute */ 1N/A * insert_non_resident_attr_in_mft_record 1N/A * Return 0 on success and -errno on error. 1N/A /* Check if the attribute is already there. */ 1N/A /* FIXME: Compress attribute into a temporary buffer, set */ 1N/A /* val accordingly and save the compressed size. */ 1N/A /* FIXME: This compression stuff is all wrong. Never mind for */ 1N/A mpa_size = 0;
/* get_size_for_compressed_mapping_pairs(rl); */ 1N/A /* Mapping pairs array and next attribute must be 8-byte aligned. */ 1N/A * FIXME: Make space! (AIA) 1N/A * can we make it non-resident? if yes, do that. 1N/A * does it fit now? yes -> do it. 1N/A * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? 1N/A * yes -> make non-resident 1N/A * does it fit now? yes -> do it. 1N/A * make all attributes non-resident 1N/A * does it fit now? yes -> do it. 1N/A * m is a base record? yes -> allocate extension record 1N/A * does the new attribute fit in there? yes -> do it. 1N/A * split up runlist into extents and place each in an extension 1N/A * FIXME: the check for needing extension records should be 1N/A * earlier on as it is very quick: asize > m->bytes_allocated? 1N/A "mft_record(): make_room_for_attribute() " 1N/A "returned error: EINVAL!\n");
1N/A /* FIXME: Allocated size depends on compression. */ 1N/A "to standard compression.\n");
1N/A /* FIXME: Set the compressed size. */ 1N/A /* FIXME: Write out the compressed data. */ 1N/A /* FIXME: err = build_mapping_pairs_compressed(); */ 1N/A /* FIXME: Handle error. */ 1N/A /* deallocate clusters */ 1N/A /* remove attribute */ 1N/A * insert_resident_attr_in_mft_record 1N/A * Return 0 on success and -errno on error. 1N/A mkntfs_attr_lookup(); 1N/A /* Check if the attribute is already there. */ 1N/A /* sizeof(resident attribute record header) == 24 */ 1N/A * FIXME: Make space! (AIA) 1N/A * can we make it non-resident? if yes, do that. 1N/A * does it fit now? yes -> do it. 1N/A * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? 1N/A * yes -> make non-resident 1N/A * does it fit now? yes -> do it. 1N/A * make all attributes non-resident 1N/A * does it fit now? yes -> do it. 1N/A * m is a base record? yes -> allocate extension record 1N/A * does the new attribute fit in there? yes -> do it. 1N/A * split up runlist into extents and place each in an extension 1N/A * FIXME: the check for needing extension records should be 1N/A * earlier on as it is very quick: asize > m->bytes_allocated? 1N/A "record(): make_room_for_attribute() returned " 1N/A "error: EINVAL!\n");
1N/A * Return 0 on success or -errno on error. 1N/A /* FIXME: $Quota support... */ 1N/A /* FIXME: $UsnJrnl support... Not needed on fresh w2k3-volume */ 1N/A /* NTFS 1.2: size of si = 48, NTFS 3.[01]: size of si = 72 */ 1N/A * add_attr_file_name 1N/A * Return 0 on success or -errno on error. 1N/A /* Check if the attribute is already there. */ 1N/A "present in file record.\n");
1N/A /* These are in a union so can't have both. */ 1N/A /* No terminating null in file names. */ 1N/A * add_attr_object_id - 1N/A * Note we insert only a basic object id which only has the GUID and none of 1N/A * the extended fields. This is because we currently only use this function 1N/A * when creating the object id for the volume. 1N/A * Return 0 on success or -errno on error. 1N/A * Create the security descriptor attribute adding the security descriptor @sd 1N/A * of length @sd_len to the mft record @m. 1N/A * Return 0 on success or -errno on error. 1N/A /* Does it fit? NO: create non-resident. YES: create resident. */ 1N/A * Return 0 on success or -errno on error. 1N/A * Does it fit? NO: create non-resident. YES: create resident. 1N/A * FIXME: Introduced arbitrary limit of mft record allocated size - 512. 1N/A * This is to get around the problem that if $Bitmap/$DATA becomes too 1N/A * big, but is just small enough to be resident, we would make it 1N/A * resident, and later run out of space when creating the other 1N/A * attributes and this would cause us to abort as making resident 1N/A * attributes non-resident is not supported yet. 1N/A * The proper fix is to support making resident attribute non-resident. 1N/A * add_attr_data_positioned 1N/A * Create a non-resident data attribute with a predefined on disk location 1N/A * specified by the runlist @rl. The clusters specified by @rl are assumed to 1N/A * be allocated already. 1N/A * Return 0 on success or -errno on error. 1N/A * Create volume name attribute specifying the volume name @vol_name as a null 1N/A * terminated char string of length @vol_name_len (number of characters not 1N/A * including the terminating null), which is converted internally to a little 1N/A * endian ntfschar string. The name is at least 1 character long and at most 1N/A * 0xff characters long (not counting the terminating null). 1N/A * Return 0 on success or -errno on error. 1N/A * Return 0 on success or -errno on error. 1N/A * add_attr_index_root 1N/A * Return 0 on success or -errno on error. 1N/A "but collation rule is not COLLATION_FILE_NAME.\n");
1N/A "a multiple of the cluster size.\n");
1N/A }
else {
/* if (g_vol->cluster_size > index_block_size) */ 1N/A "is smaller than the sector size.\n");
1N/A * No matter whether this is a file index or a view as this is a 1N/A * termination entry, hence no key value / data is associated with it 1N/A * at all. Thus, we just need the union to be all zero. 1N/A * add_attr_index_alloc 1N/A * Return 0 on success or -errno on error. 1N/A * Return 0 on success or -errno on error. 1N/A /* Does it fit? NO: create non-resident. YES: create resident. */ 1N/A * add_attr_bitmap_positioned 1N/A * Create a non-resident bitmap attribute with a predefined on disk location 1N/A * specified by the runlist @rl. The clusters specified by @rl are assumed to 1N/A * be allocated already. 1N/A * Return 0 on success or -errno on error. 1N/A * upgrade_to_large_index 1N/A * Create bitmap and index allocation attributes, modify index root 1N/A * attribute accordingly and move all of the index entries from the index root 1N/A * into the index allocation. 1N/A * Return 0 on success or -errno on error. 1N/A /* Find the index root attribute. */ 1N/A /* Bitmap has to be at least 8 bytes in size. */ 1N/A "Setting usa_count to 1. If Windows chkdsk " 1N/A "reports this as corruption, please email %s " 1N/A "stating that you saw this message and that " 1N/A "the filesystem created was corrupt. " 1N/A /* Align to 8-byte boundary. */ 1N/A /* Find the last entry in the index root and save it in re. */ 1N/A /* Next entry in index root. */ 1N/A /* Copy all the entries including the termination entry. */ 1N/A /* Finish setting up index allocation. */ 1N/A /* Move the termination entry forward to the beginning if necessary. */ 1N/A /* Now fixup empty index root with pointer to index allocation VCN 0. */ 1N/A /* Resize index root attribute. */ 1N/A /* TODO: Remove the added bitmap! */ 1N/A /* Revert index root from index allocation. */ 1N/A /* Set VCN pointer to 0LL. */ 1N/A "upgrade_to_large_index.\n");
1N/A /* TODO: Remove the added bitmap! */ 1N/A /* Revert index root from index allocation. */ 1N/A * make_room_for_index_entry_in_index_block 1N/A * Create space of @size bytes at position @pos inside the index block @idx. 1N/A * Return 0 on success or -errno on error. 1N/A * Rigorous consistency checks. Always return -EINVAL even if more 1N/A * appropriate codes exist for simplicity of parsing the return value. 1N/A "non 8-byte aligned size.\n");
1N/A /* The - sizeof(INDEX_ENTRY_HEADER) is for the index terminator. */ 1N/A /* Do we have enough space? */ 1N/A /* Move everything after pos to pos + size. */ 1N/A /* Update index block. */ 1N/A * ntfs_index_keys_compare 1N/A * not all types of COLLATION_RULES supported yet... 1N/A * added as needed.. (remove this comment when all are added) 1N/A /* i.e. $SII or $QUOTA-$Q */ 1N/A "collation rule.\n");
1N/A return 0;
/* Claim they're equal. What else can we do? */ 1N/A * insert_index_entry_in_res_dir_index 1N/A * i.e. insert an index_entry in some named index_root 1N/A * simplified search method, works for mkntfs 1N/A /* find the INDEX_ROOT attribute:*/ 1N/A /* found attribute */ 1N/A * Loop until we exceed valid memory (corruption case) or until we 1N/A * reach the last entry. 1N/A * If @file_name collates before ie->key.file_name, 1N/A * there is no matching index entry. 1N/A /* If file names are not equal, continue search. */ 1N/A /* Adjust various offsets, etc... */ 1N/A * initializes $Secure's $SDH and $SII indexes from $SDS datastream 1N/A /* SDH index entry */ 1N/A /* SII index entry */ 1N/A * initialize $Quota with the default quota index-entries. 1N/A /* q index entry num 1 */ 1N/A /* q index entry num 2 */ 1N/A for (i = 0; i <
5; i++)
1N/A for (i = 0; i <
5; i++)
1N/A /* 20 00 00 00 padding after here on ntfs 3.1. 3.0 is unchecked. */ 1N/A * insert_file_link_in_dir_index 1N/A * Insert the fully completed FILE_NAME_ATTR @file_name which is inside 1N/A * the file with mft reference @file_ref into the index (allocation) block 1N/A * @idx (which belongs to @file_ref's parent directory). 1N/A * Return 0 on success or -errno on error. 1N/A * Lookup dir entry @file_name in dir @idx to determine correct 1N/A * insertion location. FIXME: Using a very oversimplified lookup 1N/A * method which is sufficient for mkntfs but no good whatsoever in 1N/A * real world scenario. (AIA) 1N/A * Loop until we exceed valid memory (corruption case) or until we 1N/A * reach the last entry. 1N/A "Unicode characters.\n");
1N/A "Unicode characters.\n");
1N/A * If @file_name collates before ie->key.file_name, there is no 1N/A * matching index entry. 1N/A /* If file names are not equal, continue search. */ 1N/A /* File names are equal when compared ignoring case. */ 1N/A * If BOTH file names are in the POSIX namespace, do a case 1N/A * sensitive comparison as well. Otherwise the names match so 1N/A * we return -EEXIST. FIXME: There are problems with this in a 1N/A * real world scenario, when one is POSIX and one isn't, but 1N/A * fine for mkntfs where we don't use POSIX namespace at all 1N/A * and hence this following code is luxury. (AIA) 1N/A /* Complete match. Bugger. Can't insert. */ 1N/A /* Create entry in place and copy file name attribute value. */ 1N/A * create_hardlink_res 1N/A * Create a file_name_attribute in the mft record @m_file which points to the 1N/A * parent directory with mft reference @ref_parent. 1N/A * Then, insert an index entry with this file_name_attribute in the index 1N/A * root @idx of the index_root attribute of the parent directory. 1N/A * @ref_file is the mft reference of @m_file. 1N/A * Return 0 on success or -errno on error. 1N/A /* Create the file_name attribute. */ 1N/A /* FIXME: copy the creation_time from the std info */ 1N/A /* These are in a union so can't have both. */ 1N/A /* No terminating null in file names. */ 1N/A /* Increment the link count of @m_file. */ 1N/A /* Add the file_name to @m_file. */ 1N/A /* Undo link count increment. */ 1N/A /* Insert the index entry for file_name in @idx. */ 1N/A /* FIXME: Remove the file name attribute from @m_file. */ 1N/A /* Undo link count increment. */ 1N/A * Create a file_name_attribute in the mft record @m_file which points to the 1N/A * parent directory with mft reference @ref_parent. 1N/A * Then, insert an index entry with this file_name_attribute in the index 1N/A * block @idx of the index allocation attribute of the parent directory. 1N/A * @ref_file is the mft reference of @m_file. 1N/A * Return 0 on success or -errno on error. 1N/A /* Create the file_name attribute. */ 1N/A /* FIXME: Is this correct? Or do we have to copy the creation_time */ 1N/A /* from the std info? */ 1N/A /* These are in a union so can't have both. */ 1N/A /* No terminating null in file names. */ 1N/A /* Increment the link count of @m_file. */ 1N/A /* Add the file_name to @m_file. */ 1N/A /* Undo link count increment. */ 1N/A /* Insert the index entry for file_name in @idx. */ 1N/A /* FIXME: Remove the file name attribute from @m_file. */ 1N/A /* Undo link count increment. */ 1N/A * index_obj_id_insert 1N/A * Insert an index entry with the key @guid and data pointing to the mft record 1N/A * @ref in the $O index root of the mft record @m (which must be the mft record 1N/A * Return 0 on success or -errno on error. 1N/A * Insert the index entry for the object id in the index. 1N/A * First determine the size of the index entry to be inserted. This 1N/A * consists of the index entry header, followed by the index key, i.e. 1N/A * the GUID, followed by the index data, i.e. OBJ_ID_INDEX_DATA. 1N/A /* Close the volume */ 1N/A /* Free any memory we've used */ 1N/A * mkntfs_open_partition - 1N/A * Allocate and initialize an ntfs device structure and attach it to 1N/A /* Open the device for reading or reading and writing. */ 1N/A /* Verify we are dealing with a block device. */ 1N/A /* Make sure the file system is not mounted. */ 1N/A * mkntfs_get_page_size - detect the system's memory page size. 1N/A "Assuming safe default of 4096 bytes.\n");
1N/A * mkntfs_override_vol_params - 1N/A /* If user didn't specify the sector size, determine it now. */ 1N/A "for %s and it could not be obtained " 1N/A "automatically. It has been set to 512 " 1N/A /* Validate sector size. */ 1N/A "power of two, e.g. 512, 1024.\n");
1N/A "is 256 bytes and the maximum is 4096 bytes.\n");
1N/A /* Now set the device block size to the sector size. */ 1N/A "sector size. This may cause problems when " 1N/A "creating the backup boot sector and also may " 1N/A "affect performance but should be harmless " 1N/A /* If user didn't specify the number of sectors, determine it now. */ 1N/A "Please specify the number of sectors " 1N/A * Reserve the last sector for the backup boot sector unless the 1N/A * sector size is less than 512 bytes in which case reserve 512 bytes 1N/A /* If user didn't specify the partition start sector, determine it. */ 1N/A "specified for %s and it could not be obtained " 1N/A "automatically. It has been set to 0.\n",
1N/A "for %s and the automatically determined value " 1N/A "is too large. It has been set to 0.\n",
1N/A "4294967295 (2^32-1).\n");
1N/A /* If user didn't specify the sectors per track, determine it now. */ 1N/A "not specified for %s and it could not be " 1N/A "obtained automatically. It has been set to " 1N/A "not specified for %s and the automatically " 1N/A "determined value is too large. It has been " 1N/A /* If user didn't specify the number of heads, determine it now. */ 1N/A "specified for %s and it could not be obtained " 1N/A "automatically. It has been set to 0.\n",
1N/A "specified for %s and the automatically " 1N/A "determined value is too large. It has been " 1N/A /* Validate volume size. */ 1N/A /* If user didn't specify the cluster size, determine it now. */ 1N/A * Windows Vista always uses 4096 bytes as the default cluster 1N/A * size regardless of the volume size so we do it, too. 1N/A /* For small volumes on devices with large sector sizes. */ 1N/A * For huge volumes, grow the cluster size until the number of 1N/A * clusters fits into 32 bits or the cluster size exceeds the 1N/A * maximum limit of 64kiB. 1N/A "NTFS volume (maximum size is " 1N/A /* Validate cluster size. */ 1N/A "power of two, e.g. 1024, 4096.\n");
1N/A "to, or larger than, the sector size.\n");
1N/A "more that 128 times the size of the sector " 1N/A "cluster size is 65536 bytes (64kiB).\n");
1N/A "when the cluster size is " 1N/A "larger than 4096 bytes.\n");
1N/A "cluster size is larger than 4096 bytes. " 1N/A "Compression has been disabled for this " 1N/A * Check the cluster_size and num_sectors for consistency with 1N/A * sector_size and num_sectors. And check both of these for consistency 1N/A /* XXX is this code reachable? */ 1N/A /* Number of clusters must fit within 32 bits (Win2k limitation). */ 1N/A "volume (maximum size is 256TiB).\n");
1N/A "try again with a larger\ncluster size or " 1N/A "leave the cluster size unspecified and the " 1N/A "smallest possible cluster size for the size " 1N/A "of the device will be used.\n");
1N/A * Set the mft record size. By default this is 1024 but it has to be 1N/A * at least as big as a sector and not bigger than a page on the system 1N/A * or the NTFS kernel driver will not be able to mount the volume. 1N/A * TODO: The mft record size should be user specifiable just like the 1N/A * "inode size" can be specified on other Linux/Unix file systems. 1N/A "page size (%li bytes). You will not be able " 1N/A "to mount this volume using the NTFS kernel " 1N/A * Set the index record size. By default this is 4096 but it has to be 1N/A * at least as big as a sector and not bigger than a page on the system 1N/A * or the NTFS kernel driver will not be able to mount the volume. 1N/A * FIXME: Should we make the index record size to be user specifiable? 1N/A "page size (%li bytes). You will not be able " 1N/A "to mount this volume using the NTFS kernel " 1N/A "'partition start sector', the 'sectors per " 1N/A "track' and the 'number of heads' to be " 1N/A * mkntfs_initialize_bitmaps - 1N/A /* Determine lcn bitmap byte size and allocate it. */ 1N/A /* Needs to be multiple of 8 bytes. */ 1N/A * $Bitmap can overlap the end of the volume. Any bits in this region 1N/A * must be set. This region also encompasses the backup boot sector. 1N/A * Mft size is 27 (NTFS 3.0+) mft records or one cluster, whichever is 1N/A /* Determine mft bitmap size and allocate it. */ 1N/A /* Convert to bytes, at least one. */ 1N/A /* Mft bitmap is allocated in multiples of 8 bytes. */ 1N/A /* Create runlist for mft bitmap. */ 1N/A /* Mft bitmap is right after $Boot's data. */ 1N/A * Size is always one cluster, even though valid data size and 1N/A * initialized data size are only 8 bytes. 1N/A /* Allocate cluster for mft bitmap. */ 1N/A * mkntfs_initialize_rl_mft - 1N/A /* If user didn't specify the mft lcn, determine it now. */ 1N/A * We start at the higher value out of 16kiB and just after the 1N/A /* Determine MFT zone size. */ 1N/A * The mft zone begins with the mft data attribute, not at the beginning 1N/A /* Create runlist for mft. */ 1N/A /* rounded up division by cluster size */ 1N/A /* Allocate clusters for mft. */ 1N/A for (i = 0; i < j; i++)
1N/A /* Determine mftmirr_lcn (middle of volume). */ 1N/A /* Create runlist for mft mirror. */ 1N/A * The mft mirror is either 4kb (the first four records) or one cluster 1N/A * in size, which ever is bigger. In either case, it contains a 1N/A * byte-for-byte identical copy of the beginning of the mft (i.e. either 1N/A * the first four records (4kb) or the first cluster worth of records, 1N/A * whichever is bigger). 1N/A /* Allocate clusters for mft mirror. */ 1N/A for (i = 0; i < j; i++)
1N/A * mkntfs_initialize_rl_logfile - 1N/A /* Create runlist for log file. */ 1N/A * Determine logfile_size from volume_size (rounded up to a cluster), 1N/A * making sure it does not overflow the end of the volume. 1N/A * FIXME: The $LogFile size is 64 MiB upwards from 12GiB but 1N/A * the "200" divider below apparently approximates "100" or 1N/A * some other value as the volume size decreases. For example: 1N/A * Volume size LogFile size Ratio 1N/A * 8799808 46048 191.100 1N/A * 8603248 45072 190.877 1N/A * 7341704 38768 189.375 1N/A * 6144828 32784 187.433 1N/A * 4192932 23024 182.111 1N/A * $Logfile would overflow volume. Need to make it smaller than 1N/A * the standard size. It's ok as we are creating a non-standard 1N/A * volume anyway if it is that small. 1N/A * FIXME: The 256kiB limit is arbitrary. Should find out what the real 1N/A * minimum requirement for Windows is so it doesn't blue screen. 1N/A "This is not allowed as it would cause Windows " 1N/A "to blue screen and during boot.\n");
1N/A /* Allocate clusters for log file. */ 1N/A for (i = 0; i < j; i++)
1N/A * mkntfs_initialize_rl_boot - 1N/A /* Create runlist for $Boot. */ 1N/A * $Boot is always 8192 (0x2000) bytes or 1 cluster, whichever is 1N/A /* Allocate clusters for $Boot. */ 1N/A for (i = 0; i < j; i++)
1N/A * mkntfs_initialize_rl_bad - 1N/A /* Create runlist for $BadClus, $DATA named stream $Bad. */ 1N/A * $BadClus named stream $Bad contains the whole volume as a single 1N/A * sparse runlist entry. 1N/A /* TODO: Mark bad blocks as such. */ 1N/A * mkntfs_fill_device_with_zeroes - 1N/A * If not quick format, fill the device with 0s. 1N/A * FIXME: Except bad blocks! (AIA) 1N/A "Cannot create NTFS file " 1N/A /* Add the baddie to our bad blocks list. */ 1N/A "list of bad blocks.\nInitializing " 1N/A /* Seek to next cluster. */ 1N/A "location reserved for system " 1N/A /* Seek to next sector. */ 1N/A * mkntfs_sync_index_record 1N/A * (ERSO) made a function out of this, but the reason for doing that 1N/A * disappeared during coding.... 1N/A /* FIXME: This should be IGNORE_CASE! */ 1N/A "syncing index block.\n");
1N/A /* No more changes to @idx below here so no need for fixup: */ 1N/A /* ntfs_mst_post_write_fixup((NTFS_RECORD*)idx); */ 1N/A * create_file_volume - 1N/A "disk runs on next reboot into " 1N/A * create_backup_boot_sector 1N/A * Return 0 on success or -1 if it couldn't be created. 1N/A * Write the first max(512, opts.sector_size) bytes from buf to the 1N/A * last sector, but limit that to 8192 bytes of written data since that 1N/A * is how big $Boot is (and how big our buffer is).. 1N/A s =
"unknown error";
1N/A /* At least some 2.4 kernels return EIO instead of ENOSPC. */ 1N/A "limitation in the\nLinux kernel. This is not a major " 1N/A "problem as Windows check disk will create the\n" 1N/A "backup boot sector when it is run on your next boot " 1N/A * mkntfs_create_root_structures - 1N/A * Setup an empty mft record. Note, we can just give 0 as the mft 1N/A * reference as we are creating an NTFS 1.2 volume for which the mft 1N/A * reference is ignored by ntfs_mft_record_layout(). 1N/A * Copy the mft record onto all 16 records in the buffer and setup the 1N/A * sequence numbers of each system file to equal the mft record number 1N/A * of that file (only for $MFT is the sequence number 1 rather than 0). 1N/A if (i == 0 || i >
23)
1N/A * If only one cluster contains all system files then 1N/A * fill the rest of it with empty, formatted records. 1N/A * Create the 16 system files, adding the system information attribute 1N/A * to each as well as marking them in use in the mft bitmap. 1N/A if (i <
16 || i >
23) {
1N/A /* setting specific security_id flag and */ 1N/A /* file permissions for ntfs 3.x */ 1N/A if (i == 0 || i ==
1 || i ==
2 || i ==
6 || i ==
8 ||
1N/A }
else if (i ==
9) {
1N/A }
else if (i ==
11) {
1N/A }
else if (i ==
24 || i ==
25 || i ==
26) {
1N/A /* The root directory mft reference. */ 1N/A /* FIXME: This should be IGNORE_CASE */ 1N/A /* FIXME: This should be IGNORE_CASE */ 1N/A /* There is exactly one file name so this is ok. */ 1N/A /* Add all other attributes, on a per-file basis for clarity. */ 1N/A /* mft_bitmap is not modified in mkntfs; no need to sync it later. */ 1N/A /* the data attribute of $Bitmap must be non-resident or otherwise */ 1N/A /* windows 2003 will regard the volume as corrupt (ERSO) */ 1N/A * Create the boot sector in bs. Note, that bs is already zeroed 1N/A * in the boot sector section and that it has the NTFS OEM id/magic 1N/A * already inserted, so no need to worry about these things. 1N/A " is wrong (= 0x%x)\n",
1N/A "clusters_per_index_record is wrong " 1N/A /* Generate a 64-bit random number for the serial number. */ 1N/A * Leave zero for now as NT4 leaves it zero, too. If want it later, see 1N/A /* Make sure the bootsector is ok. */ 1N/A * Pre-2.6 kernels couldn't access the last sector if it was 1N/A * odd and we failed to set the device block size to the sector 1N/A * size, hence we schedule chkdsk to create it. 1N/A * We cheat a little here and if the user has requested all times to be 1N/A * set to zero then we set the GUID to zero as well. This options is 1N/A * only used for development purposes so that should be fine. 1N/A /* Generate a GUID for the volume. */ 1N/A /* FIXME: This should be IGNORE_CASE */ 1N/A /* Create a sparse named stream of size equal to the volume size. */ 1N/A /* create $Secure (NTFS 3.0+) */ 1N/A /* FIXME: This should be IGNORE_CASE */ 1N/A /* FIXME: This should be IGNORE_CASE */ 1N/A * $Extend index must be resident. Otherwise, w2k3 will regard the 1N/A * volume as corrupt. (ERSO) 1N/A /* FIXME: This should be IGNORE_CASE */ 1N/A /* NTFS reserved system files (mft records 0xc-0xf) */ 1N/A for (i =
0xc; i <
0x10; i++) {
1N/A /* create systemfiles for ntfs volumes (3.1) */ 1N/A /* starting with file 24 (ignoring file 16-23) */ 1N/A /* FIXME: This should be IGNORE_CASE */ 1N/A /* FIXME: This should be IGNORE_CASE */ 1N/A /* FIXME: This should be IGNORE_CASE */ 1N/A /* FIXME: This should be IGNORE_CASE */ 1N/A /* Initialize the random number generator with the current time. */ 1N/A /* Allocate and initialize ntfs_volume structure g_vol. */ 1N/A /* Transfer some options to the volume. */ 1N/A /* Length is in unicode characters. */ 1N/A /* Open the partition. */ 1N/A * Decide on the sector size, cluster size, mft record and index record 1N/A /* Initialize $Bitmap and $MFT/$BITMAP related stuff. */ 1N/A /* Initialize MFT & set g_logfile_lcn. */ 1N/A /* Initialize $LogFile. */ 1N/A /* Initialize $Boot. */ 1N/A /* Allocate a buffer large enough to hold the mft. */ 1N/A /* Create runlist for $BadClus, $DATA named stream $Bad. */ 1N/A /* If not quick format, fill the device with 0s. */ 1N/A /* Create NTFS volume structures. */ 1N/A * - Do not step onto bad blocks!!! 1N/A * - If any bad blocks were specified or found, modify $BadClus, 1N/A * allocating the bad clusters in $Bitmap. 1N/A * - C&w bootsector backup bootsector (backup in last sector of the 1N/A * - If NTFS 3.0+, c&w $Secure file and $Extend directory with the 1N/A * corresponding special files in it, i.e. $ObjId, $Quota, $Reparse, 1N/A * and $UsnJrnl. And others? Or not all necessary? 1N/A * - RE: Populate $root with the system files (and $Extend directory if 1N/A * applicable). Possibly should move this as far to the top as 1N/A * possible and update during each subsequent c&w of each system file. 1N/A * No need to sync $MFT/$BITMAP as that has never been modified since 1N/A * Decrement the usn by one, so it becomes the same as the one 1N/A * in $MFT once it is mst protected. - This is as we need the 1N/A * $MFTMirr to have the exact same byte by byte content as 1N/A * $MFT, rather than just equivalent meaning content. 1N/A * Return: 0 Success, the program worked 1N/A * 1 Error, something went wrong