aboutsummaryrefslogtreecommitdiffstats
path: root/extension/filefuncs.c
diff options
context:
space:
mode:
authorAndrew J. Schorr <aschorr@telemetry-investments.com>2012-04-07 16:30:50 -0400
committerAndrew J. Schorr <aschorr@telemetry-investments.com>2012-04-07 16:30:50 -0400
commitbc9ed3fd239984429613095e6cfc142092f036c4 (patch)
treea005a7ca9054b90af87d2a7b4d8b11a0607e80b8 /extension/filefuncs.c
parentaa23de50eb7c81a3e8f94769c5288aecfeb52b4c (diff)
downloadegawk-bc9ed3fd239984429613095e6cfc142092f036c4.tar.gz
egawk-bc9ed3fd239984429613095e6cfc142092f036c4.tar.bz2
egawk-bc9ed3fd239984429613095e6cfc142092f036c4.zip
Extension enhancements and tests.
Diffstat (limited to 'extension/filefuncs.c')
-rw-r--r--extension/filefuncs.c73
1 files changed, 60 insertions, 13 deletions
diff --git a/extension/filefuncs.c b/extension/filefuncs.c
index 63010c35..6d46c5e5 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 */
@@ -157,6 +155,60 @@ 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;
+}
+
/* do_stat --- provide a stat() function for gawk */
static NODE *
@@ -265,22 +317,17 @@ do_stat(int nargs)
/* 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';
+ ssize_t linksize;
+ if ((buf = read_symlink(file->stptr, sbuf.st_size,
+ &linksize)) != NULL) {
aptr = assoc_lookup(array, tmp = make_string("linkval", 7));
*aptr = make_str_node(buf, linksize, ALREADY_MALLOCED);
unref(tmp);
}
+ else
+ warning(_("unable to read symbolic link `%s'"),
+ file->stptr);
}
/* add a type field */