bug-gawk
[Top][All Lists]
Advanced

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

readdir on Windows, again


From: Eli Zaretskii
Subject: readdir on Windows, again
Date: Mon, 11 Dec 2023 21:52:27 +0200

Hi,

A user informed me privately that the following script fails on
MS-Windows to read directories when their names come from the script
(as opposed to being specified on the command line):

  @load "readdir"

  BEGIN {
    Directory = ARGV[1]

    n = (getline < Directory)
    printf("File-based getline(%s) %s: 
%d\n",Directory,((n>0)?"succeeded":"failed"),n)

    n = getline
    printf("Command line getline(%s) %s: 
%d\n",Directory,((n>0)?"succeeded":"failed"),n)

    exit
  }

The first getline fails, the second succeeds.  On GNU/Linux, both
succeed.

It turns out a change I posted during 5.2.1 development didn't make it
into the current sources.  As result, in the above scenario,
find_input_parser was not being called because redirect_string
expected 'open' to succeed on directories.

The patches to fix this are below.  Any objections to installing them
in Git?

--- io.c~0      2023-11-01 10:31:57.000000000 +0200
+++ io.c        2023-12-11 20:54:49.219500000 +0200
@@ -797,6 +797,7 @@ redirect_string(const char *str, size_t 
        static struct redirect *save_rp = NULL; /* hold onto rp that should
                                                 * be freed for reuse
                                                 */
+       int save_errno;
 
        if (do_sandbox)
                fatal(_("redirection not allowed in sandbox mode"));
@@ -979,15 +980,20 @@ redirect_string(const char *str, size_t 
                case redirect_input:
                        direction = "from";
                        fd = (extfd >= 0) ? extfd : devopen(str, binmode("r"));
-                       if (fd == INVALID_HANDLE && errno == EISDIR) {
-                               *errflg = EISDIR;
-                               /* do not free rp, saving it for reuse (save_rp 
= rp) */
-                               return NULL;
-                       }
+                       save_errno = errno;
+                       /* don't fail before letting registered
+                          parsers a chance to take control */
                        rp->iop = iop_alloc(fd, str, errno);
                        find_input_parser(rp->iop);
                        iop_finish(rp->iop);
                        if (! rp->iop->valid) {
+                               if (fd == INVALID_HANDLE && save_errno == 
EISDIR) {
+                                       *errflg = EISDIR;
+                                       iop_close(rp->iop);
+                                       rp->iop = NULL;
+                                       /* do not free rp, saving it for reuse 
(save_rp = rp) */
+                                       return NULL;
+                               }
                                if (! do_traditional && rp->iop->errcode != 0)
                                        update_ERRNO_int(rp->iop->errcode);
                                iop_close(rp->iop);

--- pc/gawkmisc.pc~0    2023-10-22 17:19:50.000000000 +0300
+++ pc/gawkmisc.pc      2023-12-11 21:38:34.594500000 +0200
@@ -106,9 +106,6 @@ optimal_bufsize(fd, stb)
 int fd;
 struct stat *stb;
 {
-       /* force all members to zero in case OS doesn't use all of them. */
-       memset(stb, '\0', sizeof(struct stat));
-
        /*
         * DOS doesn't have the file system block size in the
         * stat structure. So we have to make some sort of reasonable
@@ -117,6 +114,12 @@ struct stat *stb;
         */
 #define        DEFBLKSIZE      BUFSIZ
 
+       if (S_ISDIR(stb->st_mode))
+               return DEFBLKSIZE;
+
+       /* force all members to zero in case OS doesn't use all of them. */
+       memset(stb, '\0', sizeof(struct stat));
+
        if (fstat(fd, stb) == -1)
                fatal("can't stat fd %d (%s)", fd, strerror(errno));
        if (S_ISREG(stb->st_mode)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]