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;
                }
        }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to