see changelog
							parent
							
								
									23a84fe825
								
							
						
					
					
						commit
						a732881c5e
					
				|  | @ -58,6 +58,15 @@ xx/xx/2005 - 1.12.2-WIP | |||
| 	- ntfsinfo: dump index attribute keys.  (Szaka) | ||||
| 	- mkntfs: don't fill the last $MFT cluster with empty MFT records.  | ||||
| 	  This is needed to conform to Windows' format behavior.  (Szaka) | ||||
| 	- Add @flags field to struct ntfs_inode. Remove NIno{Sparse,Compressed, | ||||
| 	  Encrypted}, update all users to use @(ntfs_inode)->flags.  (Yura) | ||||
| 	- Make @(ntfs_inode)->data_size and @(ntfs_inode)->allocated_size to | ||||
| 	  always contain valid value.  (Yura) | ||||
| 	- Always set correct file size and attributes in ntfs_link().  (Yura) | ||||
| 	- Add info about Interix special files (symbolic links, character and | ||||
| 	  block devices, FIFOs and sockets) to layout.h. Teech ntfsmount to | ||||
| 	  handle them.  (Yura) | ||||
| 	- Fix allocated data size for resident attributes.  (Yura) | ||||
| 
 | ||||
| 10/10/2005 - 1.12.1 - Minor fix to location of mount.ntfs-fuse and mkfs.ntfs. | ||||
| 
 | ||||
