diff options
Diffstat (limited to 'extension/filefuncs.c')
-rw-r--r-- | extension/filefuncs.c | 221 |
1 files changed, 118 insertions, 103 deletions
diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 01f3fce2..74a086a9 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -7,7 +7,8 @@ */ /* - * Copyright (C) 2001, 2004, 2005, 2010, 2011 the Free Software Foundation, Inc. + * Copyright (C) 2001, 2004, 2005, 2010, 2011, 2012 + * the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Programming Language. @@ -27,28 +28,40 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "awk.h" +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include "config.h" +#include "gawkapi.h" + +static const gawk_api_t *api; /* for convenience macros to work */ +static awk_ext_id_t *ext_id; int plugin_is_GPL_compatible; /* do_chdir --- provide dynamically loaded chdir() builtin for gawk */ -static NODE * -do_chdir(int nargs) +static awk_value_t * +do_chdir(int nargs, awk_value_t *result) { - NODE *newdir; + awk_value_t newdir; int ret = -1; if (do_lint && nargs != 1) - lintwarn("chdir: called with incorrect number of arguments"); + lintwarn(ext_id, "chdir: called with incorrect number of arguments"); - newdir = get_scalar_argument(0, false); - (void) force_string(newdir); - ret = chdir(newdir->stptr); - if (ret < 0) - update_ERRNO_int(errno); + if (get_curfunc_param(0, AWK_STRING, &newdir) != NULL) { + ret = chdir(newdir.str_value.str); + if (ret < 0) + update_ERRNO_int(errno); + } - return make_number((AWKNUM) ret); + return make_number(ret, result); } /* format_mode --- turn a stat mode field into something readable */ @@ -57,7 +70,15 @@ static char * format_mode(unsigned long fmode) { static char outbuf[12]; - int i; + static struct mode_map { + int mask; + int rep; + } map[] = { + { S_IRUSR, 'r' }, { S_IWUSR, 'w' }, { S_IXUSR, 'x' }, + { S_IRGRP, 'r' }, { S_IWGRP, 'w' }, { S_IXGRP, 'x' }, + { S_IROTH, 'r' }, { S_IWOTH, 'w' }, { S_IXOTH, 'x' }, + }; + int i, j, k; strcpy(outbuf, "----------"); /* first, get the file type */ @@ -97,39 +118,16 @@ format_mode(unsigned long fmode) #endif } - i++; - if ((fmode & S_IRUSR) != 0) - outbuf[i] = 'r'; - i++; - if ((fmode & S_IWUSR) != 0) - outbuf[i] = 'w'; - i++; - if ((fmode & S_IXUSR) != 0) - outbuf[i] = 'x'; - i++; - - if ((fmode & S_IRGRP) != 0) - outbuf[i] = 'r'; - i++; - if ((fmode & S_IWGRP) != 0) - outbuf[i] = 'w'; - i++; - if ((fmode & S_IXGRP) != 0) - outbuf[i] = 'x'; - i++; + for (j = 0, k = sizeof(map)/sizeof(map[0]); j < k; j++) { + i++; + if ((fmode & map[j].mask) != 0) + outbuf[i] = map[j].rep; + } - if ((fmode & S_IROTH) != 0) - outbuf[i] = 'r'; - i++; - if ((fmode & S_IWOTH) != 0) - outbuf[i] = 'w'; i++; - if ((fmode & S_IXOTH) != 0) - outbuf[i] = 'x'; - i++; - outbuf[i] = '\0'; + /* setuid bit */ if ((fmode & S_ISUID) != 0) { if (outbuf[3] == 'x') outbuf[3] = 's'; @@ -145,6 +143,7 @@ format_mode(unsigned long fmode) outbuf[6] = 'l'; } + /* the so-called "sticky" bit */ if ((fmode & S_ISVTX) != 0) { if (outbuf[9] == 'x') outbuf[9] = 't'; @@ -158,7 +157,7 @@ format_mode(unsigned long fmode) /* 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 + for example, on GNU/Linux in the /proc filesystem, where the symbolic link sizes are often 0. */ #ifndef SIZE_MAX @@ -176,10 +175,12 @@ read_symlink(const char *fname, size_t bufsize, ssize_t *linksize) if (bufsize) bufsize += 2; else - bufsize = BUFSIZ*2; + bufsize = BUFSIZ * 2; + /* Make sure that bufsize >= 2 and within range */ - if ((bufsize > MAXSIZE) || (bufsize < 2)) + if (bufsize > MAXSIZE || bufsize < 2) bufsize = MAXSIZE; + while (1) { char *buf; @@ -212,93 +213,106 @@ read_symlink(const char *fname, size_t bufsize, ssize_t *linksize) /* array_set --- set an array element */ static void -array_set(NODE *array, const char *sub, NODE *value) +array_set(awk_array_t array, const char *sub, awk_value_t *value) +{ + awk_element_t element; + awk_value_t tmp; + + memset(& element, 0, sizeof(element)); + + element.index = dup_string(sub, strlen(sub), & tmp)->str_value; + element.value = *value; + + set_array_element(array, & element); +} + +static void +array_set_numeric(awk_array_t array, const char *sub, double num) { - NODE *tmp; - NODE **aptr; - - tmp = make_string(sub, strlen(sub)); - aptr = assoc_lookup(array, tmp); - unref(tmp); - /* - * Note: since we initialized with assoc_clear, we know that aptr - * has been initialized with Nnull_string. Thus, the call to - * unref(*aptr) is not strictly necessary. However, I think it is - * generally more correct to call unref to maintain the proper - * reference count. - */ - unref(*aptr); - *aptr = value; + awk_value_t tmp; + return array_set(array, sub, make_number(num, & tmp)); } /* do_stat --- provide a stat() function for gawk */ -static NODE * -do_stat(int nargs) +static awk_value_t * +do_stat(int nargs, awk_value_t *result) { - NODE *file, *array; + awk_value_t file_param, array_param; + char *name; + awk_array_t array; struct stat sbuf; int ret; char *pmode; /* printable mode */ char *type = "unknown"; + awk_value_t tmp; - if (do_lint && nargs > 2) - lintwarn("stat: called with too many arguments"); + if (do_lint && nargs != 2) { + lintwarn(ext_id, "stat: called with wrong number of arguments"); + /* XXX previous version returned 0; why? */ + return make_number(-1, result); + } /* file is first arg, array to hold results is second */ - file = get_scalar_argument(0, false); - array = get_array_argument(1, false); + if (get_curfunc_param(0, AWK_STRING, &file_param) == NULL || + get_curfunc_param(1, AWK_ARRAY, &array_param) == NULL) { + warning(ext_id, "stat: bad parameters"); + /* XXX previous version returned 0; why? */ + return make_number(-1, result); + } + + name = file_param.str_value.str; + array = array_param.array_cookie; /* empty out the array */ - assoc_clear(array); + clear_array(array); /* lstat the file, if error, set ERRNO and return */ - (void) force_string(file); - ret = lstat(file->stptr, & sbuf); + ret = lstat(name, & sbuf); if (ret < 0) { update_ERRNO_int(errno); - return make_number((AWKNUM) ret); + /* XXX previous version returned 0; why? */ + return make_number(-1, result); } /* fill in the array */ - 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)); + array_set(array, "name", make_string(name, file_param.str_value.len, &tmp)); + array_set_numeric(array, "dev", sbuf.st_dev); + array_set_numeric(array, "ino", sbuf.st_ino); + array_set_numeric(array, "mode", sbuf.st_mode); + array_set_numeric(array, "nlink", sbuf.st_nlink); + array_set_numeric(array, "uid", sbuf.st_uid); + array_set_numeric(array, "gid", sbuf.st_gid); + array_set_numeric(array, "size", sbuf.st_size); + array_set_numeric(array, "blocks", sbuf.st_blocks); + array_set_numeric(array, "atime", sbuf.st_atime); + array_set_numeric(array, "mtime", sbuf.st_mtime); + array_set_numeric(array, "ctime", 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)) { - 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))); + array_set_numeric(array, "rdev", sbuf.st_rdev); + array_set_numeric(array, "major", major(sbuf.st_rdev)); + array_set_numeric(array, "minor", minor(sbuf.st_rdev)); } #ifdef HAVE_ST_BLKSIZE - array_set(array, "blksize", make_number((AWKNUM) sbuf.st_blksize)); + array_set_numeric(array, "blksize", sbuf.st_blksize); #endif /* HAVE_ST_BLKSIZE */ pmode = format_mode(sbuf.st_mode); - array_set(array, "pmode", make_string(pmode, strlen(pmode))); + array_set(array, "pmode", make_string(pmode, strlen(pmode), &tmp)); /* for symbolic links, add a linkval field */ if (S_ISLNK(sbuf.st_mode)) { char *buf; ssize_t linksize; - if ((buf = read_symlink(file->stptr, sbuf.st_size, + if ((buf = read_symlink(name, sbuf.st_size, &linksize)) != NULL) - array_set(array, "linkval", make_str_node(buf, linksize, ALREADY_MALLOCED)); + array_set(array, "linkval", make_string(buf, linksize, &tmp)); else - warning(_("unable to read symbolic link `%s'"), - file->stptr); + warning(ext_id, "unable to read symbolic link `%s'", name); } /* add a type field */ @@ -337,18 +351,19 @@ do_stat(int nargs) #endif } - array_set(array, "type", make_string(type, strlen(type))); + array_set(array, "type", make_string(type, strlen(type), &tmp)); - return make_number((AWKNUM) ret); + ret = 1; /* success */ + + return make_number(ret, result); } -/* dlload --- load new builtins in this library */ +static awk_ext_func_t func_table[] = { + { "chdir", do_chdir, 1 }, + { "stat", do_stat, 2 }, +}; -NODE * -dlload(NODE *tree, void *dl) -{ - make_builtin("chdir", do_chdir, 1); - make_builtin("stat", do_stat, 2); - return make_number((AWKNUM) 0); -} +/* define the dl_load function using the boilerplate macro */ + +dl_load_func(func_table, filefuncs, "") |