Subject: bin/6854: uudecode is falling behind the times
To: None <gnats-bugs@gnats.netbsd.org>
From: John F. Woods <jfw@jfwhome.funhouse.com>
List: netbsd-bugs
Date: 01/19/1999 22:01:51
>Number:         6854
>Category:       bin
>Synopsis:       uudecode's minimalist parsing is behind the times
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Jan 19 19:05:00 1999
>Last-Modified:
>Originator:     John F. Woods
>Organization:
Misanthropes-R-Us
>Release:        current as of early January 1999
>Environment:
	
System: NetBSD jfwhome.funhouse.com 1.3G NetBSD 1.3G (JFW) #40: Sun Aug 9 23:59:09 EDT 1998 jfw@jfwhome.funhouse.com:/usr/src/sys/arch/i386/compile/JFW i386


>Description:
	I see a lot of uuencoded files on USENET generated by operating
systems so primitive they do not realize that filenames exist for the
machine's convenience, rather than the oeprator's.  Consequently, there
are frequently spaces in the filename:

	begin 0644 My Master Plan For World Domination.doc

uudecode has the annoying habit of naming the results of decoding such a
file as the first space-delineated word of the name, i.e. "My".  This gets
annoying, especially when there are many uuencoded files starting with the
same word.

>How-To-Repeat:
	Generate files with spaces in the names.  UUencode them.  UUdecode the
results.  Watch the fun.

>Fix:
	The following patch to uudecode makes it generate the correct
filenames, annoying spaces and all.

*** uudecode.c.orig	Tue Jan 19 21:34:09 1999
--- uudecode.c	Tue Jan 19 21:49:43 1999
***************
*** 61,66 ****
--- 61,69 ----
  #include <stdio.h>
  #include <string.h>
  #include <unistd.h>
+ #include <ctype.h>
+ #include <stdlib.h>
+ #include <limits.h>
  
  static int decode __P((void));
  static void usage __P((void));
***************
*** 106,112 ****
  	struct passwd *pw;
  	int n;
  	char ch, *p;
! 	int mode, n1;
  	char buf[MAXPATHLEN];
  
  	/* search for header line */
--- 109,117 ----
  	struct passwd *pw;
  	int n;
  	char ch, *p;
! 	int n1;
! 	long mode;
! 	char *fn;
  	char buf[MAXPATHLEN];
  
  	/* search for header line */
***************
*** 116,131 ****
  			return(1);
  		}
  	} while (strncmp(buf, "begin ", 6));
! 	(void)sscanf(buf, "begin %o %s", &mode, buf);
! 
  	/* handle ~user/file format */
! 	if (buf[0] == '~') {
! 		if (!(p = strchr(buf, '/'))) {
  			warnx("%s: illegal ~user.", filename);
  			return(1);
  		}
  		*p++ = '\0';
! 		if (!(pw = getpwnam(buf + 1))) {
  			warnx("%s: no user %s.", filename, buf);
  			return(1);
  		}
--- 121,152 ----
  			return(1);
  		}
  	} while (strncmp(buf, "begin ", 6));
!         /* must be followed by an octal mode and a space */
! 	mode = strtol(buf + 6, &fn, 8);
! 	if (fn == (buf+6) || !isspace(*fn) || mode==LONG_MIN || mode==LONG_MAX)
! 	{
! 	        warnx("%s: no mode on \"begin\" line\n", filename);
! 		return(1);
! 	}
! 	/* skip whitespace for file name */
! 	while (*fn && isspace(*fn)) fn++;
! 	if (*fn == 0) {
!                 warnx("%s: no filename on \"begin\" line\n", filename);
! 		return(1);
! 	}
! 	/* zap newline */
! 	for (p = fn; *p && *p != '\n'; p++) 
! 	        ;
! 	if (*p) *p = 0;
! 	
  	/* handle ~user/file format */
! 	if (*fn == '~') {
! 		if (!(p = strchr(fn, '/'))) {
  			warnx("%s: illegal ~user.", filename);
  			return(1);
  		}
  		*p++ = '\0';
! 		if (!(pw = getpwnam(fn + 1))) {
  			warnx("%s: no user %s.", filename, buf);
  			return(1);
  		}
***************
*** 135,149 ****
  			warnx("%s: path too long.", filename);
  			return(1);
  		}
  		memmove(buf + n + 1, p, n1 + 1);
  		memmove(buf, pw->pw_dir, n);
  		buf[n] = '/';
  	}
  
  	/* create output file, set mode */
! 	if (!freopen(buf, "w", stdout) ||
  	    fchmod(fileno(stdout), mode&0666)) {
! 		warnx("%s: %s", buf, filename);
  		return(1);
  	}
  
--- 156,172 ----
  			warnx("%s: path too long.", filename);
  			return(1);
  		}
+ 		/* make space at beginning of buf by moving end of pathname */
  		memmove(buf + n + 1, p, n1 + 1);
  		memmove(buf, pw->pw_dir, n);
  		buf[n] = '/';
+ 		fn = buf;
  	}
  
  	/* create output file, set mode */
! 	if (!freopen(fn, "w", stdout) ||
  	    fchmod(fileno(stdout), mode&0666)) {
! 		warnx("%s: %s", fn, filename);
  		return(1);
  	}
  

>Audit-Trail:
>Unformatted: