Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 16 Jan 2001 14:50:20 +0200
From:      Peter Pentchev <roam@orbitel.bg>
To:        mouss <usebsd@free.fr>
Cc:        "W.H.Scholten" <whs@xs4all.nl>, Alfred Perlstein <bright@wintelcom.net>, freebsd-hackers@FreeBSD.ORG
Subject:   Re: pppd & mkdir diff
Message-ID:  <20010116145020.E364@ringworld.oblivion.bg>
In-Reply-To: <4.3.0.20010116131322.03f23a80@pop.free.fr>; from usebsd@free.fr on Tue, Jan 16, 2001 at 01:32:13PM %2B0100
References:  <3A5C843C.794BDF32@xs4all.nl> <20010111132509.J7240@fw.wintelcom.net> <3A5EE6B1.41C67EA6@xs4all.nl> <20010112081422.U7240@fw.wintelcom.net> <3A6025F1.794BDF32@xs4all.nl> <4.3.0.20010116131322.03f23a80@pop.free.fr>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, Jan 16, 2001 at 01:32:13PM +0100, mouss wrote:
> These are probably cosmetic comments, but here they are anyway...
> 
> 
> At 09:54 13/01/01 +0000, W.H.Scholten wrote:
> 
> >+char *dirname(char *path) {
> >+       char *slash;
> >+
> >+       while (path[ strlen(path)-1 ] == '/') path[ strlen(path)-1 ] = 0;
> 
> if path is an empty string, you are accessing path[-1], which is dangerous.
> 
> Also, you're computing strlen too many times, and strlen is a loop
> (while (*ptr) ptr++). so I suggest using a pointer to the string as in
> /usr/bin/dirname/dirname.c. mainly:
>          if (*path == '\0') return "/";  /* if const is not ok, strdup("/") */
>          ptr = path;
>          while (*ptr) ptr++;
>          while ((*ptr == '/') && (ptr > path)) ptr--;
> ...
> 
> 
> >+
> >+       slash = strrchr(path, '/');
> >+       if (slash) {
> >+               *slash = 0;
> >+               while (path[ strlen(path)-1 ] == '/') path[ strlen(path)-1 
> >] = 0;
> 
> you already did that (I mean trimming the trailing slashes).
> 
> Finally, I'd propose adding such a function (dirname) in a library (either libc
> or say libfile) to allow code reuse. such a lib would contain functions
> such as basename, dir_create (mkdir -p), .... so that the commands
> mkdir, rmdir, cp, mv, ... etc call the lib functions instead of rewriting code.

As somebody already pointed out, there *is* a dirname(3) function, and even
a dirname(1) cmdline utility to invoke it.

In a followup to Alfred's mkdir(1) commit, I sent a sample implementation
of a direxname() function, which calls dirname(3) in a loop, and returns
the longest existing path component.  I'll get back to him shortly
with a patch to mkdir(1) using direxname() to report a meaningful error
message, something like "Cannot create /exists/nonex/foo/bar, nonexistent
path components after /exists".  In the meantime, attached is my first
shot at direxname() implementation, using dirname(3)'s static buffer.

G'luck,
Peter

-- 
"yields falsehood, when appended to its quotation." yields falsehood, when appended to its quotation.

#include <sys/types.h>
#include <sys/stat.h>

#include <err.h>
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <sysexits.h>
#include <unistd.h>

char *direxname(const char *path);
void usage(void);

int
main(int argc, char **argv) {
	char ch, *p;

	while (ch = getopt(argc, argv, ""), ch != -1)
		switch (ch) {
			case '?':
			default:
				usage();
		}
	argc -= optind;
	argv += optind;

	if (argc != 1)
		usage();

	if (p = direxname(argv[0]), p == NULL)
		err(1, "%s", argv[0]);
	printf("%s\n", p);
	return (EX_OK);
}

void
usage(void) {
	errx(EX_USAGE, "usage: direxname path");
}

char *
direxname(const char *path) {
	char *d;
	struct stat sb;

	for (d = dirname(path); d != NULL; d = dirname(d)) {
		if (stat(d, &sb) == 0)
			return (d);
		if ((errno != ENOTDIR) && (errno != ENOENT))
			return (NULL);
	}

	/* dirname() returned NULL, errno is set */
	return (NULL);
}


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010116145020.E364>