Date: Tue, 5 Nov 1996 07:54:21 +0200 (IST) From: Eli Zaretskii To: DJ Delorie Cc: robert DOT hoehne AT mathematik DOT tu-chemnitz DOT de, djgpp-workers AT delorie DOT com Subject: Re: Problems with opendir() and glob() In-Reply-To: <199611042344.SAA26450@delorie.com> Message-Id: Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII On Mon, 4 Nov 1996, DJ Delorie wrote: > > subst drive, findfirst for "s:/" (if s is substed) does not > > report "." but findfirst for "s:/*.*" reports ".". The result of > > this is, when you do > > Why would findfirst("s:/") return *anything*? It's a directory, not a > wildcard. Robert have chosen an unclear wording IMHO. The real problem as far as I can see it is that `opendir' called findfirst("s:/") instead of findfirst("s:/*.*") where it tried to see if "." is returned from the directory. It just happens that *real* root directories always fail `findfirst', so this code worked. But on a SUBSTed drive, `findfirst' succeeds for the root directory, and that's where the bug became obvious. What Robert *meant* to say (I think) was that a call like findfirst("s:/") succeeds but doesn't return a ".", and so `opendir' thinks it must fake "." and "..", but then `readdir' also finds "." and ".." on its own, so you get them twice. Btw: is it safe to assume that if a "." is found, then ".." will also be found, and that "." is always the first entry returned by `findfirst'? The original code did that, and I didn't change this in the patch below, but I wonder whether some network redirector could pull a trick on us. Here's the fix (tested with `ls' on a SUBSTed drive): *** src/libc/posix/dirent/opendir.c~0 Mon Nov 4 18:25:18 1996 --- src/libc/posix/dirent/opendir.c Mon Nov 4 18:33:58 1996 *************** *** 34,51 **** /* Make absolute path */ _fixpath(name, dir->name); - /* If we're doing opendir of the root directory, we need to - fake out the . and .. entries, as some unix programs (like - mkisofs) expect them and fail if they don't exist */ - dir->need_fake_dot_dotdot = 0; - if (dir->name[1] == ':' && dir->name[2] == '/' && dir->name[3] == 0) - { - /* see if findfirst finds "." anyway */ - int done = findfirst(dir->name, &dir->ff, FA_ARCH|FA_RDONLY|FA_DIREC|FA_SYSTEM); - if (done || strcmp(dir->ff.ff_name, ".")) - dir->need_fake_dot_dotdot = 2; - } - /* Ensure that directory to be accessed exists */ if (access(dir->name, D_OK)) { --- 34,39 ---- *************** *** 69,79 **** break; } } - dir->name[length++] = '/'; dir->name[length++] = '*'; dir->name[length++] = '.'; dir->name[length++] = '*'; dir->name[length++] = 0; return dir; } --- 57,79 ---- break; } } dir->name[length++] = '/'; dir->name[length++] = '*'; dir->name[length++] = '.'; dir->name[length++] = '*'; dir->name[length++] = 0; + + /* If we're doing opendir of the root directory, we need to + fake out the . and .. entries, as some unix programs (like + mkisofs) expect them and fail if they don't exist */ + dir->need_fake_dot_dotdot = 0; + if (dir->name[1] == ':' && dir->name[2] == '/' && length == 7) + { + /* see if findfirst finds "." anyway */ + if (findfirst(dir->name, &dir->ff, FA_ARCH|FA_RDONLY|FA_DIREC) + || strcmp(dir->ff.ff_name, ".")) + dir->need_fake_dot_dotdot = 2; + } + return dir; }