aboutsummaryrefslogtreecommitdiffstats
path: root/extension/readdir.c
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2013-05-14 16:26:29 +0300
committerEli Zaretskii <eliz@gnu.org>2013-05-14 16:26:29 +0300
commit242f84cd211a13c4056d228aaa9bc1f57aa21763 (patch)
tree8be4635902df1dde1c21e6ca9cb457a2860c73ff /extension/readdir.c
parentc96323b5e32f54295556809833d2d6a44daa75d0 (diff)
downloadegawk-242f84cd211a13c4056d228aaa9bc1f57aa21763.tar.gz
egawk-242f84cd211a13c4056d228aaa9bc1f57aa21763.tar.bz2
egawk-242f84cd211a13c4056d228aaa9bc1f57aa21763.zip
Fix building, installing, and testing extensions on MS-Windows.
test/Makefile.in (mpfr-tests, shlib-tests): Add a blank character between ' and /FOO/ in Gawk command lines, for the benefit of testing under MSYS Bash. test/filefuncs.awk (BEGIN): Call 'stat' on gawkapi.o, not on gawk, which does not exist on systems that produce gawk.exe. README_D/README.pc: Update the pc build and test instructions. pc/Makefile.tst (AWK): Set AWKLIBPATH so extensions could be found. (LS): New variable. (check): Add back shlib-tests and shlib-msg-end. (readdir): Add a warning regarding inode reporting by ls.exe. (fts, fork, fork2): Add message about expected failure on MinGW. pc/Makefile (install): Install the extensions. (install-strip): Likewise. pc/Makefile.ext: New file. io.c (devopen) [__EMX__ || __MINGW32__]: Produce EISDIR on MinGW when an attempt to open() a directory fails. (two_way_open) [__EMX__ || __MINGW32__]: When trying to open() a directory fails with EISDIR, assign FAKE_FD_VALUE to the file descriptor and attributes of a directory to its mode bits. This is needed to support the readdir extension. gawkapi.h (FAKE_FD_VALUE): New macro, used in io.h and in extension/gawkdirfd.h. extension/rwarray.c [__MINGW32__]: Include winsock2.h instead of arpa/inet.h. extension/readdir.c [__MINGW32__]: Include windows.h. Include gawkapi.h before gawkdirfd.h, since the former defines FAKE_FD_VALUE needed by the latter. (ftype): Accept an additional argument, the directory that is being read. Callers changed. [!DT_BLK]: Produce the file's type by calling 'stat' on it, if the dirent structure doesn't provide that. (get_inode): New function, to produce inode values on MS-Windows. (dir_get_record): Use it. extension/inplace.c (chown, link) [__MINGW32__]: Redirect to existing library functions. (mkstemp) [__MINGW32__]: New function, for MinGW, which doesn't have it in its library. (do_inplace_end) [__MINGW32__]: Remove the old file before renaming the new, since 'rename' on Windows cannot overwrite existing files. extension/gawkdirfd.h (ENOTSUP): Define to ENOSYS if not already defined. (DIR_TO_FD): If not defined yet, define to FAKE_FD_VALUE. extension/filefuncs.c (get_inode) [_WIN32]: New function, produces the file index used on Windows as its inode. (fill_stat_array) [_WIN32]: Use it.
Diffstat (limited to 'extension/readdir.c')
-rw-r--r--extension/readdir.c86
1 files changed, 76 insertions, 10 deletions
diff --git a/extension/readdir.c b/extension/readdir.c
index 5ca4dc63..9d53ad9a 100644
--- a/extension/readdir.c
+++ b/extension/readdir.c
@@ -50,10 +50,14 @@
#error Cannot compile the dirent extension on this system!
#endif
-#include "gawkdirfd.h"
+#ifdef __MINGW32__
+#include <windows.h>
+#endif
#include "gawkapi.h"
+#include "gawkdirfd.h"
+
#include "gettext.h"
#define _(msgid) gettext(msgid)
#define N_(msgid) msgid
@@ -77,7 +81,7 @@ typedef struct open_directory {
/* ftype --- return type of file as a single character string */
static const char *
-ftype(struct dirent *entry)
+ftype(struct dirent *entry, const char *dirname)
{
#ifdef DT_BLK
switch (entry->d_type) {
@@ -92,10 +96,67 @@ ftype(struct dirent *entry)
case DT_UNKNOWN: return "u";
}
#else
+ char fname[PATH_MAX];
+ struct stat sbuf;
+
+ strcpy(fname, dirname);
+ strcat(fname, "/");
+ strcat(fname, entry->d_name);
+ if (stat(fname, &sbuf) == 0) {
+ if (S_ISBLK(sbuf.st_mode))
+ return "b";
+ if (S_ISCHR(sbuf.st_mode))
+ return "c";
+ if (S_ISDIR(sbuf.st_mode))
+ return "d";
+ if (S_ISFIFO(sbuf.st_mode))
+ return "p";
+ if (S_ISREG(sbuf.st_mode))
+ return "f";
+#ifdef S_ISLNK
+ if (S_ISLNK(sbuf.st_mode))
+ return "l";
+#endif
+#ifdef S_ISSOCK
+ if (S_ISSOCK(sbuf.st_mode))
+ return "s";
+#endif
+ }
return "u";
#endif
}
+/* get_inode --- get the inode of a file */
+#ifdef ZOS_USS
+static long
+#else
+static long long
+#endif
+get_inode(struct dirent *entry, const char *dirname)
+{
+#ifdef __MINGW32__
+ char fname[PATH_MAX];
+ HANDLE fh;
+ BY_HANDLE_FILE_INFORMATION info;
+
+ sprintf(fname, "%s\\%s", dirname, entry->d_name);
+ fh = CreateFile(fname, 0, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (fh == INVALID_HANDLE_VALUE)
+ return 0;
+ if (GetFileInformationByHandle(fh, &info)) {
+ long long inode = info.nFileIndexHigh;
+
+ inode <<= 32;
+ inode += info.nFileIndexLow;
+ return inode;
+ }
+ return 0;
+#else
+ return entry->d_ino;
+#endif
+}
+
/* dir_get_record --- get one record at a time out of a directory */
static int
@@ -107,6 +168,11 @@ dir_get_record(char **out, awk_input_buf_t *iobuf, int *errcode,
int len;
open_directory_t *the_dir;
const char *ftstr;
+#ifdef ZOS_USS
+ unsigned long ino;
+#else
+ unsigned long long ino;
+#endif
/*
* The caller sets *errcode to 0, so we should set it only if an
@@ -129,17 +195,17 @@ dir_get_record(char **out, awk_input_buf_t *iobuf, int *errcode,
return EOF;
}
-#ifdef ZOS_USS
- len = sprintf(the_dir->buf, "%lu/%s",
- (unsigned long) dirent->d_ino,
- dirent->d_name);
+ ino = get_inode (dirent, iobuf->name);
+
+#if defined(ZOS_USS)
+ len = sprintf(the_dir->buf, "%lu/%s", ino, dirent->d_name);
+#elif __MINGW32__
+ len = sprintf(the_dir->buf, "%I64u/%s", ino, dirent->d_name);
#else
- len = sprintf(the_dir->buf, "%llu/%s",
- (unsigned long long) dirent->d_ino,
- dirent->d_name);
+ len = sprintf(the_dir->buf, "%llu/%s", ino, dirent->d_name);
#endif
- ftstr = ftype(dirent);
+ ftstr = ftype(dirent, iobuf->name);
len += sprintf(the_dir->buf + len, "/%s", ftstr);
*out = the_dir->buf;