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);
}