|  |  | |||
|  | @ -203,30 +203,30 @@ typedef enum { | |||
| #define NAttrSetNonResident(na)		  set_nattr_flag(na, NonResident) | ||||
| #define NAttrClearNonResident(na)	clear_nattr_flag(na, NonResident) | ||||
| 
 | ||||
| #define GenNAttrIno(flag)					\ | ||||
| static inline int NAttr##flag(ntfs_attr *na)			\ | ||||
| #define GenNAttrIno(func_name,flag)				\ | ||||
| static inline int NAttr##func_name(ntfs_attr *na)		\ | ||||
| {								\ | ||||
| 	if (na->type == AT_DATA && na->name == AT_UNNAMED)	\ | ||||
| 		return NIno##flag(na->ni);			\ | ||||
| 		return (na->ni->flags & FILE_ATTR_##flag);	\ | ||||
| 	return 0;						\ | ||||
| }								\ | ||||
| static inline void NAttrSet##flag(ntfs_attr *na)		\ | ||||
| static inline void NAttrSet##func_name(ntfs_attr *na)		\ | ||||
| {								\ | ||||
| 	if (na->type == AT_DATA && na->name == AT_UNNAMED)	\ | ||||
| 		NInoSet##flag(na->ni);				\ | ||||
| 		na->ni->flags |= FILE_ATTR_##flag;		\ | ||||
| 	else							\ | ||||
| 		ntfs_log_trace("BUG! Should be called only for "\ | ||||
| 			"unnamed data attribute.\n");		\ | ||||
| }								\ | ||||
| static inline void NAttrClear##flag(ntfs_attr *na)		\ | ||||
| static inline void NAttrClear##func_name(ntfs_attr *na)		\ | ||||
| {								\ | ||||
| 	if (na->type == AT_DATA && na->name == AT_UNNAMED)	\ | ||||
| 		NInoClear##flag(na->ni);			\ | ||||
| 		na->ni->flags &= ~FILE_ATTR_##flag;		\ | ||||
| } | ||||
| 
 | ||||
| GenNAttrIno(Compressed) | ||||
| GenNAttrIno(Encrypted) | ||||
| GenNAttrIno(Sparse) | ||||
| GenNAttrIno(Compressed, COMPRESSED) | ||||
| GenNAttrIno(Encrypted, ENCRYPTED) | ||||
| GenNAttrIno(Sparse, SPARSE_FILE) | ||||
| 
 | ||||
| /*
 | ||||
|  * Union of all known attribute values. For convenience. Used in the attr | ||||
|  |  | |||
|  | @ -45,9 +45,6 @@ typedef enum { | |||
| 	NI_AttrList,		/* 1: Mft record contains an attribute list. */ | ||||
| 	NI_AttrListDirty,	/* 1: Attribute list needs to be written to the
 | ||||
| 				      mft record and then to disk. */ | ||||
| 	NI_Compressed,		/* 1: Inode is compressed. */ | ||||
| 	NI_Encrypted,		/* 1: Inode is encrypted. */ | ||||
| 	NI_Sparse,		/* 1: Inode is sparse. */ | ||||
| 	NI_FileNameDirty,	/* 1: FILE_NAME attributes need to be updated
 | ||||
| 				      in the index. */ | ||||
| } ntfs_inode_state_bits; | ||||
|  | @ -87,18 +84,6 @@ typedef enum { | |||
| #define NInoAttrListTestAndSetDirty(ni)	    test_and_set_nino_al_flag(ni, Dirty) | ||||
| #define NInoAttrListTestAndClearDirty(ni) test_and_clear_nino_al_flag(ni, Dirty) | ||||
| 
 | ||||
| #define NInoCompressed(ni)		 test_nino_flag(ni, Compressed) | ||||
| #define NInoSetCompressed(ni)		  set_nino_flag(ni, Compressed) | ||||
| #define NInoClearCompressed(ni)		clear_nino_flag(ni, Compressed) | ||||
| 
 | ||||
| #define NInoEncrypted(ni)		 test_nino_flag(ni, Encrypted) | ||||
| #define NInoSetEncrypted(ni)		  set_nino_flag(ni, Encrypted) | ||||
| #define NInoClearEncrypted(ni)		clear_nino_flag(ni, Encrypted) | ||||
| 
 | ||||
| #define NInoSparse(ni)			 test_nino_flag(ni, Sparse) | ||||
| #define NInoSetSparse(ni)		  set_nino_flag(ni, Sparse) | ||||
| #define NInoClearSparse(ni)		clear_nino_flag(ni, Sparse) | ||||
| 
 | ||||
| #define NInoFileNameDirty(ni)			\ | ||||
| 					  test_nino_flag(ni, FileNameDirty) | ||||
| #define NInoFileNameSetDirty(ni)		\ | ||||
|  | @ -148,7 +133,7 @@ struct _ntfs_inode { | |||
| 	void *private_data;	/* ntfs_dt containing this inode */ | ||||
| 	int ref_count; | ||||
| 
 | ||||
| 	/* Below 2 fields needed to update indexes. They valid if != -1. */ | ||||
| 	/* Below fields are valid only for base inode. */ | ||||
| 	s64 data_size; | ||||
| 	s64 allocated_size; | ||||
| 
 | ||||
|  |  | |||
|  | @ -852,9 +852,10 @@ typedef enum { | |||
| 	   is used to obtain all flags that are valid for reading. */ | ||||
| 	FILE_ATTR_VALID_SET_FLAGS	= const_cpu_to_le32(0x000031a7), | ||||
| 	/* FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the
 | ||||
| 	   F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT, | ||||
| 	   F_A_COMPRESSED and F_A_ENCRYPTED and preserves the rest. This mask | ||||
| 	   is used to to obtain all flags that are valid for setting. */ | ||||
| 	   FILE_ATTR_DEVICE, FILE_ATTR_DIRECTORY, FILE_ATTR_SPARSE_FILE, | ||||
| 	   FILE_ATTR_REPARSE_POINT, FILE_ATRE_COMPRESSED and FILE_ATTR_ENCRYPTED | ||||
| 	   and preserves the rest. This mask is used to to obtain all flags that | ||||
| 	   are valid for setting. */ | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * These flags are only present in the FILE_NAME attribute (in the | ||||
|  |  | |||
|  | @ -409,9 +409,8 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, | |||
| 		s64 l = le32_to_cpu(a->value_length); | ||||
| 		ntfs_attr_init(na, FALSE, a->flags & ATTR_IS_COMPRESSED, | ||||
| 				a->flags & ATTR_IS_ENCRYPTED, | ||||
| 				a->flags & ATTR_IS_SPARSE, l, l, l, | ||||
| 				cs ? sle64_to_cpu(a->compressed_size) : 0, | ||||
| 				cs ? a->compression_unit : 0); | ||||
| 				a->flags & ATTR_IS_SPARSE, (l + 7) & ~7, l, l, | ||||
| 				cs ? (l + 7) & ~7 : 0, 0); | ||||
| 	} | ||||
| 	ntfs_attr_put_search_ctx(ctx); | ||||
| 	return na; | ||||
|  | @ -3702,10 +3701,10 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) | |||
| 		if (!ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, | ||||
| 				newsize)) { | ||||
| 			/* Update the ntfs attribute structure, too. */ | ||||
| 			na->allocated_size = na->data_size = | ||||
| 					na->initialized_size = newsize; | ||||
| 			na->data_size = na->initialized_size = newsize; | ||||
| 			na->allocated_size = (newsize + 7) & ~7; | ||||
| 			if (NAttrCompressed(na) || NAttrSparse(na)) | ||||
| 				na->compressed_size = newsize; | ||||
| 				na->compressed_size = na->allocated_size; | ||||
| 			goto resize_done; | ||||
| 		} | ||||
| 		/* Error! If not enough space, just continue. */ | ||||
|  | @ -4027,8 +4026,8 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) | |||
| 	NAttrClearCompressed(na); | ||||
| 	NAttrClearSparse(na); | ||||
| 	NAttrClearEncrypted(na); | ||||
| 	na->allocated_size = na->initialized_size = na->compressed_size = | ||||
| 			na->data_size; | ||||
| 	na->initialized_size = na->data_size; | ||||
| 	na->allocated_size = na->compressed_size = (na->data_size + 7) & ~7; | ||||
| 	na->compression_block_size = 0; | ||||
| 	na->compression_block_size_bits = na->compression_block_clusters = 0; | ||||
| 	return 0; | ||||
|  |  | |||
|  | @ -1465,8 +1465,11 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) | |||
| 			le16_to_cpu(dir_ni->mrec->sequence_number)); | ||||
| 	fn->file_name_length = name_len; | ||||
| 	fn->file_name_type = FILE_NAME_POSIX; | ||||
| 	fn->file_attributes = ni->flags; | ||||
| 	if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) | ||||
| 		fn->file_attributes = FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT; | ||||
| 		fn->file_attributes |= FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT; | ||||
| 	fn->allocated_size = cpu_to_sle64(ni->allocated_size); | ||||
| 	fn->data_size = cpu_to_sle64(ni->data_size); | ||||
| 	fn->creation_time = utc2ntfs(ni->creation_time); | ||||
| 	fn->last_data_change_time = utc2ntfs(ni->last_data_change_time); | ||||
| 	fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); | ||||
|  | @ -1502,15 +1505,6 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) | |||
| 	/* Increment hard links count. */ | ||||
| 	ni->mrec->link_count = cpu_to_le16(le16_to_cpu( | ||||
| 			ni->mrec->link_count) + 1); | ||||
| 	/*
 | ||||
| 	 * Do not set attributes and file size, instead of this mark filenames | ||||
| 	 * dirty to force attribute and size update during sync. | ||||
| 	 * NOTE: File size may will be not updated and not all attributes will | ||||
| 	 * be set, but it is acceptable since windows driver does not update | ||||
| 	 * all file names when one of the hard links changed. | ||||
| 	 * FIXME: It will be nice to update them all. | ||||
| 	 */ | ||||
| 	NInoFileNameSetDirty(ni); | ||||
| 	/* Done! */ | ||||
| 	ntfs_inode_mark_dirty(ni); | ||||
| 	free(fn); | ||||
|  |  | |||
|  | @ -145,8 +145,6 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) | |||
| 		goto err_out; | ||||
| 	} | ||||
| 	ni->mft_no = MREF(mref); | ||||
| 	ni->data_size = -1; | ||||
| 	ni->allocated_size = -1; | ||||
| 	ctx = ntfs_attr_get_search_ctx(ni, NULL); | ||||
| 	if (!ctx) | ||||
| 		goto err_out; | ||||
|  | @ -160,12 +158,6 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) | |||
| 	} | ||||
| 	std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + | ||||
| 			le16_to_cpu(ctx->attr->value_offset)); | ||||
| 	if (std_info->file_attributes & FILE_ATTR_COMPRESSED) | ||||
| 		NInoSetCompressed(ni); | ||||
| 	if (std_info->file_attributes & FILE_ATTR_ENCRYPTED) | ||||
| 		NInoSetEncrypted(ni); | ||||
| 	if (std_info->file_attributes & FILE_ATTR_SPARSE_FILE) | ||||
| 		NInoSetSparse(ni); | ||||
| 	ni->flags = std_info->file_attributes; | ||||
| 	ni->creation_time = ntfs2utc(std_info->creation_time); | ||||
| 	ni->last_data_change_time = ntfs2utc(std_info->last_data_change_time); | ||||
|  | @ -176,9 +168,8 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) | |||
| 			ctx)) { | ||||
| 		if (errno != ENOENT) | ||||
| 			goto put_err_out; | ||||
| 		/* Attribute list attribute not present so we are done. */ | ||||
| 		ntfs_attr_put_search_ctx(ctx); | ||||
| 		return ni; | ||||
| 		/* Attribute list attribute does not present. */ | ||||
| 		goto get_size; | ||||
| 	} | ||||
| 	NInoSetAttrList(ni); | ||||
| 	l = ntfs_get_attribute_value_length(ctx->attr); | ||||
|  | @ -199,6 +190,27 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) | |||
| 		err = EIO; | ||||
| 		goto put_err_out; | ||||
| 	} | ||||
| get_size: | ||||
| 	if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { | ||||
| 		if (errno != ENOENT) | ||||
| 			goto put_err_out; | ||||
| 		/* Directory or special file. */ | ||||
| 		ni->data_size = ni->allocated_size = 0; | ||||
| 	} else { | ||||
| 		if (ctx->attr->non_resident) { | ||||
| 			ni->data_size = sle64_to_cpu(ctx->attr->data_size); | ||||
| 			if (ctx->attr->flags & | ||||
| 					(ATTR_IS_COMPRESSED & ATTR_IS_SPARSE)) | ||||
| 				ni->allocated_size = sle64_to_cpu( | ||||
| 						ctx->attr->compressed_size); | ||||
| 			else | ||||
| 				ni->allocated_size = sle64_to_cpu( | ||||
| 						ctx->attr->allocated_size); | ||||
| 		} else { | ||||
| 			ni->data_size = le32_to_cpu(ctx->attr->value_length); | ||||
| 			ni->allocated_size = (ni->data_size + 7) & ~7; | ||||
| 		} | ||||
| 	} | ||||
| 	ntfs_attr_put_search_ctx(ctx); | ||||
| 	return ni; | ||||
| put_err_out: | ||||
|  | @ -475,18 +487,7 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni) | |||
| 	} | ||||
| 	std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + | ||||
| 			le16_to_cpu(ctx->attr->value_offset)); | ||||
| 	if (NInoCompressed(ni)) | ||||
| 		std_info->file_attributes |= FILE_ATTR_COMPRESSED; | ||||
| 	else | ||||
| 		std_info->file_attributes &= ~FILE_ATTR_COMPRESSED; | ||||
| 	if (NInoEncrypted(ni)) | ||||
| 		std_info->file_attributes |= FILE_ATTR_ENCRYPTED; | ||||
| 	else | ||||
| 		std_info->file_attributes &= ~FILE_ATTR_ENCRYPTED; | ||||
| 	if (NInoSparse(ni)) | ||||
| 		std_info->file_attributes |= FILE_ATTR_SPARSE_FILE; | ||||
| 	else | ||||
| 		std_info->file_attributes &= ~FILE_ATTR_SPARSE_FILE; | ||||
| 	std_info->file_attributes = ni->flags; | ||||
| 	std_info->creation_time = utc2ntfs(ni->creation_time); | ||||
| 	std_info->last_data_change_time = utc2ntfs(ni->last_data_change_time); | ||||
| 	std_info->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); | ||||
|  | @ -562,22 +563,11 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni) | |||
| 		} | ||||
| 		/* Update flags and file size. */ | ||||
| 		fn = (FILE_NAME_ATTR *)ictx->data; | ||||
| 		if (NInoCompressed(ni)) | ||||
| 			fn->file_attributes |= FILE_ATTR_COMPRESSED; | ||||
| 		else | ||||
| 			fn->file_attributes &= ~FILE_ATTR_COMPRESSED; | ||||
| 		if (NInoEncrypted(ni)) | ||||
| 			fn->file_attributes |= FILE_ATTR_ENCRYPTED; | ||||
| 		else | ||||
| 			fn->file_attributes &= ~FILE_ATTR_ENCRYPTED; | ||||
| 		if (NInoSparse(ni)) | ||||
| 			fn->file_attributes |= FILE_ATTR_SPARSE_FILE; | ||||
| 		else | ||||
| 			fn->file_attributes &= ~FILE_ATTR_SPARSE_FILE; | ||||
| 		if (ni->allocated_size != -1) | ||||
| 			fn->allocated_size = cpu_to_sle64(ni->allocated_size); | ||||
| 		if (ni->data_size != -1) | ||||
| 			fn->data_size = cpu_to_sle64(ni->data_size); | ||||
| 		fn->file_attributes = | ||||
| 				(fn->file_attributes & ~FILE_ATTR_VALID_FLAGS) | | ||||
| 				(ni->flags & FILE_ATTR_VALID_FLAGS); | ||||
| 		fn->allocated_size = cpu_to_sle64(ni->allocated_size); | ||||
| 		fn->data_size = cpu_to_sle64(ni->data_size); | ||||
| 		fn->creation_time = utc2ntfs(ni->creation_time); | ||||
| 		fn->last_data_change_time = utc2ntfs(ni->last_data_change_time); | ||||
| 		fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); | ||||
|  |  | |||
|  | @ -1459,7 +1459,8 @@ mft_rec_already_initialized: | |||
| 	/* Make sure the allocated inode is written out to disk later. */ | ||||
| 	ntfs_inode_mark_dirty(ni); | ||||
| 	/* Initialize time, allocated and data size in ntfs_inode struct. */ | ||||
| 	ni->data_size = ni->allocated_size = -1; | ||||
| 	ni->data_size = ni->allocated_size = 0; | ||||
| 	ni->flags = 0; | ||||
| 	ni->creation_time = ni->last_data_change_time = | ||||
| 			ni->last_mft_change_time = | ||||
| 			ni->last_access_time = time(NULL); | ||||
|  |  | |||
|  | @ -22,9 +22,11 @@ is recommended, but not mandatory. | |||
| .TP | ||||
| .B Fully implemented ntfsmount features are: | ||||
| 
 | ||||
