Blame extension/filefuncs.c

Packit Service f629e6
/*
Packit Service f629e6
 * filefuncs.c - Builtin functions that provide initial minimal iterface
Packit Service f629e6
 *		 to the file system.
Packit Service f629e6
 *
Packit Service f629e6
 * Arnold Robbins, update for 3.1, Mon Nov 23 12:53:39 EST 1998
Packit Service f629e6
 * Arnold Robbins and John Haque, update for 3.1.4, applied Mon Jun 14 13:55:30 IDT 2004
Packit Service f629e6
 * Arnold Robbins and Andrew Schorr, revised for new extension API, May 2012.
Packit Service f629e6
 * Arnold Robbins, add fts(), August 2012
Packit Service f629e6
 * Arnold Robbins, add statvfs(), November 2015
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Copyright (C) 2001, 2004, 2005, 2010-2017
Packit Service f629e6
 * the Free Software Foundation, Inc.
Packit Service f629e6
 *
Packit Service f629e6
 * This file is part of GAWK, the GNU implementation of the
Packit Service f629e6
 * AWK Programming Language.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is free software; you can redistribute it and/or modify
Packit Service f629e6
 * it under the terms of the GNU General Public License as published by
Packit Service f629e6
 * the Free Software Foundation; either version 3 of the License, or
Packit Service f629e6
 * (at your option) any later version.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is distributed in the hope that it will be useful,
Packit Service f629e6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f629e6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service f629e6
 * GNU General Public License for more details.
Packit Service f629e6
 *
Packit Service f629e6
 * You should have received a copy of the GNU General Public License
Packit Service f629e6
 * along with this program; if not, write to the Free Software
Packit Service f629e6
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_CONFIG_H
Packit Service f629e6
#include <config.h>
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#define _BSD_SOURCE
Packit Service f629e6
Packit Service f629e6
#ifdef __VMS
Packit Service f629e6
#if (__CRTL_VER >= 70200000) && !defined (__VAX)
Packit Service f629e6
#define _LARGEFILE 1
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#ifndef __VAX
Packit Service f629e6
#ifdef __CRTL_VER
Packit Service f629e6
#if __CRTL_VER >= 80200000
Packit Service f629e6
#define _USE_STD_STAT 1
Packit Service f629e6
#endif
Packit Service f629e6
#endif
Packit Service f629e6
#endif
Packit Service f629e6
#define _POSIX_C_SOURCE 1
Packit Service f629e6
#define _XOPEN_SOURCE 1
Packit Service f629e6
#include <stat.h>
Packit Service f629e6
#ifndef S_ISVTX
Packit Service f629e6
#define S_ISVTX (0)
Packit Service f629e6
#endif
Packit Service f629e6
#ifndef major
Packit Service f629e6
#define major(s) (s)
Packit Service f629e6
#endif
Packit Service f629e6
#ifndef minor
Packit Service f629e6
#define minor(s) (0)
Packit Service f629e6
#endif
Packit Service f629e6
#include <unixlib.h>
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
#include <stdio.h>
Packit Service f629e6
#include <assert.h>
Packit Service f629e6
#include <errno.h>
Packit Service f629e6
#include <stdlib.h>
Packit Service f629e6
#include <string.h>
Packit Service f629e6
#include <unistd.h>
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_SYS_PARAM_H
Packit Service f629e6
#include <sys/param.h>
Packit Service f629e6
#endif /* HAVE_SYS_PARAM_H */
Packit Service f629e6
Packit Service f629e6
#if HAVE_SYS_SYSMACROS_H
Packit Service f629e6
#include <sys/sysmacros.h>
Packit Service f629e6
#elif HAVE_SYS_MKDEV_H
Packit Service f629e6
#include <sys/mkdev.h>
Packit Service f629e6
#endif /* HAVE_SYS_MKDEV_H */
Packit Service f629e6
Packit Service f629e6
#include <sys/types.h>
Packit Service f629e6
Packit Service f629e6
#include <sys/stat.h>
Packit Service f629e6
Packit Service f629e6
#if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS)
Packit Service f629e6
#include <sys/statvfs.h>
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#include "gawkapi.h"
Packit Service f629e6
Packit Service f629e6
#include "gettext.h"
Packit Service f629e6
#define _(msgid)  gettext(msgid)
Packit Service f629e6
#define N_(msgid) msgid
Packit Service f629e6
Packit Service f629e6
#include "gawkfts.h"
Packit Service f629e6
#include "stack.h"
Packit Service f629e6
Packit Service f629e6
#ifndef S_IFLNK
Packit Service f629e6
#define lstat stat
Packit Service f629e6
#define S_ISLNK(s) 0
Packit Service f629e6
#define readlink(f,b,bs) (-1)
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#ifdef __MINGW32__
Packit Service f629e6
#define S_IRGRP S_IRUSR
Packit Service f629e6
#define S_IWGRP S_IWUSR
Packit Service f629e6
#define S_IXGRP S_IXUSR
Packit Service f629e6
#define S_IROTH S_IRUSR
Packit Service f629e6
#define S_IWOTH S_IWUSR
Packit Service f629e6
#define S_IXOTH S_IXUSR
Packit Service f629e6
#define S_ISUID 0
Packit Service f629e6
#define S_ISGID 0
Packit Service f629e6
#define S_ISVTX 0
Packit Service f629e6
#define major(s) (s)
Packit Service f629e6
#define minor(s) (0)
Packit Service f629e6
Packit Service f629e6
#define WIN32_LEAN_AND_MEAN
Packit Service f629e6
#include <windows.h>
Packit Service f629e6
Packit Service f629e6
/* get_inode --- get the inode of a file */
Packit Service f629e6
static long long
Packit Service f629e6
get_inode(const char *fname)
Packit Service f629e6
{
Packit Service f629e6
	HANDLE fh;
Packit Service f629e6
	BY_HANDLE_FILE_INFORMATION info;
Packit Service f629e6
Packit Service f629e6
	fh = CreateFile(fname, 0, 0, NULL, OPEN_EXISTING,
Packit Service f629e6
			FILE_FLAG_BACKUP_SEMANTICS, NULL);
Packit Service f629e6
	if (fh == INVALID_HANDLE_VALUE)
Packit Service f629e6
		return 0;
Packit Service f629e6
	if (GetFileInformationByHandle(fh, &info)) {
Packit Service f629e6
		long long inode = info.nFileIndexHigh;
Packit Service f629e6
Packit Service f629e6
		inode <<= 32;
Packit Service f629e6
		inode += info.nFileIndexLow;
Packit Service f629e6
		return inode;
Packit Service f629e6
	}
Packit Service f629e6
	return 0;
Packit Service f629e6
}
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
static const gawk_api_t *api;	/* for convenience macros to work */
Packit Service f629e6
static awk_ext_id_t ext_id;
Packit Service f629e6
static awk_bool_t init_filefuncs(void);
Packit Service f629e6
static awk_bool_t (*init_func)(void) = init_filefuncs;
Packit Service f629e6
static const char *ext_version = "filefuncs extension: version 1.0";
Packit Service f629e6
Packit Service f629e6
int plugin_is_GPL_compatible;
Packit Service f629e6
Packit Service f629e6
/*  do_chdir --- provide dynamically loaded chdir() function for gawk */
Packit Service f629e6
Packit Service f629e6
static awk_value_t *
Packit Service f629e6
do_chdir(int nargs, awk_value_t *result, struct awk_ext_func *unused)
Packit Service f629e6
{
Packit Service f629e6
	awk_value_t newdir;
Packit Service f629e6
	int ret = -1;
Packit Service f629e6
Packit Service f629e6
	assert(result != NULL);
Packit Service f629e6
Packit Service f629e6
	if (get_argument(0, AWK_STRING, & newdir)) {
Packit Service f629e6
		ret = chdir(newdir.str_value.str);
Packit Service f629e6
		if (ret < 0)
Packit Service f629e6
			update_ERRNO_int(errno);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return make_number(ret, result);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* format_mode --- turn a stat mode field into something readable */
Packit Service f629e6
Packit Service f629e6
static char *
Packit Service f629e6
format_mode(unsigned long fmode)
Packit Service f629e6
{
Packit Service f629e6
	static char outbuf[12];
Packit Service f629e6
	static struct ftype_map {
Packit Service f629e6
		unsigned int mask;
Packit Service f629e6
		int charval;
Packit Service f629e6
	} ftype_map[] = {
Packit Service f629e6
		{ S_IFREG, '-' },	/* redundant */
Packit Service f629e6
		{ S_IFBLK, 'b' },
Packit Service f629e6
		{ S_IFCHR, 'c' },
Packit Service f629e6
		{ S_IFDIR, 'd' },
Packit Service f629e6
#ifdef S_IFSOCK
Packit Service f629e6
		{ S_IFSOCK, 's' },
Packit Service f629e6
#endif
Packit Service f629e6
#ifdef S_IFIFO
Packit Service f629e6
		{ S_IFIFO, 'p' },
Packit Service f629e6
#endif
Packit Service f629e6
#ifdef S_IFLNK
Packit Service f629e6
		{ S_IFLNK, 'l' },
Packit Service f629e6
#endif
Packit Service f629e6
#ifdef S_IFDOOR	/* Solaris weirdness */
Packit Service f629e6
		{ S_IFDOOR, 'D' },
Packit Service f629e6
#endif /* S_IFDOOR */
Packit Service f629e6
	};
Packit Service f629e6
	static struct mode_map {
Packit Service f629e6
		unsigned int mask;
Packit Service f629e6
		int rep;
Packit Service f629e6
	} map[] = {
Packit Service f629e6
		{ S_IRUSR, 'r' }, { S_IWUSR, 'w' }, { S_IXUSR, 'x' },
Packit Service f629e6
		{ S_IRGRP, 'r' }, { S_IWGRP, 'w' }, { S_IXGRP, 'x' },
Packit Service f629e6
		{ S_IROTH, 'r' }, { S_IWOTH, 'w' }, { S_IXOTH, 'x' },
Packit Service f629e6
	};
Packit Service f629e6
	static struct setuid_map {
Packit Service f629e6
		unsigned int mask;
Packit Service f629e6
		int index;
Packit Service f629e6
		int small_rep;
Packit Service f629e6
		int big_rep;
Packit Service f629e6
	} setuid_map[] = {
Packit Service f629e6
		{ S_ISUID, 3, 's', 'S' }, /* setuid bit */
Packit Service f629e6
		{ S_ISGID, 6, 's', 'l' }, /* setgid without execute == locking */
Packit Service f629e6
		{ S_ISVTX, 9, 't', 'T' }, /* the so-called "sticky" bit */
Packit Service f629e6
	};
Packit Service f629e6
	int i, j, k;
Packit Service f629e6
Packit Service f629e6
	strcpy(outbuf, "----------");
Packit Service f629e6
Packit Service f629e6
	/* first, get the file type */
Packit Service f629e6
	i = 0;
Packit Service f629e6
	for (j = 0, k = sizeof(ftype_map)/sizeof(ftype_map[0]); j < k; j++) {
Packit Service f629e6
		if ((fmode & S_IFMT) == ftype_map[j].mask) {
Packit Service f629e6
			outbuf[i] = ftype_map[j].charval;
Packit Service f629e6
			break;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* now the permissions */
Packit Service f629e6
	for (j = 0, k = sizeof(map)/sizeof(map[0]); j < k; j++) {
Packit Service f629e6
		i++;
Packit Service f629e6
		if ((fmode & map[j].mask) != 0)
Packit Service f629e6
			outbuf[i] = map[j].rep;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	i++;
Packit Service f629e6
	outbuf[i] = '\0';
Packit Service f629e6
Packit Service f629e6
	/* tweaks for the setuid / setgid / sticky bits */
Packit Service f629e6
	for (j = 0, k = sizeof(setuid_map)/sizeof(setuid_map[0]); j < k; j++) {
Packit Service f629e6
		if (fmode & setuid_map[j].mask) {
Packit Service f629e6
			if (outbuf[setuid_map[j].index] == 'x')
Packit Service f629e6
				outbuf[setuid_map[j].index] = setuid_map[j].small_rep;
Packit Service f629e6
			else
Packit Service f629e6
				outbuf[setuid_map[j].index] = setuid_map[j].big_rep;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return outbuf;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* read_symlink --- read a symbolic link into an allocated buffer.
Packit Service f629e6
   This is based on xreadlink; the basic problem is that lstat cannot be relied
Packit Service f629e6
   upon to return the proper size for a symbolic link.  This happens,
Packit Service f629e6
   for example, on GNU/Linux in the /proc filesystem, where the symbolic link
Packit Service f629e6
   sizes are often 0. */
Packit Service f629e6
Packit Service f629e6
#ifndef SIZE_MAX
Packit Service f629e6
# define SIZE_MAX ((size_t) -1)
Packit Service f629e6
#endif
Packit Service f629e6
#ifndef SSIZE_MAX
Packit Service f629e6
# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#define MAXSIZE (SIZE_MAX < SSIZE_MAX ? SIZE_MAX : SSIZE_MAX)
Packit Service f629e6
Packit Service f629e6
static char *
Packit Service f629e6
read_symlink(const char *fname, size_t bufsize, ssize_t *linksize)
Packit Service f629e6
{
Packit Service f629e6
	if (bufsize)
Packit Service f629e6
		bufsize += 2;
Packit Service f629e6
	else
Packit Service f629e6
		bufsize = BUFSIZ * 2;
Packit Service f629e6
Packit Service f629e6
	/* Make sure that bufsize >= 2 and within range */
Packit Service f629e6
	if (bufsize > MAXSIZE || bufsize < 2)
Packit Service f629e6
		bufsize = MAXSIZE;
Packit Service f629e6
Packit Service f629e6
	while (1) {
Packit Service f629e6
		char *buf;
Packit Service f629e6
Packit Service f629e6
		emalloc(buf, char *, bufsize, "read_symlink");
Packit Service f629e6
		if ((*linksize = readlink(fname, buf, bufsize)) < 0) {
Packit Service f629e6
			/* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink
Packit Service f629e6
			   returns -1 with errno == ERANGE if the buffer is
Packit Service f629e6
			   too small.  */
Packit Service f629e6
			if (errno != ERANGE) {
Packit Service f629e6
				gawk_free(buf);
Packit Service f629e6
				return NULL;
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
		/* N.B. This test is safe because bufsize must be >= 2 */
Packit Service f629e6
		else if ((size_t)*linksize <= bufsize-2) {
Packit Service f629e6
			buf[*linksize] = '\0';
Packit Service f629e6
			return buf;
Packit Service f629e6
		}
Packit Service f629e6
		gawk_free(buf);
Packit Service f629e6
		if (bufsize <= MAXSIZE/2)
Packit Service f629e6
			bufsize *= 2;
Packit Service f629e6
		else if (bufsize < MAXSIZE)
Packit Service f629e6
			bufsize = MAXSIZE;
Packit Service f629e6
		else
Packit Service f629e6
			return NULL;
Packit Service f629e6
	}
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* device_blocksize --- try to figure out units of st_blocks */
Packit Service f629e6
Packit Service f629e6
static int
Packit Service f629e6
device_blocksize()
Packit Service f629e6
{
Packit Service f629e6
	/* some of this derived from GNULIB stat-size.h */
Packit Service f629e6
#if defined(DEV_BSIZE)
Packit Service f629e6
	/* <sys/param.h>, most systems */
Packit Service f629e6
	return DEV_BSIZE;
Packit Service f629e6
#elif defined(S_BLKSIZE)
Packit Service f629e6
	/* <sys/stat.h>, BSD systems */
Packit Service f629e6
	return S_BLKSIZE;
Packit Service f629e6
#elif defined hpux || defined __hpux__ || defined __hpux
Packit Service f629e6
	return 1024;
Packit Service f629e6
#elif defined _AIX && defined _I386
Packit Service f629e6
	/* AIX PS/2 counts st_blocks in 4K units.  */
Packit Service f629e6
	return 4 * 1024;
Packit Service f629e6
#elif defined __MINGW32__
Packit Service f629e6
	return 1024;
Packit Service f629e6
#else
Packit Service f629e6
	return 512;
Packit Service f629e6
#endif
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* array_set --- set an array element */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
array_set(awk_array_t array, const char *sub, awk_value_t *value)
Packit Service f629e6
{
Packit Service f629e6
	awk_value_t index;
Packit Service f629e6
Packit Service f629e6
	set_array_element(array,
Packit Service f629e6
			make_const_string(sub, strlen(sub), & index),
Packit Service f629e6
			value);
Packit Service f629e6
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* array_set_numeric --- set an array element with a number */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
array_set_numeric(awk_array_t array, const char *sub, double num)
Packit Service f629e6
{
Packit Service f629e6
	awk_value_t tmp;
Packit Service f629e6
Packit Service f629e6
	array_set(array, sub, make_number(num, & tmp));
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* fill_stat_array --- do the work to fill an array with stat info */
Packit Service f629e6
Packit Service f629e6
static int
Packit Service f629e6
fill_stat_array(const char *name, awk_array_t array, struct stat *sbuf)
Packit Service f629e6
{
Packit Service f629e6
	char *pmode;	/* printable mode */
Packit Service f629e6
	const char *type = "unknown";
Packit Service f629e6
	awk_value_t tmp;
Packit Service f629e6
	static struct ftype_map {
Packit Service f629e6
		unsigned int mask;
Packit Service f629e6
		const char *type;
Packit Service f629e6
	} ftype_map[] = {
Packit Service f629e6
		{ S_IFREG, "file" },
Packit Service f629e6
		{ S_IFBLK, "blockdev" },
Packit Service f629e6
		{ S_IFCHR, "chardev" },
Packit Service f629e6
		{ S_IFDIR, "directory" },
Packit Service f629e6
#ifdef S_IFSOCK
Packit Service f629e6
		{ S_IFSOCK, "socket" },
Packit Service f629e6
#endif
Packit Service f629e6
#ifdef S_IFIFO
Packit Service f629e6
		{ S_IFIFO, "fifo" },
Packit Service f629e6
#endif
Packit Service f629e6
#ifdef S_IFLNK
Packit Service f629e6
		{ S_IFLNK, "symlink" },
Packit Service f629e6
#endif
Packit Service f629e6
#ifdef S_IFDOOR	/* Solaris weirdness */
Packit Service f629e6
		{ S_IFDOOR, "door" },
Packit Service f629e6
#endif /* S_IFDOOR */
Packit Service f629e6
	};
Packit Service f629e6
	int j, k;
Packit Service f629e6
Packit Service f629e6
	/* empty out the array */
Packit Service f629e6
	clear_array(array);
Packit Service f629e6
Packit Service f629e6
	/* fill in the array */
Packit Service f629e6
	array_set(array, "name", make_const_string(name, strlen(name), & tmp));
Packit Service f629e6
	array_set_numeric(array, "dev", sbuf->st_dev);
Packit Service f629e6
#ifdef __MINGW32__
Packit Service f629e6
	array_set_numeric(array, "ino", (double)get_inode (name));
Packit Service f629e6
#else
Packit Service f629e6
	array_set_numeric(array, "ino", sbuf->st_ino);
Packit Service f629e6
#endif
Packit Service f629e6
	array_set_numeric(array, "mode", sbuf->st_mode);
Packit Service f629e6
	array_set_numeric(array, "nlink", sbuf->st_nlink);
Packit Service f629e6
	array_set_numeric(array, "uid", sbuf->st_uid);
Packit Service f629e6
	array_set_numeric(array, "gid", sbuf->st_gid);
Packit Service f629e6
	array_set_numeric(array, "size", sbuf->st_size);
Packit Service f629e6
#ifdef __MINGW32__
Packit Service f629e6
	array_set_numeric(array, "blocks", (sbuf->st_size + 4095) / 4096);
Packit Service f629e6
#else
Packit Service f629e6
	array_set_numeric(array, "blocks", sbuf->st_blocks);
Packit Service f629e6
#endif
Packit Service f629e6
	array_set_numeric(array, "atime", sbuf->st_atime);
Packit Service f629e6
	array_set_numeric(array, "mtime", sbuf->st_mtime);
Packit Service f629e6
	array_set_numeric(array, "ctime", sbuf->st_ctime);
Packit Service f629e6
Packit Service f629e6
	/* for block and character devices, add rdev, major and minor numbers */
Packit Service f629e6
	if (S_ISBLK(sbuf->st_mode) || S_ISCHR(sbuf->st_mode)) {
Packit Service f629e6
		array_set_numeric(array, "rdev", sbuf->st_rdev);
Packit Service f629e6
		array_set_numeric(array, "major", major(sbuf->st_rdev));
Packit Service f629e6
		array_set_numeric(array, "minor", minor(sbuf->st_rdev));
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
Packit Service f629e6
	array_set_numeric(array, "blksize", sbuf->st_blksize);
Packit Service f629e6
#elif defined(__MINGW32__)
Packit Service f629e6
	array_set_numeric(array, "blksize", 4096);
Packit Service f629e6
#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
Packit Service f629e6
Packit Service f629e6
	/* the size of a block for st_blocks */
Packit Service f629e6
	array_set_numeric(array, "devbsize", device_blocksize());
Packit Service f629e6
Packit Service f629e6
	pmode = format_mode(sbuf->st_mode);
Packit Service f629e6
	array_set(array, "pmode", make_const_string(pmode, strlen(pmode), & tmp));
Packit Service f629e6
Packit Service f629e6
	/* for symbolic links, add a linkval field */
Packit Service f629e6
	if (S_ISLNK(sbuf->st_mode)) {
Packit Service f629e6
		char *buf;
Packit Service f629e6
		ssize_t linksize;
Packit Service f629e6
Packit Service f629e6
		if ((buf = read_symlink(name, sbuf->st_size,
Packit Service f629e6
					& linksize)) != NULL)
Packit Service f629e6
			array_set(array, "linkval", make_malloced_string(buf, linksize, & tmp));
Packit Service f629e6
		else
Packit Service f629e6
			warning(ext_id, _("stat: unable to read symbolic link `%s'"), name);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* add a type field */
Packit Service f629e6
	type = "unknown";	/* shouldn't happen */
Packit Service f629e6
	for (j = 0, k = sizeof(ftype_map)/sizeof(ftype_map[0]); j < k; j++) {
Packit Service f629e6
		if ((sbuf->st_mode & S_IFMT) == ftype_map[j].mask) {
Packit Service f629e6
			type = ftype_map[j].type;
Packit Service f629e6
			break;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	array_set(array, "type", make_const_string(type, strlen(type), & tmp));
Packit Service f629e6
Packit Service f629e6
	return 0;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* do_stat --- provide a stat() function for gawk */
Packit Service f629e6
Packit Service f629e6
static awk_value_t *
Packit Service f629e6
do_stat(int nargs, awk_value_t *result, struct awk_ext_func *unused)
Packit Service f629e6
{
Packit Service f629e6
	awk_value_t file_param, array_param;
Packit Service f629e6
	char *name;
Packit Service f629e6
	awk_array_t array;
Packit Service f629e6
	int ret;
Packit Service f629e6
	struct stat sbuf;
Packit Service f629e6
	int (*statfunc)(const char *path, struct stat *sbuf) = lstat;	/* default */
Packit Service f629e6
Packit Service f629e6
	assert(result != NULL);
Packit Service f629e6
Packit Service f629e6
	/* file is first arg, array to hold results is second */
Packit Service f629e6
	if (   ! get_argument(0, AWK_STRING, & file_param)
Packit Service f629e6
	    || ! get_argument(1, AWK_ARRAY, & array_param)) {
Packit Service f629e6
		warning(ext_id, _("stat: bad parameters"));
Packit Service f629e6
		return make_number(-1, result);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (nargs == 3) {
Packit Service f629e6
		statfunc = stat;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	name = file_param.str_value.str;
Packit Service f629e6
	array = array_param.array_cookie;
Packit Service f629e6
Packit Service f629e6
	/* always empty out the array */
Packit Service f629e6
	clear_array(array);
Packit Service f629e6
Packit Service f629e6
	/* stat the file; if error, set ERRNO and return */
Packit Service f629e6
	ret = statfunc(name, & sbuf);
Packit Service f629e6
	if (ret < 0) {
Packit Service f629e6
		update_ERRNO_int(errno);
Packit Service f629e6
		return make_number(ret, result);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	ret = fill_stat_array(name, array, & sbuf);
Packit Service f629e6
Packit Service f629e6
	return make_number(ret, result);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
#if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS)
Packit Service f629e6
Packit Service f629e6
/* do_statvfs --- provide a statvfs() function for gawk */
Packit Service f629e6
Packit Service f629e6
static awk_value_t *
Packit Service f629e6
do_statvfs(int nargs, awk_value_t *result, struct awk_ext_func *unused)
Packit Service f629e6
{
Packit Service f629e6
	awk_value_t file_param, array_param;
Packit Service f629e6
	char *name;
Packit Service f629e6
	awk_array_t array;
Packit Service f629e6
	int ret;
Packit Service f629e6
	struct statvfs vfsbuf;
Packit Service f629e6
Packit Service f629e6
	assert(result != NULL);
Packit Service f629e6
Packit Service f629e6
	/* file is first arg, array to hold results is second */
Packit Service f629e6
	if (   ! get_argument(0, AWK_STRING, & file_param)
Packit Service f629e6
	    || ! get_argument(1, AWK_ARRAY, & array_param)) {
Packit Service f629e6
		warning(ext_id, _("stat: bad parameters"));
Packit Service f629e6
		return make_number(-1, result);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	name = file_param.str_value.str;
Packit Service f629e6
	array = array_param.array_cookie;
Packit Service f629e6
Packit Service f629e6
	/* always empty out the array */
Packit Service f629e6
	clear_array(array);
Packit Service f629e6
Packit Service f629e6
	/* stat the file; if error, set ERRNO and return */
Packit Service f629e6
	ret = statvfs(name, & vfsbuf);
Packit Service f629e6
	if (ret < 0) {
Packit Service f629e6
		update_ERRNO_int(errno);
Packit Service f629e6
		return make_number(ret, result);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	array_set_numeric(array, "bsize", vfsbuf.f_bsize);	/* filesystem block size */
Packit Service f629e6
	array_set_numeric(array, "frsize", vfsbuf.f_frsize);	/* fragment size */
Packit Service f629e6
	array_set_numeric(array, "blocks", vfsbuf.f_blocks);	/* size of fs in f_frsize units */
Packit Service f629e6
	array_set_numeric(array, "bfree", vfsbuf.f_bfree);	/* # free blocks */
Packit Service f629e6
	array_set_numeric(array, "bavail", vfsbuf.f_bavail);	/* # free blocks for unprivileged users */
Packit Service f629e6
	array_set_numeric(array, "files", vfsbuf.f_files);	/* # inodes */
Packit Service f629e6
	array_set_numeric(array, "ffree", vfsbuf.f_ffree);	/* # free inodes */
Packit Service f629e6
	array_set_numeric(array, "favail", vfsbuf.f_favail);	/* # free inodes for unprivileged users */
Packit Service f629e6
#ifndef _AIX
Packit Service f629e6
	array_set_numeric(array, "fsid", vfsbuf.f_fsid);	/* filesystem ID */
Packit Service f629e6
#endif
Packit Service f629e6
	array_set_numeric(array, "flag", vfsbuf.f_flag);	/* mount flags */
Packit Service f629e6
	array_set_numeric(array, "namemax", vfsbuf.f_namemax);	/* maximum filename length */
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
	return make_number(ret, result);
Packit Service f629e6
}
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
/* init_filefuncs --- initialization routine */
Packit Service f629e6
Packit Service f629e6
static awk_bool_t
Packit Service f629e6
init_filefuncs(void)
Packit Service f629e6
{
Packit Service f629e6
	int errors = 0;
Packit Service f629e6
	int i;
Packit Service f629e6
	awk_value_t value;
Packit Service f629e6
Packit Service f629e6
#ifndef __MINGW32__
Packit Service f629e6
	/* at least right now, only FTS needs initializing */
Packit Service f629e6
	static struct flagtab {
Packit Service f629e6
		const char *name;
Packit Service f629e6
		int value;
Packit Service f629e6
	} opentab[] = {
Packit Service f629e6
#define ENTRY(x)	{ #x, x }
Packit Service f629e6
		ENTRY(FTS_COMFOLLOW),
Packit Service f629e6
		ENTRY(FTS_LOGICAL),
Packit Service f629e6
		ENTRY(FTS_NOCHDIR),
Packit Service f629e6
		ENTRY(FTS_PHYSICAL),
Packit Service f629e6
		ENTRY(FTS_SEEDOT),
Packit Service f629e6
		ENTRY(FTS_XDEV),
Packit Service f629e6
		{ NULL, 0 }
Packit Service f629e6
	};
Packit Service f629e6
Packit Service f629e6
	for (i = 0; opentab[i].name != NULL; i++) {
Packit Service f629e6
		(void) make_number(opentab[i].value, & value);
Packit Service f629e6
		if (! sym_update(opentab[i].name, & value)) {
Packit Service f629e6
			warning(ext_id, _("fts init: could not create variable %s"),
Packit Service f629e6
					opentab[i].name);
Packit Service f629e6
			errors++;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
#endif
Packit Service f629e6
	return errors == 0;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
#ifdef __MINGW32__
Packit Service f629e6
/*  do_fts --- walk a hierarchy and fill in an array */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Usage from awk:
Packit Service f629e6
 *	flags = or(FTS_PHYSICAL, ...)
Packit Service f629e6
 *	result = fts(pathlist, flags, filedata)
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
static awk_value_t *
Packit Service f629e6
do_fts(int nargs, awk_value_t *result, struct awk_ext_func *unused)
Packit Service f629e6
{
Packit Service f629e6
	fatal(ext_id, _("fts is not supported on this system"));
Packit Service f629e6
Packit Service f629e6
	return NULL;	/* for the compiler */
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
#else /* __MINGW32__ */
Packit Service f629e6
Packit Service f629e6
static int fts_errors = 0;
Packit Service f629e6
Packit Service f629e6
/* fill_stat_element --- fill in stat element of array */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
fill_stat_element(awk_array_t element_array, const char *name, struct stat *sbuf)
Packit Service f629e6
{
Packit Service f629e6
	awk_value_t index, value;
Packit Service f629e6
	awk_array_t stat_array;
Packit Service f629e6
Packit Service f629e6
	stat_array = create_array();
Packit Service f629e6
	if (stat_array == NULL) {
Packit Service f629e6
		warning(ext_id, _("fill_stat_element: could not create array"));
Packit Service f629e6
		fts_errors++;
Packit Service f629e6
		return;
Packit Service f629e6
	}
Packit Service f629e6
	fill_stat_array(name, stat_array, sbuf);
Packit Service f629e6
	(void) make_const_string("stat", 4, & index);
Packit Service f629e6
	value.val_type = AWK_ARRAY;
Packit Service f629e6
	value.array_cookie = stat_array;
Packit Service f629e6
	if (! set_array_element(element_array, & index, & value)) {
Packit Service f629e6
		warning(ext_id, _("fill_stat_element: could not set element"));
Packit Service f629e6
		fts_errors++;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* fill_path_element --- fill in path element of array */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
fill_path_element(awk_array_t element_array, const char *path)
Packit Service f629e6
{
Packit Service f629e6
	awk_value_t index, value;
Packit Service f629e6
Packit Service f629e6
	(void) make_const_string("path", 4, & index);
Packit Service f629e6
	(void) make_const_string(path, strlen(path), & value);
Packit Service f629e6
	if (! set_array_element(element_array, & index, & value)) {
Packit Service f629e6
		warning(ext_id, _("fill_path_element: could not set element"));
Packit Service f629e6
		fts_errors++;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* fill_error_element --- fill in error element of array */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
fill_error_element(awk_array_t element_array, const int errcode)
Packit Service f629e6
{
Packit Service f629e6
	awk_value_t index, value;
Packit Service f629e6
	const char *err = strerror(errcode);
Packit Service f629e6
Packit Service f629e6
	(void) make_const_string("error", 5, & index);
Packit Service f629e6
	(void) make_const_string(err, strlen(err), & value);
Packit Service f629e6
	if (! set_array_element(element_array, & index, & value)) {
Packit Service f629e6
		warning(ext_id, _("fill_error_element: could not set element"));
Packit Service f629e6
		fts_errors++;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* fill_default_elements --- fill in stat and path elements */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
fill_default_elements(awk_array_t element_array, const FTSENT *const fentry, awk_bool_t bad_ret)
Packit Service f629e6
{
Packit Service f629e6
	/* full path */
Packit Service f629e6
	fill_path_element(element_array, fentry->fts_path);
Packit Service f629e6
Packit Service f629e6
	/* stat info */
Packit Service f629e6
	if (! bad_ret) {
Packit Service f629e6
		fill_stat_element(element_array,
Packit Service f629e6
				fentry->fts_name,
Packit Service f629e6
				fentry->fts_statp);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* error info */
Packit Service f629e6
	if (bad_ret || fentry->fts_errno != 0) {
Packit Service f629e6
		fill_error_element(element_array, fentry->fts_errno);
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* process --- process the hierarchy */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
process(FTS *hierarchy, awk_array_t destarray, int seedot)
Packit Service f629e6
{
Packit Service f629e6
	FTSENT *fentry;
Packit Service f629e6
	awk_value_t index, value;
Packit Service f629e6
	awk_array_t element_array, newdir_array, dot_array;
Packit Service f629e6
	awk_bool_t bad_ret = awk_false;
Packit Service f629e6
Packit Service f629e6
	/* path is full path,  pathlen is length thereof */
Packit Service f629e6
	/* name is name in directory, namelen is length thereof */
Packit Service f629e6
	while ((fentry = fts_read(hierarchy)) != NULL) {
Packit Service f629e6
		bad_ret = awk_false;
Packit Service f629e6
Packit Service f629e6
		switch (fentry->fts_info) {
Packit Service f629e6
		case FTS_D:
Packit Service f629e6
			/* directory */
Packit Service f629e6
			/* create array to hold entries */
Packit Service f629e6
			newdir_array = create_array();
Packit Service f629e6
			if (newdir_array == NULL) {
Packit Service f629e6
				warning(ext_id, _("fts-process: could not create array"));
Packit Service f629e6
				fts_errors++;
Packit Service f629e6
				break;
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
			/* store new directory in its parent directory */
Packit Service f629e6
			(void) make_const_string(fentry->fts_name, fentry->fts_namelen, & index);
Packit Service f629e6
			value.val_type = AWK_ARRAY;
Packit Service f629e6
			value.array_cookie = newdir_array;
Packit Service f629e6
			if (! set_array_element(destarray, & index, & value)) {
Packit Service f629e6
				warning(ext_id, _("fts-process: could not set element"));
Packit Service f629e6
				fts_errors++;
Packit Service f629e6
				break;
Packit Service f629e6
			}
Packit Service f629e6
			newdir_array = value.array_cookie;
Packit Service f629e6
Packit Service f629e6
			/* push current directory */
Packit Service f629e6
			stack_push(destarray);
Packit Service f629e6
Packit Service f629e6
			/* new directory becomes current */
Packit Service f629e6
			destarray = newdir_array;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case FTS_DNR:
Packit Service f629e6
		case FTS_DC:
Packit Service f629e6
		case FTS_ERR:
Packit Service f629e6
		case FTS_NS:
Packit Service f629e6
			/* error */
Packit Service f629e6
			bad_ret = awk_true;
Packit Service f629e6
			/* fall through */
Packit Service f629e6
Packit Service f629e6
		case FTS_NSOK:
Packit Service f629e6
		case FTS_SL:
Packit Service f629e6
		case FTS_SLNONE:
Packit Service f629e6
		case FTS_F:
Packit Service f629e6
		case FTS_DOT:
Packit Service f629e6
			/* if see dot, skip "." */
Packit Service f629e6
			if (seedot && strcmp(fentry->fts_name, ".") == 0)
Packit Service f629e6
				break;
Packit Service f629e6
Packit Service f629e6
			/*
Packit Service f629e6
			 * File case.
Packit Service f629e6
			 * destarray is the directory we're reading.
Packit Service f629e6
			 * step 1: create new empty array
Packit Service f629e6
			 */
Packit Service f629e6
			element_array = create_array();
Packit Service f629e6
			if (element_array == NULL) {
Packit Service f629e6
				warning(ext_id, _("fts-process: could not create array"));
Packit Service f629e6
				fts_errors++;
Packit Service f629e6
				break;
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
			/* step 2: add element array to parent array */
Packit Service f629e6
			(void) make_const_string(fentry->fts_name, fentry->fts_namelen, & index);
Packit Service f629e6
			value.val_type = AWK_ARRAY;
Packit Service f629e6
			value.array_cookie = element_array;
Packit Service f629e6
			if (! set_array_element(destarray, & index, & value)) {
Packit Service f629e6
				warning(ext_id, _("fts-process: could not set element"));
Packit Service f629e6
				fts_errors++;
Packit Service f629e6
				break;
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
			/* step 3: fill in path, stat, error elements */
Packit Service f629e6
			fill_default_elements(element_array, fentry, bad_ret);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case FTS_DP:
Packit Service f629e6
			/* create "." subarray */
Packit Service f629e6
			dot_array = create_array();
Packit Service f629e6
Packit Service f629e6
			/* add it to parent */
Packit Service f629e6
			(void) make_const_string(".", 1, & index);
Packit Service f629e6
			value.val_type = AWK_ARRAY;
Packit Service f629e6
			value.array_cookie = dot_array;
Packit Service f629e6
			if (! set_array_element(destarray, & index, & value)) {
Packit Service f629e6
				warning(ext_id, _("fts-process: could not set element"));
Packit Service f629e6
				fts_errors++;
Packit Service f629e6
				break;
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
			/* fill it in with path, stat, error elements */
Packit Service f629e6
			fill_default_elements(dot_array, fentry, bad_ret);
Packit Service f629e6
Packit Service f629e6
			/* now pop the parent directory off the stack */
Packit Service f629e6
			if (! stack_empty()) {
Packit Service f629e6
				/* pop stack */
Packit Service f629e6
				destarray = stack_pop();
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case FTS_DEFAULT:
Packit Service f629e6
			/* nothing to do */
Packit Service f629e6
			break;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/*  do_fts --- walk a hierarchy and fill in an array */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Usage from awk:
Packit Service f629e6
 *	flags = or(FTS_PHYSICAL, ...)
Packit Service f629e6
 *	result = fts(pathlist, flags, filedata)
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
static awk_value_t *
Packit Service f629e6
do_fts(int nargs, awk_value_t *result, struct awk_ext_func *unused)
Packit Service f629e6
{
Packit Service f629e6
	awk_value_t pathlist, flagval, dest;
Packit Service f629e6
	awk_flat_array_t *path_array = NULL;
Packit Service f629e6
	char **pathvector = NULL;
Packit Service f629e6
	FTS *hierarchy;
Packit Service f629e6
	int flags;
Packit Service f629e6
	size_t i, count;
Packit Service f629e6
	int ret = -1;
Packit Service f629e6
	static const int mask = (
Packit Service f629e6
		  FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR | FTS_PHYSICAL
Packit Service f629e6
		| FTS_SEEDOT | FTS_XDEV);
Packit Service f629e6
Packit Service f629e6
	assert(result != NULL);
Packit Service f629e6
	fts_errors = 0;		/* ensure a fresh start */
Packit Service f629e6
Packit Service f629e6
	if (nargs > 3)
Packit Service f629e6
		lintwarn(ext_id, _("fts: called with incorrect number of arguments, expecting 3"));
Packit Service f629e6
Packit Service f629e6
	if (! get_argument(0, AWK_ARRAY, & pathlist)) {
Packit Service f629e6
		warning(ext_id, _("fts: bad first parameter"));
Packit Service f629e6
		update_ERRNO_int(EINVAL);
Packit Service f629e6
		goto out;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (! get_argument(1, AWK_NUMBER, & flagval)) {
Packit Service f629e6
		warning(ext_id, _("fts: bad second parameter"));
Packit Service f629e6
		update_ERRNO_int(EINVAL);
Packit Service f629e6
		goto out;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (! get_argument(2, AWK_ARRAY, & dest)) {
Packit Service f629e6
		warning(ext_id, _("fts: bad third parameter"));
Packit Service f629e6
		update_ERRNO_int(EINVAL);
Packit Service f629e6
		goto out;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* flatten pathlist */
Packit Service f629e6
	if (! flatten_array(pathlist.array_cookie, & path_array)) {
Packit Service f629e6
		warning(ext_id, _("fts: could not flatten array\n"));
Packit Service f629e6
		goto out;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* check the flags first, before the array flattening */
Packit Service f629e6
Packit Service f629e6
	/* get flags */
Packit Service f629e6
	flags = flagval.num_value;
Packit Service f629e6
Packit Service f629e6
	/* enforce physical or logical but not both, and not no_stat */
Packit Service f629e6
	if ((flags & (FTS_PHYSICAL|FTS_LOGICAL)) == 0
Packit Service f629e6
	    || (flags & (FTS_PHYSICAL|FTS_LOGICAL)) == (FTS_PHYSICAL|FTS_LOGICAL)) {
Packit Service f629e6
		update_ERRNO_int(EINVAL);
Packit Service f629e6
		goto out;
Packit Service f629e6
	}
Packit Service f629e6
	if ((flags & FTS_NOSTAT) != 0) {
Packit Service f629e6
		flags &= ~FTS_NOSTAT;
Packit Service f629e6
		if (do_lint)
Packit Service f629e6
			lintwarn(ext_id, _("fts: ignoring sneaky FTS_NOSTAT flag. nyah, nyah, nyah."));
Packit Service f629e6
	}
Packit Service f629e6
	flags &= mask;	/* turn off anything else */
Packit Service f629e6
Packit Service f629e6
	/* make pathvector */
Packit Service f629e6
	count = path_array->count + 1;
Packit Service f629e6
	ezalloc(pathvector, char **, count * sizeof(char *), "do_fts");
Packit Service f629e6
Packit Service f629e6
	/* fill it in */
Packit Service f629e6
	count--;	/* ignore final NULL at end of vector */
Packit Service f629e6
	for (i = 0; i < count; i++)
Packit Service f629e6
		pathvector[i] = path_array->elements[i].value.str_value.str;
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
	/* clear dest array */
Packit Service f629e6
	if (! clear_array(dest.array_cookie)) {
Packit Service f629e6
		warning(ext_id, _("fts: clear_array() failed\n"));
Packit Service f629e6
		goto out;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* let's do it! */
Packit Service f629e6
	if ((hierarchy = fts_open(pathvector, flags, NULL)) != NULL) {
Packit Service f629e6
		process(hierarchy, dest.array_cookie, (flags & FTS_SEEDOT) != 0);
Packit Service f629e6
		fts_close(hierarchy);
Packit Service f629e6
Packit Service f629e6
		if (fts_errors == 0)
Packit Service f629e6
			ret = 0;
Packit Service f629e6
	} else
Packit Service f629e6
		update_ERRNO_int(errno);
Packit Service f629e6
Packit Service f629e6
out:
Packit Service f629e6
	if (pathvector != NULL)
Packit Service f629e6
		gawk_free(pathvector);
Packit Service f629e6
	if (path_array != NULL)
Packit Service f629e6
		(void) release_flattened_array(pathlist.array_cookie, path_array);
Packit Service f629e6
Packit Service f629e6
	return make_number(ret, result);
Packit Service f629e6
}
Packit Service f629e6
#endif	/* ! __MINGW32__ */
Packit Service f629e6
Packit Service f629e6
static awk_ext_func_t func_table[] = {
Packit Service f629e6
	{ "chdir",	do_chdir, 1, 1, awk_false, NULL },
Packit Service f629e6
	{ "stat",	do_stat, 3, 2, awk_false, NULL },
Packit Service f629e6
#ifndef __MINGW32__
Packit Service f629e6
	{ "fts",	do_fts, 3, 3, awk_false, NULL },
Packit Service f629e6
#endif
Packit Service f629e6
#if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS)
Packit Service f629e6
	{ "statvfs",	do_statvfs, 2, 2, awk_false, NULL },
Packit Service f629e6
#endif
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* define the dl_load function using the boilerplate macro */
Packit Service f629e6
Packit Service f629e6
dl_load_func(func_table, filefuncs, "")