And this is the other frequently encountered issue for people
trying to port our mg changes elsewhere. dirname and basename
are usually stupid on other platforms, modifying their input strings,
and other such silliness.

This fixes this issue by wrapping everything in allocating
routines. It requires a couple of extra malloc/frees, but is 
infinitely harder to get wrong.

I thought about passing a buffer and length to the basename wrapper,
but this is easier, consistent with xdirname, and, did I mention,
easier to get right?

It looks like xdirname was added to avoid this bug on such platforms,
but as written, it fails to do so. Probably my bad. It is now fixed. 
Also, all uses of basename are moved to a consistent xbasename.

Comments?


Index: buffer.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/buffer.c,v
retrieving revision 1.75
diff -u -r1.75 buffer.c
--- buffer.c    18 Jan 2011 17:35:42 -0000      1.75
+++ buffer.c    19 Jan 2011 03:51:36 -0000
@@ -665,8 +666,11 @@
 {
        int      count;
        size_t   remain, len;
+       char    *s;
 
-       len = strlcpy(bn, basename(fn), bs);
+       s = xbasename(fn);
+       len = strlcpy(bn, s, bs);
+       free(s);
        if (len >= bs)
                return (FALSE);
 
Index: def.h
===================================================================
RCS file: /cvs/src/usr.bin/mg/def.h,v
retrieving revision 1.115
diff -u -r1.115 def.h
--- def.h       18 Jan 2011 16:25:40 -0000      1.115
+++ def.h       19 Jan 2011 03:51:36 -0000
@@ -357,6 +358,7 @@
 int             makebkfile(int, int);
 int             writeout(struct buffer *, char *);
 void            upmodes(struct buffer *);
+char           *xbasename(const char *);
 
 /* line.c X */
 struct line    *lalloc(int);
Index: dired.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/dired.c,v
retrieving revision 1.47
diff -u -r1.47 dired.c
--- dired.c     18 Jan 2011 17:35:42 -0000      1.47
+++ dired.c     19 Jan 2011 03:51:36 -0000
@@ -336,6 +336,7 @@
 {
        struct line     *lp, *nlp;
        char             fname[NFILEN];
+       char            *s;
 
        for (lp = bfirstlp(curbp); lp != curbp->b_headp; lp = nlp) {
                nlp = lforw(lp);
@@ -346,15 +347,17 @@
                                return (FALSE);
                        case FALSE:
                                if (unlink(fname) < 0) {
-                                       ewprintf("Could not delete '%s'",
-                                           basename(fname));
+                                       s = xbasename(fname);
+                                       ewprintf("Could not delete '%s'", s);
+                                       free(s);
                                        return (FALSE);
                                }
                                break;
                        case TRUE:
                                if (rmdir(fname) < 0) {
-                                       ewprintf("Could not delete directory 
'%s'",
-                                           basename(fname));
+                                       s = xbasename(fname);
+                                       ewprintf("Could not delete directory 
'%s'", s);
+                                       free(s);
                                        return (FALSE);
                                }
                                break;
@@ -371,7 +374,7 @@
 int
 d_copy(int f, int n)
 {
-       char    frname[NFILEN], toname[NFILEN], *bufp;
+       char    frname[NFILEN], toname[NFILEN], *bufp, *s;
        int     ret;
        size_t  off;
        struct buffer *bp;
@@ -385,8 +388,11 @@
                ewprintf("Directory name too long");
                return (FALSE);
        }
-       if ((bufp = eread("Copy %s to: ", toname, sizeof(toname),
-           EFDEF | EFNEW | EFCR, basename(frname))) == NULL)
+       s = xbasename(frname);
+       bufp = eread("Copy %s to: ", toname, sizeof(toname),
+           EFDEF | EFNEW | EFCR, s);
+       free(s);
+       if (bufp == NULL) 
                return (ABORT);
        else if (bufp[0] == '\0')
                return (FALSE);
@@ -401,7 +407,7 @@
 int
 d_rename(int f, int n)
 {
-       char             frname[NFILEN], toname[NFILEN], *bufp;
+       char             frname[NFILEN], toname[NFILEN], *bufp, *s;
        int              ret;
        size_t           off;
        struct buffer   *bp;
@@ -415,8 +421,11 @@
                ewprintf("Directory name too long");
                return (FALSE);
        }
-       if ((bufp = eread("Rename %s to: ", toname,
-           sizeof(toname), EFDEF | EFNEW | EFCR, basename(frname))) == NULL)
+       s = xbasename(frname);
+       bufp = eread("Rename %s to: ", toname,
+           sizeof(toname), EFDEF | EFNEW | EFCR, basename(frname));
+       free(s);
+       if (bufp == NULL)
                return (ABORT);
        else if (bufp[0] == '\0')
                return (FALSE);
@@ -445,7 +454,7 @@
 int
 d_shell_command(int f, int n)
 {
-       char     command[512], fname[MAXPATHLEN], buf[BUFSIZ], *bufp, *cp;
+       char     command[512], fname[MAXPATHLEN], buf[BUFSIZ], *bufp, *cp, *s;
        int      infd, fds[2];
        pid_t    pid;
        struct   sigaction olda, newa;
@@ -463,8 +472,10 @@
        }
 
        command[0] = '\0';
-       if ((bufp = eread("! on %s: ", command, sizeof(command), EFNEW,
-           basename(fname))) == NULL)
+       s = xbasename(fname);
+       bufp = eread("! on %s: ", command, sizeof(command), EFNEW, s);
+       free(s);
+       if (bufp == NULL)
                return (ABORT);
        infd = open(fname, O_RDONLY);
        if (infd == -1) {
Index: file.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/file.c,v
retrieving revision 1.73
diff -u -r1.73 file.c
--- file.c      18 Jan 2011 16:29:37 -0000      1.73
+++ file.c      19 Jan 2011 03:51:36 -0000
@@ -665,15 +665,35 @@
  * place of "/". This means we can always add a trailing
  * slash and be correct.
  * Unlike dirname, we allocate. Caller must free.
+ * Address portability issues by copying argument
+ * before using. Some implementations modify the input string.
  */
 static char *
 xdirname(const char *path)
 {
-       char *dp;
-       
-       dp = dirname(path);
+       char *dp, *ts;
+
+       ts = strdup(path);
+       dp = strdup(dirname(ts));
        if (*dp && dp[0] == '/' && dp[1] == '\0')
-               return (strdup(""));
-               
-       return (strdup(dp));    
+               dp[0] = '\0';
+       free(ts);               
+       return (dp);
+}
+
+/*
+ * Allocating version of basename.
+ * Address portability issue by copying argument
+ * before using: some implementations modify the input string.
+ */
+char *
+xbasename(const char *path)
+{
+       char *s, *ts;
+
+       ts = strdup(path);
+       s = strdup(basename(ts));
+       free(ts);
+
+       return (s);
 }

Reply via email to