Package: ntfs-3g
Version: 1:2012.1.15AR.5-4
Severity: serious
Tags: patch upstream
User: ubuntu-de...@lists.ubuntu.com
Usertags: origin-ubuntu quantal ubuntu-patch

*** /tmp/tmpkpCNMv/bug_body

In Ubuntu, the attached patch was applied to achieve the following:

  * ntfs-3g-junction-point-fix.patch: Return the correct type (DT_LINK) for
    NTFS Junction points, in readdir(). (LP: #997391)

A bug was recently fixed in upstream ntfs-3g, where baobab (The GNOME
disk usage visualisation tool) will loop infinitely when scanning a
Windows 7 partition.

http://tuxera.com/forum/viewtopic.php?f=2&t=29578
https://bugzilla.redhat.com/show_bug.cgi?id=849332

Thanks for considering the patch.

SR

-- System Information:
Debian Release: wheezy/sid
  APT prefers testing-proposed-updates
  APT policy: (500, 'testing-proposed-updates'), (500, 'unstable'), (500, 
'testing'), (1, 'experimental')
Architecture: amd64 (x86_64)

Kernel: Linux 3.2.0-2-amd64 (SMP w/8 CPU cores)
Locale: LANG=en_ZA.UTF-8, LC_CTYPE=en_ZA.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Description: Return d_type = DT_LNK for NTFS Junction points in readdir()
 readdir() was returning DT_DIR while stat() was returning S_IFLNK.
 This caused baobab to infinitely loop.
Author: Jean-Pierre Andre
Origin: upstream, http://tuxera.com/forum/viewtopic.php?f=2&t=29578
Bug-Ubuntu: https://launchpad.net/bugs/997391
Bug-Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=849332
Last-Update: 2012-08-21

--- a/libntfs-3g/dir.c
+++ b/libntfs-3g/dir.c
@@ -867,6 +867,83 @@
 	INDEX_TYPE_ALLOCATION,	/* index allocation */
 } INDEX_TYPE;
 
+/*
+ *		Decode Interix file types
+ *
+ *	Non-Interix types are returned as plain files, because a
+ *	Windows user may force patterns very similar to Interix.
+ */
+
+static u32 ntfs_interix_types(ntfs_inode *ni)
+{
+	ntfs_attr *na;
+	u32 dt_type;
+	le64 magic;
+
+	dt_type = NTFS_DT_UNKNOWN;
+	na = ntfs_attr_open(ni, AT_DATA, NULL, 0);
+	if (na) {
+		/* Unrecognized patterns (eg HID + SYST) are plain files */
+		dt_type = NTFS_DT_REG;
+		if (na->data_size <= 1) {
+			if (!(ni->flags & FILE_ATTR_HIDDEN))
+				dt_type = (na->data_size ?
+						NTFS_DT_SOCK : NTFS_DT_FIFO);
+		} else {
+			if ((na->data_size >= (s64)sizeof(magic))
+			    && (ntfs_attr_pread(na, 0, sizeof(magic), &magic)
+				== sizeof(magic))) {
+				if (magic == INTX_SYMBOLIC_LINK)
+					dt_type = NTFS_DT_LNK;
+				else if (magic == INTX_BLOCK_DEVICE)
+					dt_type = NTFS_DT_BLK;
+				else if (magic == INTX_CHARACTER_DEVICE)
+					dt_type = NTFS_DT_CHR;
+			}
+		}
+		ntfs_attr_close(na);
+	}
+	return (dt_type);
+}
+
+/*
+ *		Decode file types
+ *
+ *	Better only use for Interix types and junctions,
+ *	unneeded complexity when used for plain files or directories
+ *
+ *	Error cases are logged and returned as unknown.
+ */
+
+static u32 ntfs_dir_entry_type(ntfs_inode *dir_ni, MFT_REF mref, FILE_ATTR_FLAGS attributes)
+{
+	ntfs_inode *ni;
+	u32 dt_type;
+
+	dt_type = NTFS_DT_UNKNOWN;
+	ni = ntfs_inode_open(dir_ni->vol, mref);
+	if (ni) {
+		if ((attributes & FILE_ATTR_REPARSE_POINT)
+		    && ntfs_possible_symlink(ni))
+			dt_type = NTFS_DT_LNK;
+		else
+			if ((attributes & FILE_ATTR_SYSTEM)
+			   && !(attributes & FILE_ATTR_I30_INDEX_PRESENT))
+				dt_type = ntfs_interix_types(ni);
+			else
+				dt_type = (attributes
+						& FILE_ATTR_I30_INDEX_PRESENT
+					? NTFS_DT_DIR : NTFS_DT_REG);
+		if (ntfs_inode_close(ni)) {
+				 /* anything special to do ? */
+		}
+	}
+	if (dt_type == NTFS_DT_UNKNOWN)
+		ntfs_log_error("Could not decode the type of inode %lld\n",
+				(long long)MREF(mref));
+	return (dt_type);
+}
+
 /**
  * ntfs_filldir - ntfs specific filldir method
  * @dir_ni:	ntfs inode of current directory
@@ -901,19 +978,23 @@
 				dir_ni->vol->mft_record_size;
 	else /* if (index_type == INDEX_TYPE_ROOT) */
 		*pos = (u8*)ie - (u8*)iu.ir;
