[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[FDclone-users:00311] Re: cannot enter ./ in an archive



 しらいです。

In Message-Id <86brihclsp.knu@iDaemons.org>
        "Akinori MUSHA" <knu@iDaemons.org>さんwrites:
>  FDclone 2.05g で、 ./foo のようなパス名のファイルが入った
> tarball をブラウズしたとき、「.」のところで Enter を押しても
> その下に移動できません。2.05f までは問題ありませんでした。

 ああ、そういうケースがありましたね。

 例えば「tar cf foo.tar .」なんてすると archive の中に不要
な「.」という entry が出来てしまい、archive browser で「.」
に移動しても中が空で無意味なので、「.」へは移動出来ないよう
にしようとしたのでした。
 でも「./foo」の場合は無意味でも「.」に移動しないと「foo」
が見えなくなってしまいますよね。どうしましょうか。

 そもそも「.」は「./foo」のような pathname の時でも不要なの
で、pathname の取得の際に無駄な「.」や「..」は削除してしまう
realpath() 的な処理の方がいいかも知れません。
 それだと、ついでに「../foo」とか「foo/../bar」とか混在する
場合にも対処出来るようになりますし。

 一応仕様としては、
	./foo		-> foo
	foo/./bar	-> foo/bar
	foo/../bar	-> bar
	/../foo	-> /foo
	../foo	-> ../foo
のように正規化するルールにしてみました。
 最後のケースだけがちょっと特殊で、「..」への移動が archive
browser の終了ではなくて、疑似的な directory「..」への移動に
なってしまいますので、混乱を生じさせてしまうかも知れません。
 この実装では、こういうケースでは明示的に「..」への移動を選
択した場合と「Bs」で戻る場合とで挙動を敢えて分けてみましたが、
使い勝手はどうでしょうね?

 尤も、こういった entry の入った archive file なんて滅多に
存在しないんでしょうけど。

---- Cut Here ----
diff -u ../old/FD-2.05g/archive.c ./archive.c
--- ../old/FD-2.05g/archive.c	Wed Jul  7 00:00:00 2004
+++ ./archive.c	Fri Jul 16 18:51:51 2004
@@ -163,13 +163,10 @@
 static VOID NEAR poparchdupl __P_((VOID_A));
 #endif
 static int NEAR readattr __P_((namelist *, char *));
+static VOID NEAR archrealpath __P_((char *, char *));
+static char *NEAR readfname __P_((char *, int));
 #if	FD >= 2
 static char *NEAR checkspace __P_((char *, int *));
-# ifdef	_NOKANJIFCONV
-#define	readfname	strndup2
-# else
-static char *NEAR readfname __P_((char *, int));
-# endif
 static int NEAR readfileent __P_((namelist *, char *, char *, int));
 #else	/* FD < 2 */
 static int NEAR countfield __P_((char *, u_char [], int, int *));
@@ -188,6 +185,7 @@
 static VOID NEAR unpackerror __P_((VOID_A));
 static int NEAR readarchive __P_((char *, launchtable *, int));
 static char *NEAR searcharcdir __P_((char *, int));
+static char *NEAR archoutdir __P_((VOID_A));
 static int NEAR undertmp __P_((char *));
 #ifdef	_NODOSDRIVE
 static char *NEAR genfullpath __P_((char *, char *, char *));
@@ -457,9 +455,7 @@
 	int i, c, len;
 	u_int mode;
 
-	if (!*buf) return(0);
 	len = strlen(buf);
-
 	if (len < 9) {
 		mode = (tmp -> st_mode & S_IFMT) | S_IREAD_ALL | S_IWRITE_ALL;
 		while (--len >= 0) {
@@ -547,7 +543,65 @@
 	}
 
 	tmp -> st_mode = mode;
-	return(1);
+	return(len);
+}
+
+static VOID NEAR archrealpath(path, resolved)
+char *path, *resolved;
+{
+	char *cp;
+
+	if (!*path || !strcmp(path, ".")) return;
+	else if ((cp = strdelim(path, 0))) {
+		*cp = '\0';
+		archrealpath(path, resolved);
+		*(cp++) = _SC_;
+		archrealpath(cp, resolved);
+		return;
+	}
+
+	if (!strcmp(path, "..") && *resolved) {
+		if (!(cp = strrdelim(resolved, 0))) cp = resolved;
+		else if (cp == resolved) cp++;
+		*cp = '\0';
+	}
+	else {
+		cp = strcatdelim(resolved);
+		strcpy(cp, path);
+	}
+}
+
+static char *NEAR readfname(s, len)
+char *s;
+int len;
+{
+	char *cp, *tmp;
+	int c;
+
+	cp = malloc2(len + 1);
+	c = s[len];
+	s[len] = '\0';
+	tmp = s;
+	if (*tmp != _SC_) *cp = '\0';
+	else {
+		strcpy(cp, _SS_);
+		tmp++;
+	}
+	archrealpath(tmp, cp);
+	s[len] = c;
+
+	if (len && !*cp) {
+		free(cp);
+		return(NULL);
+	}
+
+#ifdef	_NOKANJIFCONV
+	return(cp);
+#else
+	tmp = newkanjiconv(cp, fnamekcode, DEFCODE, L_FNAME);
+	if (tmp != cp) free(cp);
+	return(tmp);
+#endif
 }
 
 #if	FD >= 2
@@ -572,20 +626,6 @@
 	return(strndup2(s, len));
 }
 
