Subject: proposal: FTS_NOPATH
To: None <tech-userlevel@netbsd.org>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-userlevel
Date: 09/28/2002 19:14:07
--NextPart-20020928191241-2411900
Content-Type: Text/Plain; charset=us-ascii
hi.
i've noticed that "rm -r" can't remove
too deep directories. (ie. pathlen > USHRT_MAX)
it's due to limit of FTSENTRY::fts_pathlen.
but some applications (including rm(1), imo) don't really need
fts_pathlen (and fts_path).
so i plan to add a new flag, FTS_NOPATH, to fts_open.
if it's specified, fts_path{,len} isn't updated and
fts_read can dig into such deep directories.
patch is attached.
is it ok?
--
YAMAMOTO Takashi
--NextPart-20020928191241-2411900
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="fts.diff"
Index: include/fts.h
===================================================================
RCS file: /cvs/NetBSD/basesrc/include/fts.h,v
retrieving revision 1.9
diff -u -p -r1.9 fts.h
--- include/fts.h 1998/11/06 19:44:52 1.9
+++ include/fts.h 2002/09/28 10:01:27
@@ -58,10 +58,11 @@ typedef struct {
#define FTS_SEEDOT 0x020 /* return dot and dot-dot */
#define FTS_XDEV 0x040 /* don't cross devices */
#define FTS_WHITEOUT 0x080 /* return whiteout information */
-#define FTS_OPTIONMASK 0x0ff /* valid user option mask */
+#define FTS_NOPATH 0x100 /* don't need path */
+#define FTS_OPTIONMASK 0x1ff /* valid user option mask */
-#define FTS_NAMEONLY 0x100 /* (private) child names only */
-#define FTS_STOP 0x200 /* (private) unrecoverable error */
+#define FTS_NAMEONLY 0x200 /* (private) child names only */
+#define FTS_STOP 0x400 /* (private) unrecoverable error */
int fts_options; /* fts_open options, global flags */
} FTS;
Index: lib/libc/gen/__fts13.c
===================================================================
RCS file: /cvs/NetBSD/basesrc/lib/libc/gen/__fts13.c,v
retrieving revision 1.40
diff -u -p -r1.40 __fts13.c
--- lib/libc/gen/__fts13.c 2002/09/16 04:10:36 1.40
+++ lib/libc/gen/__fts13.c 2002/09/28 10:01:27
@@ -155,12 +155,14 @@ fts_open(argv, options, compar)
if (ISSET(FTS_LOGICAL))
SET(FTS_NOCHDIR);
- /*
- * Start out with 1K of path space, and enough, in any case,
- * to hold the user's paths.
- */
- if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
- goto mem1;
+ if (!ISSET(FTS_NOPATH)) {
+ /*
+ * Start out with 1K of path space, and enough, in any case,
+ * to hold the user's paths.
+ */
+ if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
+ goto mem1;
+ }
/* Allocate/initialize root's parent. */
if ((parent = fts_alloc(sp, "", 0)) == NULL)
@@ -226,6 +228,11 @@ fts_open(argv, options, compar)
if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
SET(FTS_NOCHDIR);
+ if (ISSET(FTS_NOPATH) && ISSET(FTS_NOCHDIR)) {
+ errno = EINVAL;
+ goto mem3; /*XXX*/
+ }
+
return (sp);
mem3: fts_lfree(root);
@@ -253,14 +260,20 @@ fts_load(sp, p)
* place and the user can access the first node. From fts_open it's
* known that the path will fit.
*/
- len = p->fts_pathlen = p->fts_namelen;
- memmove(sp->fts_path, p->fts_name, len + 1);
- if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
- len = strlen(++cp);
- memmove(p->fts_name, cp, len + 1);
- p->fts_namelen = len;
+ if (ISSET(FTS_NOPATH)) {
+ p->fts_accpath = p->fts_name;
}
- p->fts_accpath = p->fts_path = sp->fts_path;
+ else {
+ len = p->fts_pathlen = p->fts_namelen;
+ memmove(sp->fts_path, p->fts_name, len + 1);
+ if ((cp = strrchr(p->fts_name, '/')) &&
+ (cp != p->fts_name || cp[1])) {
+ len = strlen(++cp);
+ memmove(p->fts_name, cp, len + 1);
+ p->fts_namelen = len;
+ }
+ p->fts_accpath = p->fts_path = sp->fts_path;
+ }
sp->fts_dev = p->fts_dev;
}
@@ -458,9 +471,12 @@ next: tmp = p;
p->fts_instr = FTS_NOINSTR;
}
-name: t = sp->fts_path + NAPPEND(p->fts_parent);
- *t++ = '/';
- memmove(t, p->fts_name, (size_t)(p->fts_namelen + 1));
+name:
+ if (!ISSET(FTS_NOPATH)) {
+ t = sp->fts_path + NAPPEND(p->fts_parent);
+ *t++ = '/';
+ memmove(t, p->fts_name, (size_t)(p->fts_namelen + 1));
+ }
return (sp->fts_cur = p);
}
@@ -478,8 +494,10 @@ name: t = sp->fts_path + NAPPEND(p->fts
return (sp->fts_cur = NULL);
}
- /* Nul terminate the pathname. */
- sp->fts_path[p->fts_pathlen] = '\0';
+ if (!ISSET(FTS_NOPATH)) {
+ /* Nul terminate the pathname. */
+ sp->fts_path[p->fts_pathlen] = '\0';
+ }
/*
* Return to the parent directory. If at a root node or came through
@@ -722,13 +740,15 @@ fts_build(sp, type)
* If not changing directories set a pointer so that can just append
* each new name into the path.
*/
- len = NAPPEND(cur);
- if (ISSET(FTS_NOCHDIR)) {
- cp = sp->fts_path + len;
- *cp++ = '/';
+ if (!ISSET(FTS_NOPATH)) {
+ len = NAPPEND(cur);
+ if (ISSET(FTS_NOCHDIR)) {
+ cp = sp->fts_path + len;
+ *cp++ = '/';
+ }
+ len++;
+ maxlen = sp->fts_pathlen - len;
}
- len++;
- maxlen = sp->fts_pathlen - len;
level = cur->fts_level + 1;
@@ -747,30 +767,33 @@ fts_build(sp, type)
#endif
if ((p = fts_alloc(sp, dp->d_name, dlen)) == NULL)
goto mem1;
- if (dlen >= maxlen) { /* include space for NUL */
- if (fts_palloc(sp, len + dlen + 1)) {
- /*
- * No more memory for path or structures. Save
- * errno, free up the current structure and the
- * structures already allocated.
- */
-mem1: saved_errno = errno;
- if (p)
- free(p);
- fts_lfree(head);
- (void)closedir(dirp);
- errno = saved_errno;
- cur->fts_info = FTS_ERR;
- SET(FTS_STOP);
- return (NULL);
+ if (!ISSET(FTS_NOPATH)) {
+ if (dlen >= maxlen) { /* include space for NUL */
+ if (fts_palloc(sp, len + dlen + 1)) {
+ /*
+ * No more memory for path or
+ * structures. Save errno, free up the
+ * current structure and the structures
+ * already allocated.
+ */
+mem1: saved_errno = errno;
+ if (p)
+ free(p);
+ fts_lfree(head);
+ (void)closedir(dirp);
+ errno = saved_errno;
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ adjust = 1;
+ if (ISSET(FTS_NOCHDIR))
+ cp = sp->fts_path + len;
+ maxlen = sp->fts_pathlen - len;
}
- adjust = 1;
- if (ISSET(FTS_NOCHDIR))
- cp = sp->fts_path + len;
- maxlen = sp->fts_pathlen - len;
- }
- p->fts_pathlen = len + dlen;
+ p->fts_pathlen = len + dlen;
+ }
p->fts_parent = sp->fts_cur;
p->fts_level = level;
@@ -1106,7 +1129,7 @@ fts_palloc(sp, size)
#if 1
/* Protect against fts_pathlen overflow. */
if (size > USHRT_MAX + 1) {
- errno = ENOMEM;
+ errno = ENAMETOOLONG;
return (1);
}
#endif
--NextPart-20020928191241-2411900
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="rm.diff"
Index: bin/rm/rm.c
===================================================================
RCS file: /cvs/NetBSD/basesrc/bin/rm/rm.c,v
retrieving revision 1.30
diff -u -p -r1.30 rm.c
--- bin/rm/rm.c 2002/05/02 13:25:09 1.30
+++ bin/rm/rm.c 2002/09/28 10:12:28
@@ -62,7 +62,7 @@ __RCSID("$NetBSD: rm.c,v 1.30 2002/05/02
#include <string.h>
#include <unistd.h>
-int dflag, eval, fflag, iflag, Pflag ,stdin_ok, Wflag;
+int Cflag, dflag, eval, fflag, iflag, Pflag ,stdin_ok, Wflag;
int check(char *, char *, struct stat *);
void checkdot(char **);
@@ -79,6 +79,7 @@ int main(int, char *[]);
*/
#define NONEXISTENT(x) \
((x) == ENOENT || (x) == ENAMETOOLONG || (x) == ENOTDIR)
+#define PATH(x) ((Cflag) ? (x)->fts_path : (x)->fts_accpath)
/*
* rm --
@@ -96,8 +97,11 @@ main(int argc, char *argv[])
(void)setlocale(LC_ALL, "");
Pflag = rflag = 0;
- while ((ch = getopt(argc, argv, "dfiPRrW")) != -1)
+ while ((ch = getopt(argc, argv, "CdfiPRrW")) != -1)
switch (ch) {
+ case 'C':
+ Cflag = 1;
+ break;
case 'd':
dflag = 1;
break;
@@ -164,6 +168,8 @@ rm_tree(char **argv)
#define SKIPPED 1
flags = FTS_PHYSICAL;
+ if (Cflag)
+ flags |= FTS_NOPATH;
if (!needstat)
flags |= FTS_NOSTAT;
if (Wflag)
@@ -176,12 +182,12 @@ rm_tree(char **argv)
case FTS_DNR:
if (!fflag || p->fts_errno != ENOENT) {
warnx("%s: %s",
- p->fts_path, strerror(p->fts_errno));
+ PATH(p), strerror(p->fts_errno));
eval = 1;
}
continue;
case FTS_ERR:
- errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
+ errx(1, "%s: %s", PATH(p), strerror(p->fts_errno));
/* NOTREACHED */
case FTS_NS:
/*
@@ -192,14 +198,14 @@ rm_tree(char **argv)
continue;
if (needstat) {
warnx("%s: %s",
- p->fts_path, strerror(p->fts_errno));
+ PATH(p), strerror(p->fts_errno));
eval = 1;
continue;
}
break;
case FTS_D:
/* Pre-order: give user chance to skip. */
- if (!fflag && !check(p->fts_path, p->fts_accpath,
+ if (!fflag && !check(PATH(p), p->fts_accpath,
p->fts_statp)) {
(void)fts_set(fts, p, FTS_SKIP);
p->fts_number = SKIPPED;
@@ -212,7 +218,7 @@ rm_tree(char **argv)
break;
default:
if (!fflag &&
- !check(p->fts_path, p->fts_accpath, p->fts_statp))
+ !check(PATH(p), p->fts_accpath, p->fts_statp))
continue;
}
@@ -242,7 +248,7 @@ rm_tree(char **argv)
(fflag && NONEXISTENT(errno)))
continue;
}
- warn("%s", p->fts_path);
+ warn("%s", PATH(p));
eval = 1;
}
if (errno)
@@ -430,7 +436,7 @@ void
usage(void)
{
- (void)fprintf(stderr, "usage: %s [-f|-i] [-dPRrW] file ...\n",
+ (void)fprintf(stderr, "usage: %s [-f|-i] [-CdPRrW] file ...\n",
getprogname());
exit(1);
/* NOTREACHED */
--NextPart-20020928191241-2411900--