|
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, "")
|