aboutsummaryrefslogtreecommitdiffstats
path: root/extension/filefuncs.c
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2012-05-09 20:31:35 +0300
committerArnold D. Robbins <arnold@skeeve.com>2012-05-09 20:31:35 +0300
commita59319732d89feda419acab674ea580c95db7d4a (patch)
tree3d30595e8f50cb1b486c9f61f93a498834c22842 /extension/filefuncs.c
parent8ff0b4eaa7592280b5a55087c0326c6ef1f88db5 (diff)
parentc41908d0b02f7746a67ab7aa2e54058e5b66439a (diff)
downloadegawk-a59319732d89feda419acab674ea580c95db7d4a.tar.gz
egawk-a59319732d89feda419acab674ea580c95db7d4a.tar.bz2
egawk-a59319732d89feda419acab674ea580c95db7d4a.zip
Merge branch 'xgawk'
Diffstat (limited to 'extension/filefuncs.c')
-rw-r--r--extension/filefuncs.c189
1 files changed, 99 insertions, 90 deletions
diff --git a/extension/filefuncs.c b/extension/filefuncs.c
index 1a0a86ef..8e5e8daa 100644
--- a/extension/filefuncs.c
+++ b/extension/filefuncs.c
@@ -29,8 +29,6 @@
#include "awk.h"
-#include <sys/sysmacros.h>
-
int plugin_is_GPL_compatible;
/* do_chdir --- provide dynamically loaded chdir() builtin for gawk */
@@ -48,7 +46,7 @@ do_chdir(int nargs)
(void) force_string(newdir);
ret = chdir(newdir->stptr);
if (ret < 0)
- update_ERRNO();
+ update_ERRNO_int(errno);
return make_number((AWKNUM) ret);
}
@@ -157,15 +155,83 @@ format_mode(unsigned long fmode)
return outbuf;
}
+/* read_symlink -- read a symbolic link into an allocated buffer.
+ This is based on xreadlink; the basic problem is that lstat cannot be relied
+ upon to return the proper size for a symbolic link. This happens,
+ for example, on linux in the /proc filesystem, where the symbolic link
+ sizes are often 0. */
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+#ifndef SSIZE_MAX
+# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
+#endif
+
+#define MAXSIZE (SIZE_MAX < SSIZE_MAX ? SIZE_MAX : SSIZE_MAX)
+
+static char *
+read_symlink(const char *fname, size_t bufsize, ssize_t *linksize)
+{
+ if (bufsize)
+ bufsize += 2;
+ else
+ bufsize = BUFSIZ*2;
+ /* Make sure that bufsize >= 2 and within range */
+ if ((bufsize > MAXSIZE) || (bufsize < 2))
+ bufsize = MAXSIZE;
+ while (1) {
+ char *buf;
+
+ emalloc(buf, char *, bufsize, "read_symlink");
+ if ((*linksize = readlink(fname, buf, bufsize)) < 0) {
+ /* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink
+ returns -1 with errno == ERANGE if the buffer is
+ too small. */
+ if (errno != ERANGE) {
+ free(buf);
+ return NULL;
+ }
+ }
+ /* N.B. This test is safe because bufsize must be >= 2 */
+ else if ((size_t)*linksize <= bufsize-2) {
+ buf[*linksize] = '\0';
+ return buf;
+ }
+ free(buf);
+ if (bufsize <= MAXSIZE/2)
+ bufsize *= 2;
+ else if (bufsize < MAXSIZE)
+ bufsize = MAXSIZE;
+ else
+ return NULL;
+ }
+ return NULL;
+}
+
+/* array_set --- set an array element */
+
+static void
+array_set(NODE *array, const char *sub, NODE *value)
+{
+ NODE *tmp;
+ NODE **aptr;
+
+ tmp = make_string(sub, strlen(sub));
+ aptr = assoc_lookup(array, tmp);
+ unref(tmp);
+ unref(*aptr);
+ *aptr = value;
+}
+
/* do_stat --- provide a stat() function for gawk */
static NODE *
do_stat(int nargs)
{
- NODE *file, *array, *tmp;
+ NODE *file, *array;
struct stat sbuf;
int ret;
- NODE **aptr;
char *pmode; /* printable mode */
char *type = "unknown";
@@ -177,110 +243,55 @@ do_stat(int nargs)
array = get_array_argument(1, FALSE);
/* empty out the array */
- assoc_clear(array, NULL);
+ assoc_clear(array);
/* lstat the file, if error, set ERRNO and return */
(void) force_string(file);
ret = lstat(file->stptr, & sbuf);
if (ret < 0) {
- update_ERRNO();
+ update_ERRNO_int(errno);
return make_number((AWKNUM) ret);
}
/* fill in the array */
- aptr = assoc_lookup(array, tmp = make_string("name", 4));
- *aptr = dupnode(file);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("dev", 3));
- *aptr = make_number((AWKNUM) sbuf.st_dev);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("ino", 3));
- *aptr = make_number((AWKNUM) sbuf.st_ino);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("mode", 4));
- *aptr = make_number((AWKNUM) sbuf.st_mode);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("nlink", 5));
- *aptr = make_number((AWKNUM) sbuf.st_nlink);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("uid", 3));
- *aptr = make_number((AWKNUM) sbuf.st_uid);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("gid", 3));
- *aptr = make_number((AWKNUM) sbuf.st_gid);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("size", 4));
- *aptr = make_number((AWKNUM) sbuf.st_size);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("blocks", 6));
- *aptr = make_number((AWKNUM) sbuf.st_blocks);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("atime", 5));
- *aptr = make_number((AWKNUM) sbuf.st_atime);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("mtime", 5));
- *aptr = make_number((AWKNUM) sbuf.st_mtime);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("ctime", 5));
- *aptr = make_number((AWKNUM) sbuf.st_ctime);
- unref(tmp);
+ array_set(array, "name", dupnode(file));
+ array_set(array, "dev", make_number((AWKNUM) sbuf.st_dev));
+ array_set(array, "ino", make_number((AWKNUM) sbuf.st_ino));
+ array_set(array, "mode", make_number((AWKNUM) sbuf.st_mode));
+ array_set(array, "nlink", make_number((AWKNUM) sbuf.st_nlink));
+ array_set(array, "uid", make_number((AWKNUM) sbuf.st_uid));
+ array_set(array, "gid", make_number((AWKNUM) sbuf.st_gid));
+ array_set(array, "size", make_number((AWKNUM) sbuf.st_size));
+ array_set(array, "blocks", make_number((AWKNUM) sbuf.st_blocks));
+ array_set(array, "atime", make_number((AWKNUM) sbuf.st_atime));
+ array_set(array, "mtime", make_number((AWKNUM) sbuf.st_mtime));
+ array_set(array, "ctime", make_number((AWKNUM) sbuf.st_ctime));
/* for block and character devices, add rdev, major and minor numbers */
if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) {
- aptr = assoc_lookup(array, tmp = make_string("rdev", 4));
- *aptr = make_number((AWKNUM) sbuf.st_rdev);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("major", 5));
- *aptr = make_number((AWKNUM) major(sbuf.st_rdev));
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("minor", 5));
- *aptr = make_number((AWKNUM) minor(sbuf.st_rdev));
- unref(tmp);
+ array_set(array, "rdev", make_number((AWKNUM) sbuf.st_rdev));
+ array_set(array, "major", make_number((AWKNUM) major(sbuf.st_rdev)));
+ array_set(array, "minor", make_number((AWKNUM) minor(sbuf.st_rdev)));
}
#ifdef HAVE_ST_BLKSIZE
- aptr = assoc_lookup(array, tmp = make_string("blksize", 7));
- *aptr = make_number((AWKNUM) sbuf.st_blksize);
- unref(tmp);
+ array_set(array, "blksize", make_number((AWKNUM) sbuf.st_blksize));
#endif /* HAVE_ST_BLKSIZE */
- aptr = assoc_lookup(array, tmp = make_string("pmode", 5));
pmode = format_mode(sbuf.st_mode);
- *aptr = make_string(pmode, strlen(pmode));
- unref(tmp);
+ array_set(array, "pmode", make_string(pmode, strlen(pmode)));
/* for symbolic links, add a linkval field */
if (S_ISLNK(sbuf.st_mode)) {
char *buf;
- int linksize;
-
- emalloc(buf, char *, sbuf.st_size + 2, "do_stat");
- if (((linksize = readlink(file->stptr, buf,
- sbuf.st_size + 2)) >= 0) &&
- (linksize <= sbuf.st_size)) {
- /*
- * set the linkval field only if we are able to
- * retrieve the entire link value successfully.
- */
- buf[linksize] = '\0';
-
- aptr = assoc_lookup(array, tmp = make_string("linkval", 7));
- *aptr = make_str_node(buf, linksize, ALREADY_MALLOCED);
- unref(tmp);
- }
+ ssize_t linksize;
+
+ if ((buf = read_symlink(file->stptr, sbuf.st_size,
+ &linksize)) != NULL)
+ array_set(array, "linkval", make_str_node(buf, linksize, ALREADY_MALLOCED));
+ else
+ warning(_("unable to read symbolic link `%s'"),
+ file->stptr);
}
/* add a type field */
@@ -319,9 +330,7 @@ do_stat(int nargs)
#endif
}
- aptr = assoc_lookup(array, tmp = make_string("type", 4));
- *aptr = make_string(type, strlen(type));
- unref(tmp);
+ array_set(array, "type", make_string(type, strlen(type)));
return make_number((AWKNUM) ret);
}