-# ifndef	_NOKANJIFCONV
-static char *NEAR readfname(s, len)
-char *s;
-int len;
-{
-	char *cp, *tmp;
-
-	cp = strndup2(s, len);
-	tmp = newkanjiconv(cp, fnamekcode, DEFCODE, L_FNAME);
-	if (tmp != cp) free(cp);
-	return(tmp);
-}
-# endif	/* !_NOKANJIFCONV */
-
 static int NEAR readfileent(tmp, line, form, skip)
 namelist *tmp;
 char *line, *form;
@@ -813,6 +853,10 @@
 				}
 				if (tmp -> name) free(tmp -> name);
 				tmp -> name = readfname(rawbuf, i);
+				if (!(tmp -> name)) {
+					hit = -2;
+					break;
+				}
 				hit++;
 				err = 0;
 # ifndef	NOSYMLINK
@@ -836,21 +880,24 @@
 				err = 0;
 				break;
 			default:
-				free(buf);
-				free(rawbuf);
-				if (tmp -> name) free(tmp -> name);
+				hit = -1;
+				break;
+		}
+
+		free(buf);
+		free(rawbuf);
+
+		if (hit < 0) {
+			if (tmp -> name) free(tmp -> name);
 # ifndef	NOSYMLINK
-				if (tmp -> linkname) free(tmp -> linkname);
+			if (tmp -> linkname) free(tmp -> linkname);
 # endif
-				return(-1);
-/*NOTREACHED*/
-				break;
+			return(hit);
 		}
+
 		if (!hit) score += 5;
 		else if (hit <= err2) score += err2;
 		score += err;
-		free(buf);
-		free(rawbuf);
 		line += len;
 		if (!ch) while (iswhitespace(*line)) line++;
 	}
@@ -1021,10 +1068,13 @@
 		if (i > 0) buf[i] = '\0';
 		tmp -> st_mode |= S_IFDIR;
 	}
-	tmp -> name = strdup2(buf);
+	if (!(tmp -> name = readfname(buf, strlen(buf)))) {
+		free(buf);
+		return(-1);
+	}
 
 	getfield(buf, line, skip, list, F_MODE);
-	if (!readattr(tmp, buf)) tmp -> st_mode = 0644;
+	readattr(tmp, buf);
 	if (!(tmp -> st_mode & S_IFMT)) tmp -> st_mode |= S_IFREG;
 	if (s_isdir(tmp)) tmp -> flags |= F_ISDIR;
 	else if (s_islnk(tmp)) tmp -> flags |= F_ISLNK;
