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