+	mref = le64_to_cpu(ie->indexed_file);
+        metadata = (MREF(mref) != FILE_root) && (MREF(mref) < FILE_first_user);
 	/* Skip root directory self reference entry. */
 	if (MREF_LE(ie->indexed_file) == FILE_root)
 		return 0;
-	if (ie->key.file_name.file_attributes & FILE_ATTR_I30_INDEX_PRESENT)
+	if ((ie->key.file_name.file_attributes
+		     & (FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYSTEM))
+	    && !metadata)
+		dt_type = ntfs_dir_entry_type(dir_ni, mref,
+					ie->key.file_name.file_attributes);
+	else if (ie->key.file_name.file_attributes
+		     & FILE_ATTR_I30_INDEX_PRESENT)
 		dt_type = NTFS_DT_DIR;
-	else if (fn->file_attributes & FILE_ATTR_SYSTEM)
-		dt_type = NTFS_DT_UNKNOWN;
 	else
 		dt_type = NTFS_DT_REG;
 
 		/* return metadata files and hidden files if requested */
-	mref = le64_to_cpu(ie->indexed_file);
-        metadata = (MREF(mref) != FILE_root) && (MREF(mref) < FILE_first_user);
         if ((!metadata && (NVolShowHidFiles(dir_ni->vol)
 				|| !(fn->file_attributes & FILE_ATTR_HIDDEN)))
             || (NVolShowSysFiles(dir_ni->vol) && (NVolShowHidFiles(dir_ni->vol)
--- a/src/ntfs-3g.c
+++ b/src/ntfs-3g.c
@@ -1017,10 +1017,30 @@
 	} else {
 		struct stat st = { .st_ino = MREF(mref) };
 		 
-		if (dt_type == NTFS_DT_REG)
-			st.st_mode = S_IFREG | (0777 & ~ctx->fmask);
-		else if (dt_type == NTFS_DT_DIR)
+		switch (dt_type) {
+		case NTFS_DT_DIR :
 			st.st_mode = S_IFDIR | (0777 & ~ctx->dmask); 
+			break;
+		case NTFS_DT_LNK :
+			st.st_mode = S_IFLNK | 0777;
+			break;
+		case NTFS_DT_FIFO :
+			st.st_mode = S_IFIFO;
+			break;
+		case NTFS_DT_SOCK :
+			st.st_mode = S_IFSOCK;
+			break;
+		case NTFS_DT_BLK :
+			st.st_mode = S_IFBLK;
+			break;
+		case NTFS_DT_CHR :
+			st.st_mode = S_IFCHR;
+			break;
+		default : /* unexpected types shown as plain files */
+		case NTFS_DT_REG :
+			st.st_mode = S_IFREG | (0777 & ~ctx->fmask);
+			break;
+		}
 		
 #if defined(__APPLE__) || defined(__DARWIN__)
 		/* 
--- a/src/lowntfs-3g.c
+++ b/src/lowntfs-3g.c
@@ -920,10 +920,30 @@
 	if (MREF(mref) > 1) {
 		struct stat st = { .st_ino = MREF(mref) };
 		 
-		if (dt_type == NTFS_DT_REG)
-			st.st_mode = S_IFREG | (0777 & ~ctx->fmask);
-		else if (dt_type == NTFS_DT_DIR)
+		switch (dt_type) {
+		case NTFS_DT_DIR :
 			st.st_mode = S_IFDIR | (0777 & ~ctx->dmask); 
+			break;
+		case NTFS_DT_LNK :
+			st.st_mode = S_IFLNK | 0777;
+			break;
+		case NTFS_DT_FIFO :
+			st.st_mode = S_IFIFO;
+			break;
+		case NTFS_DT_SOCK :
+			st.st_mode = S_IFSOCK;
+			break;
+		case NTFS_DT_BLK :
+			st.st_mode = S_IFBLK;
+			break;
+		case NTFS_DT_CHR :
+			st.st_mode = S_IFCHR;
+			break;
+		default : /* unexpected types shown as plain files */
+		case NTFS_DT_REG :
+			st.st_mode = S_IFREG | (0777 & ~ctx->fmask);
+			break;
+		}
 	        
 #if defined(__APPLE__) || defined(__DARWIN__)
 		/* 

Reply via email to