NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/10715 (msdosfs LFN problems)



The following reply was made to PR kern/10715; it has been noted by GNATS.

From: Thomas Klausner <wiz%NetBSD.org@localhost>
To: gnats-bugs%NetBSD.org@localhost
Cc: jdolecek%NetBSD.org@localhost, pooka%NetBSD.org@localhost
Subject: Re: kern/10715 (msdosfs LFN problems)
Date: Sat, 26 Jan 2008 15:46:43 +0100

 --K8nIJk4ghYZn606h
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 On Sat, Jan 19, 2008 at 04:51:48PM +0000, Antti Kantee wrote:
 > Synopsis: msdosfs LFN problems
 > 
 > State-Changed-From-To: analyzed->feedback
 > State-Changed-By: pooka%narn.netbsd.org@localhost
 > State-Changed-When: Sat, 19 Jan 2008 18:51:47 +0200
 > State-Changed-Why:
 > does the patch in the PR work?  it's high time we solve this as 7 years of
 > discussing the problem has not produced a result
 
 The patch didn't apply cleanly, I changed it to match the comment
 above the list of characters.
 
 The attached (perhaps wrongly updated) patch makes access to SFN files
 on msdosfs fail, with:
 ls: IMG_3098.JPG: Invalid argument
 
 So either I updated it incorrectly, the rest of the code has changed
 incompatibly in the meantime, or it is wrong :(
  Thomas
 
 --K8nIJk4ghYZn606h
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename="lfnconv-updated.diff"
 
 Index: msdosfs_conv.c
 ===================================================================
 RCS file: /cvsroot/src/sys/fs/msdosfs/msdosfs_conv.c,v
 retrieving revision 1.5
 diff -u -r1.5 msdosfs_conv.c
 --- msdosfs_conv.c     11 Dec 2005 12:24:25 -0000      1.5
 +++ msdosfs_conv.c     25 Jan 2008 16:28:53 -0000
 @@ -233,6 +233,12 @@
        tsp->tv_nsec = (dh % 100) * 10000000;
  }
  
 +/*
 + * Characters allowed in short file names:
 + * letters, digits, characters with code value > 127 and
 + * $ % ' - _ @ ~ ` ! ( ) { } ^ # &
 + * All other characters are not allowed.
 + */
  static const u_char
  unix2dos[256] = {
        0,    0,    0,    0,    0,    0,    0,    0,    /* 00-07 */
 @@ -240,7 +246,7 @@
        0,    0,    0,    0,    0,    0,    0,    0,    /* 10-17 */
        0,    0,    0,    0,    0,    0,    0,    0,    /* 18-1f */
        0,    '!',  0,    '#',  '$',  '%',  '&',  '\'', /* 20-27 */
 -      '(',  ')',  0,    '+',  0,    '-',  0,    0,    /* 28-2f */
 +      '(',  ')',  0,    0,    0,    '-',  0,    0,    /* 28-2f */
        '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  /* 30-37 */
        '8',  '9',  0,    0,    0,    0,    0,    0,    /* 38-3f */
        '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  /* 40-47 */
 @@ -429,8 +435,7 @@
        int i, j, l;
        int conv = 1;
        const u_char *cp, *dp, *dp1;
 -      u_char gentext[6], *wcp;
 -      int shortlen;
 +      u_char gentext[6], *wcp, ch;
  
        /*
         * Fill the dos filename string with blanks. These are DOS's pad
 @@ -464,13 +469,38 @@
                return 0;
  
        /*
 +       * Skip leading blanks.
 +       */
 +      if (un[0] == ' ') {
 +              conv = 3;
 +              while(un[0] == ' ') {
 +                      un++;
 +                      unlen--;
 +              }
 +      }
 +              
 +      /*
 +       * Check that name contains only valid characters. If using
 +       * long file names, couple additional characters are
 +       * supported for them; handle them appropriately.
 +       */
 +      for(i=0; i < unlen; i++) {
 +              ch = unix2dos[un[i]];
 +              if (ch == 0) {
 +                      if (!strchr("+,;=[]", un[i]))
 +                              return (0);
 +                      conv = 3;
 +              }
 +      }
 +
 +      /*
         * Now find the extension
         * Note: dot as first char doesn't start extension
         *       and trailing dots and blanks are ignored
         */
 -      dp = dp1 = 0;
 -      for (cp = un + 1, i = unlen - 1; --i >= 0;) {
 -              switch (*cp++) {
 +      dp = dp1 = NULL;
 +      for (cp = un + 1, i = unlen - 1; --i >= 0; cp++) {
 +              switch (*cp) {
                case '.':
                        if (!dp1)
                                dp1 = cp;
 @@ -478,9 +508,10 @@
                case ' ':
                        break;
                default:
 -                      if (dp1)
 +                      if (dp1) {
                                dp = dp1;
 -                      dp1 = 0;
 +                              dp1 = NULL;
 +                      }
                        break;
                }
        }
 @@ -493,40 +524,35 @@
                        l = dp1 - dp;
                else
                        l = unlen - (dp - un);
 -              for (i = 0, j = 8; i < l && j < 11; i++, j++) {
 -                      if (dp[i] != (dn[j] = unix2dos[dp[i]])
 -                          && conv != 3)
 -                              conv = 2;
 -                      if (!dn[j]) {
 +              for (i = 0, j = 8; i < l && j < 11; i++) {
 +                      ch = unix2dos[dp[i]];
 +                      if (!ch) {
                                conv = 3;
 -                              dn[j--] = ' ';
 -                      }
 +                              continue;
 +                      } else if (dp[i] != ch && conv != 3)
 +                              conv = 2;
 +
 +                      dn[j++] = ch;
                }
                if (i < l)
                        conv = 3;
 -              dp--;
        } else {
                for (dp = cp; *--dp == ' ' || *dp == '.';);
                dp++;
        }
  
 -      shortlen = (dp - un) <= 8;
 -
        /*
         * Now convert the rest of the name
         */
 -      for (i = j = 0; un < dp && j < 8; i++, j++, un++) {
 -              if ((*un == ' ') && shortlen)
 -                      dn[j] = ' ';
 -              else
 -                      dn[j] = unix2dos[*un];
 -              if ((*un != dn[j])
 -                  && conv != 3)
 -                      conv = 2;
 -              if (!dn[j]) {
 +      for (i = j = 0; un < dp && j < 8; i++, un++) {
 +              ch = unix2dos[*un];
 +              if (!ch) {
                        conv = 3;
 -                      dn[j--] = ' ';
 -              }
 +                      continue;
 +              } else if ((*un != ch) && conv != 3)
 +                      conv = 2;
 +
 +              dn[j++] = ch;
        }
        if (un < dp)
                conv = 3;
 
 --K8nIJk4ghYZn606h--
 



Home | Main Index | Thread Index | Old Index