Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 21 Jul 2014 23:23:21 +0000 (UTC)
From:      "Pedro F. Giffuni" <pfg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r268968 - stable/10/sbin/fsck_msdosfs
Message-ID:  <201407212323.s6LNNLdZ009000@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: pfg
Date: Mon Jul 21 23:23:20 2014
New Revision: 268968
URL: http://svnweb.freebsd.org/changeset/base/268968

Log:
  MFC	r268632:
  fsck_msdosfs: Assorted fixes from other BSDs.
  
  When truncating cluster chains fix the length of the cluster head.
  http://marc.info/?t=140304310700005&r=1&w=2
  
  Avoid infinite loops in cluster chain linked lists.
  http://marc.info/?l=openbsd-tech&m=140275150804337&w=2
  
  Avoid off-by-one on FAT12 filesystems.
  http://marc.info/?l=openbsd-tech&m=140234174104724&w=2
  
  Obtained from:	NetBSD (from OpenBSD)

Modified:
  stable/10/sbin/fsck_msdosfs/dir.c
  stable/10/sbin/fsck_msdosfs/fat.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sbin/fsck_msdosfs/dir.c
==============================================================================
--- stable/10/sbin/fsck_msdosfs/dir.c	Mon Jul 21 23:00:26 2014	(r268967)
+++ stable/10/sbin/fsck_msdosfs/dir.c	Mon Jul 21 23:23:20 2014	(r268968)
@@ -419,13 +419,14 @@ checksize(struct bootblock *boot, struct
 		      fullpath(dir));
 		if (ask(1, "Drop superfluous clusters")) {
 			cl_t cl;
-			u_int32_t sz = 0;
+			u_int32_t sz, len;
 
-			for (cl = dir->head; (sz += boot->ClusterSize) <
-			    dir->size;)
+			for (cl = dir->head, len = sz = 0;
+			    (sz += boot->ClusterSize) < dir->size; len++)
 				cl = fat[cl].next;
 			clearchain(boot, fat, fat[cl].next);
 			fat[cl].next = CLUST_EOF;
+			fat[dir->head].length = len;
 			return FSFATMOD;
 		} else
 			return FSERROR;

Modified: stable/10/sbin/fsck_msdosfs/fat.c
==============================================================================
--- stable/10/sbin/fsck_msdosfs/fat.c	Mon Jul 21 23:00:26 2014	(r268967)
+++ stable/10/sbin/fsck_msdosfs/fat.c	Mon Jul 21 23:23:20 2014	(r268968)
@@ -436,7 +436,15 @@ tryclear(struct bootblock *boot, struct 
 		clearchain(boot, fat, head);
 		return FSFATMOD;
 	} else if (ask(0, "Truncate")) {
+		uint32_t len;
+		cl_t p;
+
+		for (p = head, len = 0;
+		    p >= CLUST_FIRST && p < boot->NumClusters;
+		    p = fat[p].next, len++)
+			continue;
 		*truncp = CLUST_EOF;
+		fat[head].length = len;
 		return FSFATMOD;
 	} else
 		return FSERROR;
@@ -465,7 +473,8 @@ checkfat(struct bootblock *boot, struct 
 
 		/* follow the chain and mark all clusters on the way */
 		for (len = 0, p = head;
-		     p >= CLUST_FIRST && p < boot->NumClusters;
+		     p >= CLUST_FIRST && p < boot->NumClusters &&
+		     fat[p].head != head;
 		     p = fat[p].next) {
 			fat[p].head = head;
 			len++;
@@ -486,10 +495,10 @@ checkfat(struct bootblock *boot, struct 
 			continue;
 
 		/* follow the chain to its end (hopefully) */
-		for (p = head;
+		for (len = fat[head].length, p = head;
 		     (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters;
 		     p = n)
-			if (fat[n].head != head)
+			if (fat[n].head != head || len-- < 2)
 				break;
 		if (n >= CLUST_EOFS)
 			continue;
@@ -497,14 +506,20 @@ checkfat(struct bootblock *boot, struct 
 		if (n == CLUST_FREE || n >= CLUST_RSRVD) {
 			pwarn("Cluster chain starting at %u ends with cluster marked %s\n",
 			      head, rsrvdcltype(n));
+clear:
 			ret |= tryclear(boot, fat, head, &fat[p].next);
 			continue;
 		}
 		if (n < CLUST_FIRST || n >= boot->NumClusters) {
 			pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n",
-			      head, n);
-			ret |= tryclear(boot, fat, head, &fat[p].next);
-			continue;
+			    head, n);
+			goto clear;
+		}
+		if (head == fat[n].head) {
+			pwarn("Cluster chain starting at %u loops at cluster %u\n",
+			
+			    head, p);
+			goto clear;
 		}
 		pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n",
 		      head, fat[n].head, n);
@@ -621,13 +636,15 @@ writefat(int fs, struct bootblock *boot,
 		default:
 			if (fat[cl].next == CLUST_FREE)
 				boot->NumFree++;
-			if (cl + 1 < boot->NumClusters
-			    && fat[cl + 1].next == CLUST_FREE)
-				boot->NumFree++;
 			*p++ = (u_char)fat[cl].next;
-			*p++ = (u_char)((fat[cl].next >> 8) & 0xf)
-			       |(u_char)(fat[cl+1].next << 4);
-			*p++ = (u_char)(fat[++cl].next >> 4);
+			*p = (u_char)((fat[cl].next >> 8) & 0xf);
+			cl++;
+			if (cl >= boot->NumClusters)
+				break;
+			if (fat[cl].next == CLUST_FREE)
+				boot->NumFree++;
+			*p++ |= (u_char)(fat[cl + 1].next << 4);
+			*p++ = (u_char)(fat[cl + 1].next >> 4);
 			break;
 		}
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201407212323.s6LNNLdZ009000>