@@ -1241,41 +1291,44 @@
 static char *NEAR pseudodir(namep)
 namelist *namep;
 {
-	char *cp, *tmp;
+	char *cp, *next;
 	int i, len;
 	u_short ent;
 
-	cp = namep -> name;
-	while ((tmp = strdelim(cp, 0))) {
-		while (*(tmp + 1) == _SC_) tmp++;
-		if (!*(tmp + 1)) break;
-		len = tmp - (namep -> name);
+	for (cp = namep -> name; (next = strdelim(cp, 0)); cp = next + 1) {
+		while (*(next + 1) == _SC_) next++;
+		if (!*(next + 1)) break;
+		len = next - namep -> name;
 		if (!len) len++;
-		for (i = 0; i < maxfile; i++) {
+
+		/* omit filelist[0] as pseudo ".." */
+		for (i = 1; i < maxfile; i++) {
 			if (isdir(&(filelist[i]))
 			&& len == dirmatchlen(filelist[i].name, namep -> name))
 				break;
 		}
+
 		if (i >= maxfile) return(strndup2(namep -> name, len));
 		if (strncmp(filelist[i].name, namep -> name, len)) {
 			filelist[i].name = realloc2(filelist[i].name, len + 1);
 			strncpy2(filelist[i].name, namep -> name, len);
 		}
-		cp = tmp + 1;
 	}
+
 	if (isdir(namep) && !isdotdir(namep -> name))
 	for (i = 0; i < maxfile; i++) {
 		if (isdir(&(filelist[i]))
 		&& !dircmp(filelist[i].name, namep -> name)) {
-			tmp = filelist[i].name;
+			cp = filelist[i].name;
 			ent = filelist[i].ent;
 			memcpy((char *)&(filelist[i]), (char *)namep,
 				sizeof(namelist));
-			filelist[i].name = tmp;
+			filelist[i].name = cp;
 			filelist[i].ent = ent;
 			return(NULL);
 		}
 	}
+
 	return(namep -> name);
 }
 
@@ -1492,6 +1545,7 @@
 		free(cp);
 
 		if (score < 0) {
+			if (score < -1) break;
 			if (formlist[nf]) {
 				free(formlist[nf]);
 				for (i = nf; formlist[i]; i++)
@@ -1715,6 +1769,7 @@
 	char *cp, *tmp;
 	int i, j, n, len;
 
+	/* omit filelist[0] as pseudo ".." */
 	for (i = 1; i < maxarcf; i++) {
 		if (!*archivedir) len = 0;
 		else if (!(len = dirmatchlen(archivedir, arcflist[i].name)))
@@ -1791,6 +1846,29 @@
 	return(NULL);
 }
 
+static char *NEAR archoutdir(VOID_A)
+{
+	char *cp, *file;
+
+	if (!*archivedir) return((char *)-1);
+	if (!(file = searcharcdir(NULL, 0))) return(NULL);
+
+	cp = file + (int)strlen(file) - 1;
+	while (cp > file && *cp == _SC_) cp--;
+#ifdef	BSPATHDELIM
+	if (onkanji1(file, cp - file)) cp++;
+#endif
+	cp = strrdelim2(file, cp);
+	if (!cp) *archivedir = '\0';
+	else {
+		if (cp == file) strcpy(archivedir, _SS_);
+		else strncpy2(archivedir, file, cp - file);
+		file = cp + 1;
+	}
+
+	return(file);
+}
+
 char *archchdir(path)
 char *path;
 {
@@ -1799,11 +1877,11 @@
 
 	if (findpattern) free(findpattern);
 	findpattern = NULL;
-	if (!path || !*path) path = "..";
 #ifndef	_NOBROWSE
 	if (browselist) {
 		int i, n, dupfilepos;
 
+		if (!path || !*path) path = "..";
 		if ((cp = strdelim(path, 0))) {
 			for (i = 1; cp[i]; i++) if (cp[i] != _SC_) break;
 			if (cp[i]) {
@@ -1846,43 +1924,28 @@
 		return("..");
 	}
 #endif	/* !_NOBROWSE */
+
+	if (!path) return(archoutdir());
+	if (!*path) path = "..";
 	strcpy(duparcdir, archivedir);
 	do {
 		if (*path == _SC_) len = 1;
 		else if ((cp = strdelim(path, 0))) len = cp - path;
 		else len = strlen(path);
 
-		if (len == 1 && *path == '.') file = "..";
-		else if (len != 2 || strncmp(path, "..", len)) {
-			if (!searcharcdir(path, len)) {
-				strcpy(archivedir, duparcdir);
-				errno = ENOENT;
-				return(NULL);
-			}
+		if (searcharcdir(path, len)) {
 			if (*(cp = archivedir)) cp = strcatdelim(archivedir);
 			strncpy2(cp, path, len);
 			file = "..";
 		}
-		else if (!*archivedir) return((char *)-1);
-		else {
-			if (!(file = searcharcdir(NULL, 0))) {
-				strcpy(archivedir, duparcdir);
-				errno = ENOENT;
-				return(NULL);
-			}
-			cp = file + (int)strlen(file) - 1;
-			while (cp > file && *cp == _SC_) cp--;
-#ifdef	BSPATHDELIM
-			if (onkanji1(file, cp - file)) cp++;
-#endif
-			cp = strrdelim2(file, cp);
-			if (!cp) *archivedir = '\0';
-			else {
-				if (cp == file) strcpy(archivedir, _SS_);
-				else strncpy2(archivedir, file, cp - file);
-				file = cp + 1;
-			}
+		else if (len != 2 || strncmp(path, "..", len)
+		|| !(file = archoutdir())) {
+			strcpy(archivedir, duparcdir);
+			errno = ENOENT;
+			return(NULL);
 		}
+		else if (file == (char *)-1) break;
+
 		path += len;
 		while (*path == _SC_) path++;
 	} while (*path);
diff -u ../old/FD-2.05g/browse.c ./browse.c
--- ../old/FD-2.05g/browse.c	Wed Jul  7 00:00:00 2004
+++ ./browse.c	Fri Jul 16 18:53:30 2004
@@ -1657,7 +1657,7 @@
 		else if (no > 4) {
 			char *tmp;
 
-			tmp = (filepos < 0) ? ".." : filelist[filepos].name;
+			tmp = (filepos >= 0) ? filelist[filepos].name : NULL;
 			if (!(cp = archchdir(tmp))) {
 				warning(-1, tmp);
 				strcpy(file, tmp);
---- Cut Here ----

                                               しらい たかし