| * Read-only access to normal, sparse and compressed files. | ||||
| * Read-write access to normal and sparse files. | ||||
| 
 | ||||
| * Overwrite normal and sparse files *with* changes to size. | ||||
| * Read-only access to compressed files. | ||||
| 
 | ||||
| * Access to special Interix files (symlinks, devices, FIFOs). | ||||
| 
 | ||||
| * List/Read/Write/Add/Remove named data streams. | ||||
| 
 | ||||
|  |  | |||
|  | @ -312,13 +312,40 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) | |||
| 		} | ||||
| 		stbuf->st_nlink = 1; /* Needed for correct find work. */ | ||||
| 	} else { | ||||
| 		/* Regular or INTX file. */ | ||||
| 		/* Regular or Interix (INTX) file. */ | ||||
| 		stbuf->st_mode = S_IFREG; | ||||
| 		na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); | ||||
| 		if (na) { | ||||
| 			/* Check whether it's special INTX file. */ | ||||
| 			if ((ni->flags & FILE_ATTR_SYSTEM) && na->data_size <= | ||||
| 					sizeof(INTX_FILE_TYPES) + sizeof( | ||||
| 		stbuf->st_size = ni->data_size; | ||||
| 		stbuf->st_blocks = ni->allocated_size >> vol->sector_size_bits; | ||||
| 		stbuf->st_mode |= (0777 & ~ctx->fmask); | ||||
| 		stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); | ||||
| 		if (ni->flags & FILE_ATTR_SYSTEM || stream_name_len) { | ||||
| 			na = ntfs_attr_open(ni, AT_DATA, stream_name, | ||||
| 					stream_name_len); | ||||
| 			if (!na) { | ||||
| 				if (stream_name_len) | ||||
| 					res = -ENOENT; | ||||
| 				goto exit; | ||||
| 			} | ||||
| 			if (stream_name_len) { | ||||
| 				stbuf->st_size = na->data_size; | ||||
| 				stbuf->st_blocks = na->allocated_size >> | ||||
| 					vol->sector_size_bits; | ||||
| 			} | ||||
| 			/* Check whether it's Interix fifo or socket. */ | ||||
| 			if (!(ni->flags & FILE_ATTR_HIDDEN) && | ||||
| 					!stream_name_len) { | ||||
| 				/* FIFO. */ | ||||
| 				if (na->data_size == 0) | ||||
| 					stbuf->st_mode = S_IFIFO; | ||||
| 				/* Socket link. */ | ||||
| 				if (na->data_size == 1) | ||||
| 					stbuf->st_mode = S_IFSOCK; | ||||
| 			} | ||||
| 			/*
 | ||||
| 			 * Check wheter it's Interix symbolic link, block or | ||||
| 			 * character device. | ||||
| 			 */ | ||||
| 			if (na->data_size <= sizeof(INTX_FILE_TYPES) + sizeof( | ||||
| 					ntfschar) * MAX_PATH && na->data_size > | ||||
| 					sizeof(INTX_FILE_TYPES) && | ||||
| 					!stream_name_len) { | ||||
|  | @ -359,18 +386,8 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) | |||
| 					stbuf->st_mode = S_IFLNK; | ||||
| 				free(intx_file); | ||||
| 			} | ||||
| 			stbuf->st_size = na->data_size; | ||||
| 			stbuf->st_blocks = na->allocated_size >> | ||||
| 				vol->sector_size_bits; | ||||
| 			ntfs_attr_close(na); | ||||
| 		} else { | ||||
| 			stbuf->st_size = 0; | ||||
| 			stbuf->st_blocks = 0; | ||||
| 			if (stream_name_len) | ||||
| 				res = -ENOENT; | ||||
| 		} | ||||
| 		stbuf->st_mode |= (0777 & ~ctx->fmask); | ||||
| 		stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); | ||||
| 	} | ||||
| 	stbuf->st_uid = ctx->uid; | ||||
| 	stbuf->st_gid = ctx->gid; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue