Megapatch!!! Check evecrything!!! I probably broke everything!!!
							parent
							
								
									99e18269b7
								
							
						
					
					
						commit
						2a104d8eda
					
				|  | @ -51,6 +51,15 @@ xx/xx/2005 - 1.12.0-WIP | |||
| 	- New API for hard link creating: dir.[ch]::ntfs_link.  (Yura) | ||||
| 	- ntfsresize: emphasize that disk partitioning must use sector as the | ||||
| 	  unit instead of cylinder to avoid shifting of the partition.  (Szaka) | ||||
| 	- Rename API: ntfs_volume_set_flags() as it is misleading.  It does not | ||||
| 	  set a flag, it overwrites the flags!  Rename it to | ||||
| 	  ntfs_volume_write_flags() and clean it up a lot.  Update all | ||||
| 	  callers.  (Anton) | ||||
| 	- Change ntfsfix to no longer set the volume dirty. | ||||
| 	- Change everything to supply an ntfs_inode and NULL for mft record | ||||
| 	  when calling ntfs_attr_get_search_ctx() except a very few cases which | ||||
| 	  genuinely need this functionality as they work on a too low level. | ||||
| 	  Make sure all those cases are ok. | ||||
| 
 | ||||
| 08/08/2005 - 1.11.2 - ntfsdecrypt now works and lots of fixes and improvements. | ||||
| 
 | ||||
|  |  | |||
|  | @ -61,5 +61,7 @@ extern int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs, | |||
| 		int outs_len); | ||||
| extern int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len); | ||||
| 
 | ||||
| extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len); | ||||
| 
 | ||||
| #endif /* defined _NTFS_UNISTR_H */ | ||||
| 
 | ||||
|  |  | |||
|  | @ -117,6 +117,8 @@ struct _ntfs_volume { | |||
| 	char *vol_name;		/* Name of the volume. */ | ||||
| 	unsigned long state;	/* NTFS specific flags describing this volume.
 | ||||
| 				   See ntfs_volume_state_bits above. */ | ||||
| 
 | ||||
| 	ntfs_inode *vol_ni;	/* ntfs_inode structure for FILE_Volume. */ | ||||
| 	u8 major_ver;		/* Ntfs major version of volume. */ | ||||
| 	u8 minor_ver;		/* Ntfs minor version of volume. */ | ||||
| 	u16 flags;		/* Bit array of VOLUME_* flags. */ | ||||
|  | @ -198,7 +200,8 @@ extern int ntfs_umount(ntfs_volume *vol, const BOOL force); | |||
| 
 | ||||
| extern int ntfs_version_is_supported(ntfs_volume *vol); | ||||
| extern int ntfs_logfile_reset(ntfs_volume *vol); | ||||
| extern int ntfs_volume_set_flags(ntfs_volume *v, const u16 flags); | ||||
| 
 | ||||
| extern int ntfs_volume_write_flags(ntfs_volume *v, const u16 flags); | ||||
| 
 | ||||
| #endif /* defined _NTFS_VOLUME_H */ | ||||
| 
 | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ | |||
| #   - If the interface is the same as the previous version, change to C:R+1:A
 | ||||
| #
 | ||||
| 
 | ||||
| LTVERSION_LIBNTFS = 7:1:0 | ||||
| LTVERSION_LIBNTFS = 8:0:0 | ||||
| LTVERSION_LIBNTFS_GNOMEVFS = 1:0:0 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -1559,10 +1559,23 @@ static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, | |||
| 		const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx) | ||||
| { | ||||
| 	ATTR_RECORD *a; | ||||
| 	ntfs_volume *vol = ctx->ntfs_ino->vol; | ||||
| 	ntfschar *upcase = vol->upcase; | ||||
| 	u32 upcase_len = vol->upcase_len; | ||||
| 	ntfs_volume *vol; | ||||
| 	ntfschar *upcase; | ||||
| 	u32 upcase_len; | ||||
| 
 | ||||
| 	if (ctx->ntfs_ino) { | ||||
| 		vol = ctx->ntfs_ino->vol; | ||||
| 		upcase = vol->upcase; | ||||
| 		upcase_len = vol->upcase_len; | ||||
| 	} else { | ||||
| 		if (name) { | ||||
| 			errno = EINVAL; | ||||
| 			return -1; | ||||
| 		} | ||||
| 		vol = NULL; | ||||
| 		upcase = NULL; | ||||
| 		upcase_len = 0; | ||||
| 	} | ||||
| 	/*
 | ||||
| 	 * Iterate over attributes in mft record starting at @ctx->attr, or the | ||||
| 	 * attribute following that, if @ctx->is_first is TRUE. | ||||
|  | @ -2196,7 +2209,7 @@ int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, | |||
| static __inline__ void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx, | ||||
| 		ntfs_inode *ni, MFT_RECORD *mrec) | ||||
| { | ||||
| 	if (ni && !mrec) | ||||
| 	if (!mrec) | ||||
| 		mrec = ni->mrec; | ||||
| 	ctx->mrec = mrec; | ||||
| 	/* Sanity checks are performed elsewhere. */ | ||||
|  | @ -2245,19 +2258,22 @@ void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx) | |||
|  * Allocate a new attribute search context, initialize it with @ni and @mrec, | ||||
|  * and return it. Return NULL on error with errno set to ENOMEM. | ||||
|  * | ||||
|  * @ni can be NULL if the search context is only going to be used for searching | ||||
|  * for the attribute list attribute and for searches ignoring the contents of | ||||
|  * the attribute list attribute. | ||||
|  * @mrec can be NULL, in which case the mft record is taken from @ni. | ||||
|  * | ||||
|  * If @ni is specified, @mrec can be NULL, in which case the mft record is | ||||
|  * taken from @ni. | ||||
|  * | ||||
|  * If both @ni and @mrec are specified, the mft record is taken from @mrec and | ||||
|  * the value of @ni->mrec is ignored. | ||||
|  * Note: For low level utilities which know what they are doing we allow @ni to | ||||
|  * be NULL and @mrec to be set.  Do NOT do this unless you understand the | ||||
|  * implications!!!  For example it is no longer safe to call ntfs_attr_lookup() | ||||
|  * if you  | ||||
|  */ | ||||
| ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) | ||||
| { | ||||
| 	ntfs_attr_search_ctx *ctx = malloc(sizeof(ntfs_attr_search_ctx)); | ||||
| 	ntfs_attr_search_ctx *ctx; | ||||
| 
 | ||||
| 	if (!ni && !mrec) { | ||||
| 		errno = EINVAL; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	ctx = malloc(sizeof(ntfs_attr_search_ctx)); | ||||
| 	if (ctx) | ||||
| 		ntfs_attr_init_search_ctx(ctx, ni, mrec); | ||||
| 	return ctx; | ||||
|  | @ -2530,7 +2546,7 @@ int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, | |||
| 	} | ||||
| 
 | ||||
| 	/* Locate place where record should be. */ | ||||
| 	ctx = ntfs_attr_get_search_ctx(NULL, ni->mrec); | ||||
| 	ctx = ntfs_attr_get_search_ctx(ni, NULL); | ||||
| 	if (!ctx) | ||||
| 		return -1; | ||||
| 	if (!ntfs_attr_lookup(type, name, name_len, | ||||
|  | @ -2655,7 +2671,7 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, | |||
| 	} | ||||
| 
 | ||||
| 	/* Locate place where record should be. */ | ||||
| 	ctx = ntfs_attr_get_search_ctx(NULL, ni->mrec); | ||||
| 	ctx = ntfs_attr_get_search_ctx(ni, NULL); | ||||
| 	if (!ctx) | ||||
| 		return -1; | ||||
| 	if (!ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, | ||||
|  | @ -3318,7 +3334,7 @@ int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni) | |||
| 
 | ||||
| 	/* Find place in MFT record where attribute will be moved. */ | ||||
| 	a = ctx->attr; | ||||
| 	nctx = ntfs_attr_get_search_ctx(NULL, ni->mrec); | ||||
| 	nctx = ntfs_attr_get_search_ctx(ni, NULL); | ||||
| 	if (!nctx) { | ||||
| 		err = errno; | ||||
| 		Dprintf("%s(): Couldn't obtain search context.\n", | ||||
|  |  | |||
|  | @ -591,3 +591,69 @@ err_out: | |||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * ntfs_upcase_table_build - build the default upcase table for NTFS | ||||
|  * @uc:		destination buffer where to store the built table | ||||
|  * @uc_len:	size of destination buffer in bytes | ||||
|  * | ||||
|  * ntfs_upcase_table_build() builds the default upcase table for NTFS and | ||||
|  * stores it in the caller supplied buffer @uc of size @uc_len. | ||||
|  * | ||||
|  * Note, @uc_len must be at least 128kiB in size or bad things will happen! | ||||
|  */ | ||||
| void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len) | ||||
| { | ||||
| 	static int uc_run_table[][3] = { /* Start, End, Add */ | ||||
| 	{0x0061, 0x007B,  -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72,  74}, | ||||
| 	{0x00E0, 0x00F7,  -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76,  86}, | ||||
| 	{0x00F8, 0x00FF,  -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100}, | ||||
| 	{0x0256, 0x0258, -205}, {0x1F00, 0x1F08,   8}, {0x1F78, 0x1F7A, 128}, | ||||
| 	{0x028A, 0x028C, -217}, {0x1F10, 0x1F16,   8}, {0x1F7A, 0x1F7C, 112}, | ||||
| 	{0x03AC, 0x03AD,  -38}, {0x1F20, 0x1F28,   8}, {0x1F7C, 0x1F7E, 126}, | ||||
| 	{0x03AD, 0x03B0,  -37}, {0x1F30, 0x1F38,   8}, {0x1FB0, 0x1FB2,   8}, | ||||
| 	{0x03B1, 0x03C2,  -32}, {0x1F40, 0x1F46,   8}, {0x1FD0, 0x1FD2,   8}, | ||||
| 	{0x03C2, 0x03C3,  -31}, {0x1F51, 0x1F52,   8}, {0x1FE0, 0x1FE2,   8}, | ||||
| 	{0x03C3, 0x03CC,  -32}, {0x1F53, 0x1F54,   8}, {0x1FE5, 0x1FE6,   7}, | ||||
| 	{0x03CC, 0x03CD,  -64}, {0x1F55, 0x1F56,   8}, {0x2170, 0x2180, -16}, | ||||
| 	{0x03CD, 0x03CF,  -63}, {0x1F57, 0x1F58,   8}, {0x24D0, 0x24EA, -26}, | ||||
| 	{0x0430, 0x0450,  -32}, {0x1F60, 0x1F68,   8}, {0xFF41, 0xFF5B, -32}, | ||||
| 	{0} | ||||
| 	}; | ||||
| 	static int uc_dup_table[][2] = { /* Start, End */ | ||||
| 	{0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC}, | ||||
| 	{0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB}, | ||||
| 	{0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5}, | ||||
| 	{0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9}, | ||||
| 	{0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95}, | ||||
| 	{0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9}, | ||||
| 	{0} | ||||
| 	}; | ||||
| 	static int uc_byte_table[][2] = { /* Offset, Value */ | ||||
| 	{0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196}, | ||||
| 	{0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C}, | ||||
| 	{0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D}, | ||||
| 	{0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F}, | ||||
| 	{0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9}, | ||||
| 	{0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE}, | ||||
| 	{0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7}, | ||||
| 	{0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197}, | ||||
| 	{0} | ||||
| 	}; | ||||
| 	int i, r; | ||||
| 
 | ||||
| 	memset((char*)uc, 0, uc_len); | ||||
| 	uc_len >>= 1; | ||||
| 	if (uc_len > 65536) | ||||
| 		uc_len = 65536; | ||||
| 	for (i = 0; (u32)i < uc_len; i++) | ||||
| 		uc[i] = i; | ||||
| 	for (r = 0; uc_run_table[r][0]; r++) | ||||
| 		for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++) | ||||
| 			uc[i] += uc_run_table[r][2]; | ||||
| 	for (r = 0; uc_dup_table[r][0]; r++) | ||||
| 		for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2) | ||||
| 			uc[i + 1]--; | ||||
| 	for (r = 0; uc_byte_table[r][0]; r++) | ||||
| 		uc[uc_byte_table[r][0]] = uc_byte_table[r][1]; | ||||
| } | ||||
|  |  | |||
|  | @ -79,6 +79,8 @@ ntfs_volume *ntfs_volume_alloc(void) | |||
|  */ | ||||
| static void __ntfs_volume_release(ntfs_volume *v) | ||||
| { | ||||
| 	if (v->vol_ni && NInoDirty(v->vol_ni)) | ||||
| 		ntfs_inode_close(v->vol_ni); | ||||
| 	if (v->lcnbmp_ni && NInoDirty(v->lcnbmp_ni)) | ||||
| 		ntfs_inode_sync(v->lcnbmp_ni); | ||||
| 	if (v->lcnbmp_na) | ||||
|  | @ -166,7 +168,7 @@ static int ntfs_mft_load(ntfs_volume *vol) | |||
| 		Dputs("Error: $MFT has invalid magic."); | ||||
| 		goto io_error_exit; | ||||
| 	} | ||||
| 	ctx = ntfs_attr_get_search_ctx(vol->mft_ni, mb); | ||||
| 	ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL); | ||||
| 	if (!ctx) { | ||||
| 		Dperror("Failed to allocate attribute search context"); | ||||
| 		goto error_exit; | ||||
|  | @ -416,6 +418,15 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long rwflag) | |||
| 	vol = ntfs_volume_alloc(); | ||||
| 	if (!vol) | ||||
| 		goto error_exit; | ||||
| 	/* Create the default upcase table. */ | ||||
| 	vol->upcase_len = 65536; | ||||
| 	vol->upcase = (ntfschar*)malloc(vol->upcase_len * sizeof(ntfschar)); | ||||
| 	if (!vol->upcase) { | ||||
| 		Dperror("Error allocating memory for upcase table."); | ||||
| 		goto error_exit; | ||||
| 	} | ||||
| 	ntfs_upcase_table_build(vol->upcase, | ||||
| 			vol->upcase_len * sizeof(ntfschar)); | ||||
| 	if ((rwflag & MS_RDONLY) == MS_RDONLY) | ||||
| 		NVolSetReadOnly(vol); | ||||
| 	Dprintf("Reading bootsector... "); | ||||
|  | @ -889,13 +900,17 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long rwflag) | |||
| 		errno = EINVAL; | ||||
| 		goto error_exit; | ||||
| 	} | ||||
| 	if (vol->upcase_len != na->data_size >> 1) { | ||||
| 		vol->upcase_len = na->data_size >> 1; | ||||
| 		/* Throw away default table. */ | ||||
| 		free(vol->upcase); | ||||
| 		vol->upcase = (ntfschar*)malloc(na->data_size); | ||||
| 		if (!vol->upcase) { | ||||
| 			Dputs(FAILED); | ||||
| 			Dputs("Not enough memory to load $UpCase."); | ||||
| 			goto error_exit; | ||||
| 		} | ||||
| 	} | ||||
| 	/* Read in the $DATA attribute value into the buffer. */ | ||||
| 	l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase); | ||||
| 	if (l != na->data_size) { | ||||
|  | @ -916,14 +931,14 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long rwflag) | |||
| 	 * vol structure accordingly. | ||||
| 	 */ | ||||
| 	Dprintf("Loading $Volume... "); | ||||
| 	ni = ntfs_inode_open(vol, FILE_Volume); | ||||
| 	if (!ni) { | ||||
| 	vol->vol_ni = ntfs_inode_open(vol, FILE_Volume); | ||||
| 	if (!vol->vol_ni) { | ||||
| 		Dputs(FAILED); | ||||
| 		Dperror("Failed to open inode"); | ||||
| 		goto error_exit; | ||||
| 	} | ||||
| 	/* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */ | ||||
| 	ctx = ntfs_attr_get_search_ctx(ni, NULL); | ||||
| 	ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); | ||||
| 	if (!ctx) { | ||||
| 		Dputs(FAILED); | ||||
| 		Dperror("Failed to allocate attribute search context"); | ||||
|  | @ -1033,9 +1048,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long rwflag) | |||
| 	Dputs(OK); | ||||
| 	ntfs_attr_put_search_ctx(ctx); | ||||
| 	ctx = NULL; | ||||
| 	if (ntfs_inode_close(ni)) | ||||
| 		Dperror("Failed to close inode, leaking memory"); | ||||
| 
 | ||||
| 	/* Now load the attribute definitions from $AttrDef. */ | ||||
| 	Dprintf("Loading $AttrDef... "); | ||||
| 	ni = ntfs_inode_open(vol, FILE_AttrDef); | ||||
|  | @ -1080,7 +1092,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long rwflag) | |||
| 	ntfs_attr_close(na); | ||||
| 	if (ntfs_inode_close(ni)) | ||||
| 		Dperror("Failed to close inode, leaking memory"); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Check for dirty logfile and hibernated Windows. | ||||
| 	 * We care only about read-write mounts. | ||||
|  | @ -1429,7 +1440,7 @@ error_exit: | |||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * ntfs_volume_set_flags - set the flags of an ntfs volume | ||||
|  * ntfs_volume_write_flags - set the flags of an ntfs volume | ||||
|  * @vol:	ntfs volume where we set the volume flags | ||||
|  * @flags:	new flags | ||||
|  * | ||||
|  | @ -1438,37 +1449,22 @@ error_exit: | |||
|  * | ||||
|  * Return 0 if successful and -1 if not with errno set to the error code. | ||||
|  */ | ||||
| int ntfs_volume_set_flags(ntfs_volume *vol, const u16 flags) | ||||
| int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags) | ||||
| { | ||||
| 	MFT_RECORD *m = NULL; | ||||
| 	ATTR_RECORD *r; | ||||
| 	ATTR_RECORD *a; | ||||
| 	VOLUME_INFORMATION *c; | ||||
| 	ntfs_attr_search_ctx *ctx; | ||||
| 	int ret = -1;	/* failure */ | ||||
| 
 | ||||
| 	if (!vol) { | ||||
| 	if (!vol || !vol->vol_ni) { | ||||
| 		errno = EINVAL; | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ntfs_file_record_read(vol, FILE_Volume, &m, NULL)) { | ||||
| 		Dperror("Failed to read $Volume"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Sanity check */ | ||||
| 	if (!(m->flags & MFT_RECORD_IN_USE)) { | ||||
| 		Dprintf("Error: $Volume has been deleted. Cannot " | ||||
| 			"handle this yet. Run chkdsk to fix this.\n"); | ||||
| 		errno = EIO; | ||||
| 		goto err_exit; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Get a pointer to the volume information attribute. */ | ||||
| 	ctx = ntfs_attr_get_search_ctx(NULL, m); | ||||
| 	ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); | ||||
| 	if (!ctx) { | ||||
| 		Dperror("Failed to allocate attribute search context"); | ||||
| 		goto err_exit; | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, | ||||
| 			0, ctx)) { | ||||
|  | @ -1476,40 +1472,36 @@ int ntfs_volume_set_flags(ntfs_volume *vol, const u16 flags) | |||
| 				"$Volume!"); | ||||
| 		goto err_out; | ||||
| 	} | ||||
| 	r = ctx->attr; | ||||
| 	a = ctx->attr; | ||||
| 	/* Sanity check. */ | ||||
| 	if (r->non_resident) { | ||||
| 	if (a->non_resident) { | ||||
| 		Dputs("Error: Attribute $VOLUME_INFORMATION must be resident " | ||||
| 				"(and it isn't)!"); | ||||
| 		errno = EIO; | ||||
| 		goto err_out; | ||||
| 	} | ||||
| 	/* Get a pointer to the value of the attribute. */ | ||||
| 	c = (VOLUME_INFORMATION*)(le16_to_cpu(r->value_offset) + (char*)r); | ||||
| 	c = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a); | ||||
| 	/* Sanity checks. */ | ||||
| 	if ((char*)c + le32_to_cpu(r->value_length) > | ||||
| 			le16_to_cpu(m->bytes_in_use) + (char*)m || | ||||
| 			le16_to_cpu(r->value_offset) + | ||||
| 			le32_to_cpu(r->value_length) > le32_to_cpu(r->length)) { | ||||
| 	if ((char*)c + le32_to_cpu(a->value_length) > | ||||
| 			le16_to_cpu(ctx->mrec->bytes_in_use) + | ||||
| 			(char*)ctx->mrec || le16_to_cpu(a->value_offset) + | ||||
| 			le32_to_cpu(a->value_length) > le32_to_cpu(a->length)) { | ||||
| 		Dputs("Error: Attribute $VOLUME_INFORMATION in $Volume is " | ||||
| 				"corrupt!"); | ||||
| 		errno = EIO; | ||||
| 		goto err_out; | ||||
| 	} | ||||
| 	/* Set the volume flags. */ | ||||
| 	vol->flags = c->flags = cpu_to_le16(flags); | ||||
| 
 | ||||
| 	if (ntfs_mft_record_write(vol, FILE_Volume, m)) { | ||||
| 	vol->flags = c->flags = flags & VOLUME_FLAGS_MASK; | ||||
| 	/* Write them to disk. */ | ||||
| 	ntfs_inode_mark_dirty(vol->vol_ni); | ||||
| 	if (ntfs_inode_sync(vol->vol_ni)) { | ||||
| 		Dperror("Error writing $Volume"); | ||||
| 		goto err_out; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = 0; /* success */ | ||||
| err_out: | ||||
| 	ntfs_attr_put_search_ctx(ctx); | ||||
| err_exit: | ||||
| 	if (m) | ||||
| 		free(m); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -81,7 +81,7 @@ int cluster_find (ntfs_volume *vol, LCN c_begin, LCN c_end, cluster_cb *cb, void | |||
| 		Vprintf ("Inode: %llu\n", (unsigned long long) | ||||
| 				m_ctx->inode->mft_no); | ||||
| 
 | ||||
| 		a_ctx = ntfs_attr_get_search_ctx (NULL, m_ctx->inode->mrec); | ||||
| 		a_ctx = ntfs_attr_get_search_ctx (m_ctx->inode, NULL); | ||||
| 
 | ||||
| 		while ((rec = find_attribute (AT_UNUSED, a_ctx))) { | ||||
| 
 | ||||
|  |  | |||
|  | @ -1180,6 +1180,297 @@ err_end: | |||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Internal: | ||||
|  * | ||||
|  * ntfs_attr_find - find (next) attribute in mft record | ||||
|  * @type:	attribute type to find | ||||
|  * @name:	attribute name to find (optional, i.e. NULL means don't care) | ||||
|  * @name_len:	attribute name length (only needed if @name present) | ||||
|  * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) | ||||
|  * @val:	attribute value to find (optional, resident attributes only) | ||||
|  * @val_len:	attribute value length | ||||
|  * @ctx:	search context with mft record and attribute to search from | ||||
|  * | ||||
|  * You shouldn't need to call this function directly. Use lookup_attr() instead. | ||||
|  * | ||||
|  * ntfs_attr_find() takes a search context @ctx as parameter and searches the | ||||
|  * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an | ||||
|  * attribute of @type, optionally @name and @val. If found, ntfs_attr_find() | ||||
|  * returns 0 and @ctx->attr will point to the found attribute. | ||||
|  * | ||||
|  * If not found, ntfs_attr_find() returns -1, with errno set to ENOENT and | ||||
|  * @ctx->attr will point to the attribute before which the attribute being | ||||
|  * searched for would need to be inserted if such an action were to be desired. | ||||
|  * | ||||
|  * On actual error, ntfs_attr_find() returns -1 with errno set to the error | ||||
|  * code but not to ENOENT.  In this case @ctx->attr is undefined and in | ||||
|  * particular do not rely on it not changing. | ||||
|  * | ||||
|  * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it | ||||
|  * is FALSE, the search begins after @ctx->attr. | ||||
|  * | ||||
|  * If @type is AT_UNUSED, return the first found attribute, i.e. one can | ||||
|  * enumerate all attributes by setting @type to AT_UNUSED and then calling | ||||
|  * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to | ||||
|  * indicate that there are no more entries. During the enumeration, each | ||||
|  * successful call of ntfs_attr_find() will return the next attribute in the | ||||
|  * mft record @ctx->mrec. | ||||
|  * | ||||
|  * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT. | ||||
|  * AT_END is not a valid attribute, its length is zero for example, thus it is | ||||
|  * safer to return error instead of success in this case. This also allows us | ||||
|  * to interoperate cleanly with ntfs_external_attr_find(). | ||||
|  * | ||||
|  * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present | ||||
|  * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, | ||||
|  * match both named and unnamed attributes. | ||||
|  * | ||||
|  * If @ic is IGNORE_CASE, the @name comparison is not case sensitive and | ||||
|  * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record | ||||
|  * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at | ||||
|  * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case | ||||
|  * sensitive. When @name is present, @name_len is the @name length in Unicode | ||||
|  * characters. | ||||
|  * | ||||
|  * If @name is not present (NULL), we assume that the unnamed attribute is | ||||
|  * being searched for. | ||||
|  * | ||||
|  * Finally, the resident attribute value @val is looked for, if present. | ||||
|  * If @val is not present (NULL), @val_len is ignored. | ||||
|  * | ||||
|  * ntfs_attr_find() only searches the specified mft record and it ignores the | ||||
|  * presence of an attribute list attribute (unless it is the one being searched | ||||
|  * for, obviously). If you need to take attribute lists into consideration, use | ||||
|  * ntfs_attr_lookup() instead (see below). This also means that you cannot use | ||||
|  * ntfs_attr_find() to search for extent records of non-resident attributes, as | ||||
|  * extents with lowest_vcn != 0 are usually described by the attribute list | ||||
|  * attribute only. - Note that it is possible that the first extent is only in | ||||
|  * the attribute list while the last extent is in the base mft record, so don't | ||||
|  * rely on being able to find the first extent in the base mft record. | ||||
|  * | ||||
|  * Warning: Never use @val when looking for attribute types which can be | ||||
|  *	    non-resident as this most likely will result in a crash! | ||||
|  */ | ||||
| static int mkntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, | ||||
| 		const u32 name_len, const IGNORE_CASE_BOOL ic, | ||||
| 		const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx) | ||||
| { | ||||
| 	ATTR_RECORD *a; | ||||
| 	ntfschar *upcase = vol->upcase; | ||||
| 	u32 upcase_len = vol->upcase_len; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Iterate over attributes in mft record starting at @ctx->attr, or the | ||||
| 	 * attribute following that, if @ctx->is_first is TRUE. | ||||
| 	 */ | ||||
| 	if (ctx->is_first) { | ||||
| 		a = ctx->attr; | ||||
| 		ctx->is_first = FALSE; | ||||
| 	} else | ||||
| 		a = (ATTR_RECORD*)((char*)ctx->attr + | ||||
| 				le32_to_cpu(ctx->attr->length)); | ||||
| 	for (;;	a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) { | ||||
| 		if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec + | ||||
| 				le32_to_cpu(ctx->mrec->bytes_allocated)) | ||||
| 			break; | ||||
| 		ctx->attr = a; | ||||
| 		if (((type != AT_UNUSED) && (le32_to_cpu(a->type) > | ||||
| 				le32_to_cpu(type))) || | ||||
| 				(a->type == AT_END)) { | ||||
| 			errno = ENOENT; | ||||
| 			return -1; | ||||
| 		} | ||||
| 		if (!a->length) | ||||
| 			break; | ||||
| 		/* If this is an enumeration return this attribute. */ | ||||
| 		if (type == AT_UNUSED) | ||||
| 			return 0; | ||||
| 		if (a->type != type) | ||||
| 			continue; | ||||
| 		/*
 | ||||
| 		 * If @name is AT_UNNAMED we want an unnamed attribute. | ||||
| 		 * If @name is present, compare the two names. | ||||
| 		 * Otherwise, match any attribute. | ||||
| 		 */ | ||||
| 		if (name == AT_UNNAMED) { | ||||
| 			/* The search failed if the found attribute is named. */ | ||||
| 			if (a->name_length) { | ||||
| 				errno = ENOENT; | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} else if (name && !ntfs_names_are_equal(name, name_len, | ||||
| 			    (ntfschar*)((char*)a + le16_to_cpu(a->name_offset)), | ||||
| 			    a->name_length, ic, upcase, upcase_len)) { | ||||
| 			register int rc; | ||||
| 
 | ||||
| 			rc = ntfs_names_collate(name, name_len, | ||||
| 					(ntfschar*)((char*)a + | ||||
| 					le16_to_cpu(a->name_offset)), | ||||
| 					a->name_length, 1, IGNORE_CASE, | ||||
| 					upcase, upcase_len); | ||||
| 			/*
 | ||||
| 			 * If @name collates before a->name, there is no | ||||
| 			 * matching attribute. | ||||
| 			 */ | ||||
| 			if (rc == -1) { | ||||
| 				errno = ENOENT; | ||||
| 				return -1; | ||||
| 			} | ||||
| 			/* If the strings are not equal, continue search. */ | ||||
| 			if (rc) | ||||
| 				continue; | ||||
| 			rc = ntfs_names_collate(name, name_len, | ||||
| 					(ntfschar*)((char*)a + | ||||
| 					le16_to_cpu(a->name_offset)), | ||||
| 					a->name_length, 1, CASE_SENSITIVE, | ||||
| 					upcase, upcase_len); | ||||
| 			if (rc == -1) { | ||||
| 				errno = ENOENT; | ||||
| 				return -1; | ||||
| 			} | ||||
| 			if (rc) | ||||
| 				continue; | ||||
| 		} | ||||
| 		/*
 | ||||
| 		 * The names match or @name not present and attribute is | ||||
| 		 * unnamed. If no @val specified, we have found the attribute | ||||
| 		 * and are done. | ||||
| 		 */ | ||||
| 		if (!val) | ||||
| 			return 0; | ||||
| 		/* @val is present; compare values. */ | ||||
| 		else { | ||||
| 			register int rc; | ||||
| 
 | ||||
| 			rc = memcmp(val, (char*)a +le16_to_cpu(a->value_offset), | ||||
| 					min(val_len, | ||||
| 					le32_to_cpu(a->value_length))); | ||||
| 			/*
 | ||||
| 			 * If @val collates before the current attribute's | ||||
| 			 * value, there is no matching attribute. | ||||
| 			 */ | ||||
| 			if (!rc) { | ||||
| 				register u32 avl; | ||||
| 				avl = le32_to_cpu(a->value_length); | ||||
| 				if (val_len == avl) | ||||
| 					return 0; | ||||
| 				if (val_len < avl) { | ||||
| 					errno = ENOENT; | ||||
| 					return -1; | ||||
| 				} | ||||
| 			} else if (rc < 0) { | ||||
| 				errno = ENOENT; | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	Dputs("mkntfs_attr_find(): File is corrupt. Run chkdsk."); | ||||
| 	errno = EIO; | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * ntfs_attr_lookup - find an attribute in an ntfs inode | ||||
|  * @type:	attribute type to find | ||||
|  * @name:	attribute name to find (optional, i.e. NULL means don't care) | ||||
|  * @name_len:	attribute name length (only needed if @name present) | ||||
|  * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) | ||||
|  * @lowest_vcn:	lowest vcn to find (optional, non-resident attributes only) | ||||
|  * @val:	attribute value to find (optional, resident attributes only) | ||||
|  * @val_len:	attribute value length | ||||
|  * @ctx:	search context with mft record and attribute to search from | ||||
|  * | ||||
|  * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must | ||||
|  * be the base mft record and @ctx must have been obtained from a call to | ||||
|  * ntfs_attr_get_search_ctx(). | ||||
|  * | ||||
|  * This function transparently handles attribute lists and @ctx is used to | ||||
|  * continue searches where they were left off at. | ||||
|  * | ||||
|  * If @type is AT_UNUSED, return the first found attribute, i.e. one can | ||||
|  * enumerate all attributes by setting @type to AT_UNUSED and then calling | ||||
|  * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT | ||||
|  * to indicate that there are no more entries. During the enumeration, each | ||||
|  * successful call of ntfs_attr_lookup() will return the next attribute, with | ||||
|  * the current attribute being described by the search context @ctx. | ||||
|  * | ||||
|  * If @type is AT_END, seek to the end of the base mft record ignoring the | ||||
|  * attribute list completely and return -1 with errno set to ENOENT.  AT_END is | ||||
|  * not a valid attribute, its length is zero for example, thus it is safer to | ||||
|  * return error instead of success in this case.  It should never ne needed to | ||||
|  * do this, but we implement the functionality because it allows for simpler | ||||
|  * code inside ntfs_external_attr_find(). | ||||
|  * | ||||
|  * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present | ||||
|  * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, | ||||
|  * match both named and unnamed attributes. | ||||
|  * | ||||
|  * After finishing with the attribute/mft record you need to call | ||||
|  * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any | ||||
|  * mapped extent inodes, etc). | ||||
|  * | ||||
|  * Return 0 if the search was successful and -1 if not, with errno set to the | ||||
|  * error code. | ||||
|  * | ||||
|  * On success, @ctx->attr is the found attribute, it is in mft record | ||||
|  * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this | ||||
|  * attribute with @ctx->base_* being the base mft record to which @ctx->attr | ||||
|  * belongs.  If no attribute list attribute is present @ctx->al_entry and | ||||
|  * @ctx->base_* are NULL. | ||||
|  * | ||||
|  * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the | ||||
|  * attribute which collates just after the attribute being searched for in the | ||||
|  * base ntfs inode, i.e. if one wants to add the attribute to the mft record | ||||
|  * this is the correct place to insert it into, and if there is not enough | ||||
|  * space, the attribute should be placed in an extent mft record. | ||||
|  * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list | ||||
|  * at which the new attribute's attribute list entry should be inserted.  The | ||||
|  * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. | ||||
|  * The only exception to this is when @type is AT_END, in which case | ||||
|  * @ctx->al_entry is set to NULL also (see above). | ||||
|  * | ||||
|  * | ||||
|  * The following error codes are defined: | ||||
|  *	ENOENT	Attribute not found, not an error as such. | ||||
|  *	EINVAL	Invalid arguments. | ||||
|  *	EIO	I/O error or corrupt data structures found. | ||||
|  *	ENOMEM	Not enough memory to allocate necessary buffers. | ||||
|  */ | ||||
| int mkntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, | ||||
| 		const u32 name_len, const IGNORE_CASE_BOOL ic, | ||||
| 		const VCN lowest_vcn, const u8 *val, const u32 val_len, | ||||
| 		ntfs_attr_search_ctx *ctx) | ||||
| { | ||||
| 	ntfs_inode *base_ni; | ||||
| 
 | ||||
| 	if (!ctx || !ctx->mrec || !ctx->attr) { | ||||
| 		errno = EINVAL; | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if (ctx->base_ntfs_ino) | ||||
| 		base_ni = ctx->base_ntfs_ino; | ||||
| 	else | ||||
| 		base_ni = ctx->ntfs_ino; | ||||
| 	if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST) | ||||
| 		return mkntfs_attr_find(type, name, name_len, ic, val, val_len, | ||||
| 				ctx); | ||||
| 	errno = EOPNOTSUPP; | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * ntfs_attr_put_search_ctx - release an attribute search context | ||||
|  * @ctx:	attribute search context to free | ||||
|  * | ||||
|  * Release the attribute search context @ctx. | ||||
|  */ | ||||
| void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx) | ||||
| { | ||||
| 	free(ctx); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * insert_positioned_attr_in_mft_record | ||||
|  * Create a non-resident attribute with a predefined on disk location | ||||
|  | @ -1229,7 +1520,7 @@ static int insert_positioned_attr_in_mft_record(MFT_RECORD *m, | |||
| 		err = -EOPNOTSUPP; | ||||
| 		goto err_out; | ||||
| 	} | ||||
| 	if (!ntfs_attr_lookup(type, uname, name_len, ic, 0, NULL, 0, ctx)) { | ||||
| 	if (!mkntfs_attr_lookup(type, uname, name_len, ic, 0, NULL, 0, ctx)) { | ||||
| 		err = -EEXIST; | ||||
| 		goto err_out; | ||||
| 	} | ||||
|  | @ -1414,7 +1705,7 @@ static int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, | |||
| 		err = -EOPNOTSUPP; | ||||
| 		goto err_out; | ||||
| 	} | ||||
| 	if (!ntfs_attr_lookup(type, uname, name_len, ic, 0, NULL, 0, ctx)) { | ||||
| 	if (!mkntfs_attr_lookup(type, uname, name_len, ic, 0, NULL, 0, ctx)) { | ||||
| 		err = -EEXIST; | ||||
| 		goto err_out; | ||||
| 	} | ||||
|  | @ -1576,7 +1867,7 @@ static int insert_resident_attr_in_mft_record(MFT_RECORD *m, | |||
| 	ntfschar *uname; | ||||
| /*
 | ||||
| 	if (base record) | ||||
| 		ntfs_attr_lookup(); | ||||
| 		mkntfs_attr_lookup(); | ||||
| 	else | ||||
| */ | ||||
| 	if (name_len) { | ||||
|  | @ -1603,7 +1894,7 @@ static int insert_resident_attr_in_mft_record(MFT_RECORD *m, | |||
| 		err = -EOPNOTSUPP; | ||||
| 		goto err_out; | ||||
| 	} | ||||
| 	if (!ntfs_attr_lookup(type, uname, name_len, ic, 0, val, val_len, | ||||
| 	if (!mkntfs_attr_lookup(type, uname, name_len, ic, 0, val, val_len, | ||||
| 			ctx)) { | ||||
| 		err = -EEXIST; | ||||
| 		goto err_out; | ||||
|  | @ -1726,7 +2017,7 @@ static int add_attr_file_name(MFT_RECORD *m, const MFT_REF parent_dir, | |||
| 		Eprintf("Failed to allocate attribute search context.\n"); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 	if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, | ||||
| 	if (mkntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, | ||||
| 			ctx)) { | ||||
| 		int eo = errno; | ||||
| 		Eprintf("BUG: Standard information attribute not present in " | ||||
|  | @ -2126,7 +2417,7 @@ static int upgrade_to_large_index(MFT_RECORD *m, const char *name, | |||
| 			free(uname); | ||||
| 		goto err_out; | ||||
| 	} | ||||
| 	err = ntfs_attr_lookup(AT_INDEX_ROOT, uname, name_len, ic, 0, NULL, 0, | ||||
| 	err = mkntfs_attr_lookup(AT_INDEX_ROOT, uname, name_len, ic, 0, NULL, 0, | ||||
| 			ctx); | ||||
| 	if (uname) | ||||
| 		free(uname); | ||||
|  | @ -3399,7 +3690,7 @@ static void mkntfs_create_root_structures(void) | |||
| 			err_exit("Failed to allocate attribute search " | ||||
| 					"context: %s\n", strerror(errno)); | ||||
| 		/* There is exactly one file name so this is ok. */ | ||||
| 		if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, | ||||
| 		if (mkntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, | ||||
| 				ctx)) { | ||||
| 			ntfs_attr_put_search_ctx(ctx); | ||||
| 			err_exit("BUG: $FILE_NAME attribute not found.\n"); | ||||
|  | @ -3780,7 +4071,7 @@ int main(int argc, char **argv) | |||
| 		err_exit("Failed to allocate attribute search context: %s\n", | ||||
| 				strerror(errno)); | ||||
| 	// FIXME: This should be IGNORE_CASE!
 | ||||
| 	if (ntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4, 0, 0, | ||||
| 	if (mkntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4, 0, 0, | ||||
| 			NULL, 0, ctx)) { | ||||
| 		ntfs_attr_put_search_ctx(ctx); | ||||
| 		err_exit("BUG: $INDEX_ALLOCATION attribute not found.\n"); | ||||
|  | @ -3814,7 +4105,7 @@ int main(int argc, char **argv) | |||
| 	if (!ctx) | ||||
| 		err_exit("Failed to allocate attribute search context: %s\n", | ||||
| 				strerror(errno)); | ||||
| 	if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { | ||||
| 	if (mkntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { | ||||
| 		ntfs_attr_put_search_ctx(ctx); | ||||
| 		err_exit("BUG: $DATA attribute not found.\n"); | ||||
| 	} | ||||
|  |  | |||
|  | @ -1335,11 +1335,11 @@ static void check_output_device(s64 input_size) | |||
| 		set_filesize(input_size); | ||||
| } | ||||
| 
 | ||||
| static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) | ||||
| static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni) | ||||
| { | ||||
| 	ntfs_attr_search_ctx *ret; | ||||
| 
 | ||||
| 	if ((ret = ntfs_attr_get_search_ctx(ni, mrec)) == NULL) | ||||
| 	if ((ret = ntfs_attr_get_search_ctx(ni, NULL)) == NULL) | ||||
| 		perr_printf("ntfs_attr_get_search_ctx"); | ||||
| 
 | ||||
| 	return ret; | ||||
|  | @ -1371,7 +1371,7 @@ static ntfs_attr_search_ctx *lookup_data_attr(ntfs_inode *ni, const char *aname) | |||
| 	ntfschar *ustr = NULL; | ||||
| 	int len = 0; | ||||
| 
 | ||||
| 	if ((ctx = attr_get_search_ctx(ni, NULL)) == NULL) | ||||
| 	if ((ctx = attr_get_search_ctx(ni)) == NULL) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (str2unicode(aname, &ustr, &len) == -1) | ||||
|  |  | |||
|  | @ -237,11 +237,11 @@ static void parse_options(int argc, char **argv) | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) | ||||
| static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni) | ||||
| { | ||||
| 	ntfs_attr_search_ctx *ret; | ||||
| 
 | ||||
| 	if ((ret = ntfs_attr_get_search_ctx(ni, mrec)) == NULL) | ||||
| 	if ((ret = ntfs_attr_get_search_ctx(ni, NULL)) == NULL) | ||||
| 		perr_println("ntfs_attr_get_search_ctx"); | ||||
| 
 | ||||
| 	return ret; | ||||
|  | @ -612,9 +612,9 @@ static int cmp_attributes(ntfs_inode *ni1, ntfs_inode *ni2) | |||
| 	ATTR_TYPES prev_atype, atype1, atype2; | ||||
| 	ntfs_attr_search_ctx *ctx1, *ctx2; | ||||
| 	 | ||||
| 	if (!(ctx1 = attr_get_search_ctx(ni1, NULL))) | ||||
| 	if (!(ctx1 = attr_get_search_ctx(ni1))) | ||||
| 		return -1; | ||||
| 	if (!(ctx2 = attr_get_search_ctx(ni2, NULL))) | ||||
| 	if (!(ctx2 = attr_get_search_ctx(ni2))) | ||||
| 		goto out; | ||||
| 	 | ||||
| 	atype1 = ctx1->attr->type;  | ||||
|  |  | |||
|  | @ -16,16 +16,15 @@ | |||
| .\" .sp <n> insert n+1 empty lines | ||||
| .\" for manpage-specific macros, see man(7) | ||||
| .SH NAME | ||||
| ntfsfix \- fix common errors and force Windows to check NTFS | ||||
| ntfsfix \- fix common errors | ||||
| .SH SYNOPSIS | ||||
| .B ntfsfix | ||||
| .I device | ||||
| .SH DESCRIPTION | ||||
| \fBntfsfix\fP is a utility that fixes some common NTFS problems.  | ||||
| \fBntfsfix\fP is \fBNOT\fP a Linux | ||||
| version of chkdsk. It only repairs some fundamental NTFS inconsistencies, | ||||
| resets the NTFS journal file and schedules an NTFS consistency check for  | ||||
| the first boot into Windows. | ||||
| version of chkdsk. It only repairs some fundamental NTFS inconsistencies and | ||||
| resets the NTFS journal file. | ||||
| .sp | ||||
| You may run  | ||||
| .B ntfsfix  | ||||
|  |  | |||
|  | @ -73,7 +73,6 @@ GEN_PRINTF(Qprintf, stdout, NULL, FALSE) | |||
| static const char *EXEC_NAME = "ntfsfix"; | ||||
| static const char *OK        = "OK"; | ||||
| static const char *FAILED    = "FAILED"; | ||||
| static BOOL vol_is_dirty     = FALSE; | ||||
| static BOOL journal_is_empty = FALSE; | ||||
| 
 | ||||
| struct { | ||||
|  | @ -146,32 +145,6 @@ static void parse_options(int argc, char **argv) | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int set_dirty_flag(ntfs_volume *vol) | ||||
| { | ||||
| 	u16 flags; | ||||
| 
 | ||||
| 	if (vol_is_dirty == TRUE) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	printf("Setting required flags on partition... "); | ||||
| 	/*
 | ||||
| 	 * Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run | ||||
| 	 * and fix it for us. | ||||
| 	 */ | ||||
| 	flags = vol->flags | VOLUME_IS_DIRTY; | ||||
| 	/* If NTFS volume version >= 2.0 then set mounted on NT4 flag. */ | ||||
| 	if (vol->major_ver >= 2) | ||||
| 		flags |= VOLUME_MOUNTED_ON_NT4; | ||||
| 	if (ntfs_volume_set_flags(vol, flags)) { | ||||
| 		puts(FAILED); | ||||
| 		fprintf(stderr, "Error setting volume flags.\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	puts(OK); | ||||
| 	vol_is_dirty = TRUE; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int empty_journal(ntfs_volume *vol) | ||||
| { | ||||
| 	if (journal_is_empty == TRUE) | ||||
|  | @ -349,9 +322,6 @@ int main(int argc, char **argv) | |||
| 
 | ||||
| 	printf("Processing of $MFT and $MFTMirr completed successfully.\n"); | ||||
| 
 | ||||
| 	if (set_dirty_flag(vol) < 0) | ||||
| 		goto error_exit; | ||||
| 
 | ||||
| 	if (empty_journal(vol) < 0) | ||||
| 		goto error_exit; | ||||
| 
 | ||||
|  | @ -374,9 +344,6 @@ mount_ok: | |||
| 		goto error_exit; | ||||
| 	} | ||||
| 
 | ||||
| 	if (set_dirty_flag(vol) < 0) | ||||
| 		goto error_exit; | ||||
| 
 | ||||
| 	if (empty_journal(vol) < 0) | ||||
| 		goto error_exit; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1253,7 +1253,7 @@ static int get_type_and_size_of_indx(ntfs_inode *ni, ATTR_RECORD *attr, | |||
| 		memcpy(name, (u8 *)attr + attr->name_offset, | ||||
| 				attr->name_length * sizeof(ntfschar)); | ||||
| 	} | ||||
| 	ctx = ntfs_attr_get_search_ctx(ni, 0); | ||||
| 	ctx = ntfs_attr_get_search_ctx(ni, NULL); | ||||
| 	if (!ctx) { | ||||
| 		perror("ntfs_get_search_ctx failed"); | ||||
| 		free(name); | ||||
|  |  | |||
|  | @ -248,9 +248,8 @@ static int resize_resident_attribute_value(MFT_RECORD *m, ATTR_RECORD *a, | |||
|  */ | ||||
| static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, BOOL force) | ||||
| { | ||||
| 	ntfs_attr_search_ctx *ctx = NULL; | ||||
| 	ntfs_attr_search_ctx *ctx; | ||||
| 	ntfschar *new_label = NULL; | ||||
| 	MFT_RECORD *mrec = NULL; | ||||
| 	ATTR_RECORD *a; | ||||
| 	int label_len; | ||||
| 	int result = 0; | ||||
|  | @ -269,17 +268,7 @@ static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, | |||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (ntfs_file_record_read(vol, (MFT_REF)FILE_Volume, &mrec, NULL)) { | ||||
| 		perror("Error reading file record"); | ||||
| 		goto err_out; | ||||
| 	} | ||||
| 	if (!(mrec->flags & MFT_RECORD_IN_USE)) { | ||||
| 		fprintf(stderr, "Error: $Volume has been deleted. Run " | ||||
| 				"chkdsk to fix this.\n"); | ||||
| 		goto err_out; | ||||
| 	} | ||||
| 	ctx = ntfs_attr_get_search_ctx(NULL, mrec); | ||||
| 	ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); | ||||
| 	if (!ctx) { | ||||
| 		perror("Failed to get attribute search context"); | ||||
| 		goto err_out; | ||||
|  | @ -314,39 +303,38 @@ static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, | |||
| 		new_label[label_len / sizeof(ntfschar)] = cpu_to_le16(L'\0'); | ||||
| 	} | ||||
| 	if (a) { | ||||
| 		if (resize_resident_attribute_value(mrec, a, label_len)) { | ||||
| 		if (resize_resident_attribute_value(ctx->mrec, a, label_len)) { | ||||
| 			perror("Error resizing resident attribute"); | ||||
| 			goto err_out; | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* sizeof(resident attribute record header) == 24 */ | ||||
| 		int asize = (24 + label_len + 7) & ~7; | ||||
| 		u32 biu = le32_to_cpu(mrec->bytes_in_use); | ||||
| 		if (biu + asize > le32_to_cpu(mrec->bytes_allocated)) { | ||||
| 		u32 biu = le32_to_cpu(ctx->mrec->bytes_in_use); | ||||
| 		if (biu + asize > le32_to_cpu(ctx->mrec->bytes_allocated)) { | ||||
| 			errno = ENOSPC; | ||||
| 			perror("Error adding resident attribute"); | ||||
| 			goto err_out; | ||||
| 		} | ||||
| 		a = ctx->attr; | ||||
| 		memmove((u8*)a + asize, a, biu - ((u8*)a - (u8*)mrec)); | ||||
| 		mrec->bytes_in_use = cpu_to_le32(biu + asize); | ||||
| 		memmove((u8*)a + asize, a, biu - ((u8*)a - (u8*)ctx->mrec)); | ||||
| 		ctx->mrec->bytes_in_use = cpu_to_le32(biu + asize); | ||||
| 		a->type = AT_VOLUME_NAME; | ||||
| 		a->length = cpu_to_le32(asize); | ||||
| 		a->non_resident = 0; | ||||
| 		a->name_length = 0; | ||||
| 		a->name_offset = cpu_to_le16(24); | ||||
| 		a->flags = cpu_to_le16(0); | ||||
| 		a->instance = mrec->next_attr_instance; | ||||
| 		mrec->next_attr_instance = cpu_to_le16((le16_to_cpu( | ||||
| 				mrec->next_attr_instance) + 1) & 0xffff); | ||||
| 		a->instance = ctx->mrec->next_attr_instance; | ||||
| 		ctx->mrec->next_attr_instance = cpu_to_le16((le16_to_cpu( | ||||
| 				ctx->mrec->next_attr_instance) + 1) & 0xffff); | ||||
| 		a->value_length = cpu_to_le32(label_len); | ||||
| 		a->value_offset = a->name_offset; | ||||
| 		a->resident_flags = 0; | ||||
| 		a->reservedR = 0; | ||||
| 	} | ||||
| 	memcpy((u8*)a + le16_to_cpu(a->value_offset), new_label, label_len); | ||||
| 	if (!opts.noaction && | ||||
| 			ntfs_mft_record_write(vol, (MFT_REF)FILE_Volume, mrec)) { | ||||
| 	if (!opts.noaction && ntfs_inode_sync(vol->vol_ni)) { | ||||
| 		perror("Error writing MFT Record to disk"); | ||||
| 		goto err_out; | ||||
| 	} | ||||
|  | @ -354,8 +342,6 @@ static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, | |||
| err_out: | ||||
| 	if (new_label) | ||||
| 		free(new_label); | ||||
| 	if (mrec) | ||||
| 		free(mrec); | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -534,7 +534,7 @@ static int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name, | |||
| 		if (!ni) | ||||
| 			goto release; | ||||
| 
 | ||||
| 		ctx = ntfs_attr_get_search_ctx(ni, ni->mrec); | ||||
| 		ctx = ntfs_attr_get_search_ctx(ni, NULL); | ||||
| 		if (!ctx) | ||||
| 			goto release; | ||||
| 
 | ||||
|  | @ -658,7 +658,7 @@ int main(int argc, char **argv) | |||
| 		ntfschar *name = NULL; | ||||
| 		int name_len = 0;; | ||||
| 
 | ||||
| 		ctx = ntfs_attr_get_search_ctx (NULL, ni->mrec); | ||||
| 		ctx = ntfs_attr_get_search_ctx(ni, NULL); | ||||
| 		if (!ctx) | ||||
| 			return -1; | ||||
| 
 | ||||
|  |  | |||
|  | @ -867,7 +867,8 @@ int main (int argc, char *argv[]) | |||
| 
 | ||||
| 	count = move_file (vol, inode, opts.location, 0); | ||||
| 	if ((count > 0) && (!opts.nodirty)) { | ||||
| 		if (ntfs_volume_set_flags (vol, VOLUME_IS_DIRTY) < 0) { | ||||
| 		if (ntfs_volume_set_flags (vol, vol->flags | VOLUME_IS_DIRTY) < | ||||
| 				0) { | ||||
| 			Eprintf ("Couldn't mark volume dirty\n"); | ||||
| 		} | ||||
| 		printf ("Relocated %lld bytes\n", count); | ||||
|  | @ -884,4 +885,3 @@ int main (int argc, char *argv[]) | |||
| 	ntfs_umount (vol, FALSE); | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2249,7 +2249,7 @@ static void prepare_volume_fixup(ntfs_volume *vol) | |||
| 	printf("Schedule chkdsk for NTFS consistency check at Windows " | ||||
| 		"boot time ...\n"); | ||||
| 
 | ||||
| 	if (ntfs_volume_set_flags(vol, flags)) | ||||
| 	if (ntfs_volume_write_flags(vol, flags)) | ||||
| 		perr_exit("Failed to set $Volume dirty"); | ||||
| 
 | ||||
| 	if (vol->dev->d_ops->sync(vol->dev) == -1) | ||||
|  |  | |||
|  | @ -2301,7 +2301,7 @@ static int utils_free_non_residents2 (ntfs_inode *inode, struct ntfs_bmp *bmp) | |||
| 	if (!bmp) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	ctx = ntfs_attr_get_search_ctx (NULL, inode->mrec); | ||||
| 	ctx = ntfs_attr_get_search_ctx (inode, NULL); | ||||
| 	if (!ctx) { | ||||
| 		printf ("can't create a search context\n"); | ||||
| 		return -1; | ||||
|  | @ -2480,7 +2480,7 @@ static int ntfs_mft_resize_resident (ntfs_inode *inode, ATTR_TYPES type, ntfscha | |||
| 	//printf ("mft_free  = %d\n", mft_free);
 | ||||
| 	//printf ("\n");
 | ||||
| 
 | ||||
| 	ctx = ntfs_attr_get_search_ctx (NULL, mrec); | ||||
| 	ctx = ntfs_attr_get_search_ctx (inode, NULL); | ||||
| 	if (!ctx) | ||||
| 		goto done; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1391,10 +1391,6 @@ int main (int argc, char *argv[]) | |||
| 
 | ||||
| 		printf ("%lld bytes were wiped\n", (long long)total); | ||||
| 	} | ||||
| 	if (ntfs_volume_set_flags (vol, VOLUME_IS_DIRTY) < 0) { | ||||
| 		Eprintf ("Couldn't mark volume dirty\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	result = 0; | ||||
| umount: | ||||
| 	ntfs_umount (vol, FALSE); | ||||
|  | @ -1403,4 +1399,3 @@ free: | |||
| 		free (opts.bytes); | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -903,7 +903,7 @@ int mft_next_record (struct mft_search_ctx *ctx) | |||
| 				ctx->flags_match |= FEMR_FILE; | ||||
| 
 | ||||
| 			if (ctx->flags_search & FEMR_DIR) { | ||||
| 				attr_ctx = ntfs_attr_get_search_ctx (NULL, ctx->inode->mrec); | ||||
| 				attr_ctx = ntfs_attr_get_search_ctx (ctx->inode, NULL); | ||||
| 				if (attr_ctx) { | ||||
| 					if (ntfs_attr_lookup (AT_INDEX_ROOT, I30, 4, 0, 0, NULL, 0, attr_ctx) == 0) | ||||
| 						ctx->flags_match |= FEMR_DIR; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue