--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/openenvutils/commandshell/shell/src/modules/stat.c Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,650 @@
+// stat.c - stat builtin interface to system call
+//
+// © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
+//
+/*
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1996-1997 Peter Stephenson
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Peter Stephenson or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Peter Stephenson and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Peter Stephenson and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Peter Stephenson and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+#include "stat.mdh"
+#include "stat.pro"
+
+#ifdef __SYMBIAN32__
+#ifdef __WINSCW__
+#pragma warn_unusedarg off
+#endif//__WINSCW__
+#endif//__SYMBIAN32__
+
+enum statnum { ST_DEV, ST_INO, ST_MODE, ST_NLINK, ST_UID, ST_GID,
+ ST_RDEV, ST_SIZE, ST_ATIM, ST_MTIM, ST_CTIM,
+ ST_BLKSIZE, ST_BLOCKS, ST_READLINK, ST_COUNT };
+enum statflags { STF_NAME = 1, STF_FILE = 2, STF_STRING = 4, STF_RAW = 8,
+ STF_PICK = 16, STF_ARRAY = 32, STF_GMT = 64,
+ STF_HASH = 128, STF_OCTAL = 256 };
+static char *statelts[] = { "device", "inode", "mode", "nlink",
+ "uid", "gid", "rdev", "size", "atime",
+ "mtime", "ctime", "blksize", "blocks",
+ "link", NULL };
+#define HNAMEKEY "name"
+
+/**/
+static void
+statmodeprint(mode_t mode, char *outbuf, int flags)
+{
+ if (flags & STF_RAW) {
+ sprintf(outbuf, (flags & STF_OCTAL) ? "0%lo" : "%lu",
+ (unsigned long)mode);
+ if (flags & STF_STRING)
+ strcat(outbuf, " (");
+ }
+ if (flags & STF_STRING) {
+ static const char *modes = "?rwxrwxrwx";
+#ifdef __CYGWIN__
+ static mode_t mflags[9] = { 0 };
+#else
+ static const mode_t mflags[9] = {
+ S_IRUSR, S_IWUSR, S_IXUSR,
+ S_IRGRP, S_IWGRP, S_IXGRP,
+ S_IROTH, S_IWOTH, S_IXOTH
+ };
+#endif
+ const mode_t *mfp = mflags;
+ char pm[11];
+ int i;
+
+#ifdef __CYGWIN__
+ if (mflags[0] == 0) {
+ mflags[0] = S_IRUSR;
+ mflags[1] = S_IWUSR;
+ mflags[2] = S_IXUSR;
+ mflags[3] = S_IRGRP;
+ mflags[4] = S_IWGRP;
+ mflags[5] = S_IXGRP;
+ mflags[6] = S_IROTH;
+ mflags[7] = S_IWOTH;
+ mflags[8] = S_IXOTH;
+ }
+#endif
+
+ if (S_ISBLK(mode))
+ *pm = 'b';
+ else if (S_ISCHR(mode))
+ *pm = 'c';
+ else if (S_ISDIR(mode))
+ *pm = 'd';
+ else if (S_ISDOOR(mode))
+ *pm = 'D';
+ else if (S_ISFIFO(mode))
+ *pm = 'p';
+ else if (S_ISLNK(mode))
+ *pm = 'l';
+ else if (S_ISMPC(mode))
+ *pm = 'm';
+ else if (S_ISNWK(mode))
+ *pm = 'n';
+ else if (S_ISOFD(mode))
+ *pm = 'M';
+ else if (S_ISOFL(mode))
+ *pm = 'M';
+ else if (S_ISREG(mode))
+ *pm = '-';
+ else if (S_ISSOCK(mode))
+ *pm = 's';
+ else
+ *pm = '?';
+
+ for (i = 1; i <= 9; i++)
+ pm[i] = (mode & *mfp++) ? modes[i] : '-';
+ pm[10] = '\0';
+
+ if (mode & S_ISUID)
+ pm[3] = (mode & S_IXUSR) ? 's' : 'S';
+ if (mode & S_ISGID)
+ pm[6] = (mode & S_IXGRP) ? 's' : 'S';
+ if (mode & S_ISVTX)
+ pm[9] = (mode & S_IXOTH) ? 't' : 'T';
+
+ pm[10] = 0;
+ strcat(outbuf, pm);
+ if (flags & STF_RAW)
+ strcat(outbuf, ")");
+ }
+}
+
+
+/**/
+static void
+statuidprint(uid_t uid, char *outbuf, int flags)
+{
+ if (flags & STF_RAW) {
+ sprintf(outbuf, "%lu", (unsigned long)uid);
+ if (flags & STF_STRING)
+ strcat(outbuf, " (");
+ }
+ if (flags & STF_STRING) {
+#ifdef HAVE_GETPWUID
+ struct passwd *pwd;
+ pwd = getpwuid(uid);
+ strcat(outbuf, pwd ? pwd->pw_name : "???");
+#else /* !HAVE_GETPWUID */
+ strcat(outbuf, "???");
+#endif /* !HAVE_GETPWUID */
+ if (flags & STF_RAW)
+ strcat(outbuf, ")");
+ }
+}
+
+
+/**/
+static void
+statgidprint(gid_t gid, char *outbuf, int flags)
+{
+ if (flags & STF_RAW) {
+ sprintf(outbuf, "%lu", (unsigned long)gid);
+ if (flags & STF_STRING)
+ strcat(outbuf, " (");
+ }
+ if (flags & STF_STRING) {
+#ifdef HAVE_GETGRGID
+ struct group *gr;
+ gr = getgrgid(gid);
+ strcat(outbuf, gr ? gr->gr_name : "???");
+#else /* !HAVE_GETGRGID */
+ strcat(outbuf, "???");
+#endif /* !HAVE_GETGRGID */
+ if (flags & STF_RAW)
+ strcat(outbuf, ")");
+ }
+}
+
+static char *timefmt;
+
+/**/
+static void
+stattimeprint(time_t tim, char *outbuf, int flags)
+{
+ if (flags & STF_RAW) {
+ sprintf(outbuf, "%ld", (unsigned long)tim);
+ if (flags & STF_STRING)
+ strcat(outbuf, " (");
+ }
+ if (flags & STF_STRING) {
+ char *oend = outbuf + strlen(outbuf);
+ ztrftime(oend, 40, timefmt, (flags & STF_GMT) ? gmtime(&tim) :
+ localtime(&tim));
+ if (flags & STF_RAW)
+ strcat(outbuf, ")");
+ }
+}
+
+
+/**/
+static void
+statulprint(unsigned long num, char *outbuf)
+{
+ sprintf(outbuf, "%lu", num);
+}
+
+
+/**/
+static void
+statlinkprint(struct stat *sbuf, char *outbuf, char *fname)
+{
+ int num;
+
+ /* fname is NULL if we are looking at an fd */
+ if (fname && S_ISLNK(sbuf->st_mode) &&
+ (num = readlink(fname, outbuf, PATH_MAX)) > 0) {
+ /* readlink doesn't terminate the buffer itself */
+ outbuf[num] = '\0';
+ }
+}
+
+
+/**/
+static void
+statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
+{
+ char *optr = outbuf;
+
+ if (flags & STF_NAME) {
+ sprintf(outbuf, (flags & (STF_PICK|STF_ARRAY)) ?
+ "%s " : "%-8s", statelts[iwhich]);
+ optr += strlen(outbuf);
+ }
+ *optr = '\0';
+
+ /* cast values to unsigned long as safest bet */
+ switch (iwhich) {
+ case ST_DEV:
+ statulprint((unsigned long)sbuf->st_dev, optr);
+ break;
+
+ case ST_INO:
+#ifdef INO_T_IS_64_BIT
+ convbase(optr, sbuf->st_ino, 0);
+#else
+ DPUTS(sizeof(sbuf->st_ino) > 4,
+ "Shell compiled with wrong ino_t size");
+ statulprint((unsigned long)sbuf->st_ino, optr);
+#endif
+ break;
+
+ case ST_MODE:
+ statmodeprint(sbuf->st_mode, optr, flags);
+ break;
+
+ case ST_NLINK:
+ statulprint((unsigned long)sbuf->st_nlink, optr);
+ break;
+
+ case ST_UID:
+ statuidprint(sbuf->st_uid, optr, flags);
+ break;
+
+ case ST_GID:
+ statgidprint(sbuf->st_gid, optr, flags);
+ break;
+
+ case ST_RDEV:
+ statulprint((unsigned long)sbuf->st_rdev, optr);
+ break;
+
+ case ST_SIZE:
+#ifdef OFF_T_IS_64_BIT
+ convbase(optr, sbuf->st_size, 0);
+#else
+ DPUTS(sizeof(sbuf->st_size) > 4,
+ "Shell compiled with wrong off_t size");
+ statulprint((unsigned long)sbuf->st_size, optr);
+#endif
+ break;
+
+ case ST_ATIM:
+ stattimeprint(sbuf->st_atime, optr, flags);
+ break;
+
+ case ST_MTIM:
+ stattimeprint(sbuf->st_mtime, optr, flags);
+ break;
+
+ case ST_CTIM:
+ stattimeprint(sbuf->st_ctime, optr, flags);
+ break;
+
+ case ST_BLKSIZE:
+ statulprint((unsigned long)sbuf->st_blksize, optr);
+ break;
+
+ case ST_BLOCKS:
+ statulprint((unsigned long)sbuf->st_blocks, optr);
+ break;
+
+ case ST_READLINK:
+ statlinkprint(sbuf, optr, fname);
+ break;
+
+ case ST_COUNT: /* keep some compilers happy */
+ break;
+ }
+}
+
+
+/*
+ *
+ * Options:
+ * -f fd: stat fd instead of file
+ * -g: use GMT rather than local time for time strings (forces -s on).
+ * -n: always print file name of file being statted
+ * -N: never print file name
+ * -l: list stat types
+ * -L: do lstat (else links are implicitly dereferenced by stat)
+ * -t: always print name of stat type
+ * -T: never print name of stat type
+ * -r: print raw alongside string data
+ * -s: string, print mode, times, uid, gid as appropriate strings:
+ * harmless but unnecessary when combined with -r.
+ * -A array: assign results to given array, one stat result per element.
+ * File names and type names are only added if explicitly requested:
+ * file names are returned as a separate array element, type names as
+ * prefix to element. Note the formatting deliberately contains
+ * fewer frills when -A is used.
+ * -H hash: as for -A array, but returns a hash with the keys being those
+ * from stat -l
+ * -F fmt: specify a $TIME-like format for printing times; the default
+ * is the (CTIME-like) "%a %b %e %k:%M:%S". This option implies
+ * -s as it is not useful for numerical times.
+ *
+ * +type selects just element type of stat buffer (-l gives list):
+ * type can be shortened to unambiguous string. only one type is
+ * allowed. The extra type, +link, reads the target of a symbolic
+ * link; it is empty if the stat was not an lstat or if
+ * a file descriptor was stat'd, if the stat'd file is
+ * not a symbolic link, or if symbolic links are not
+ * supported. If +link is explicitly requested, the -L (lstat)
+ * option is set automatically.
+ */
+/**/
+static int
+bin_stat(char *name, char **args, Options ops, UNUSED(int func))
+{
+ char **aptr, *arrnam = NULL, **array = NULL, **arrptr = NULL;
+ char *hashnam = NULL, **hash = NULL, **hashptr = NULL;
+ int len, iwhich = -1, ret = 0, flags = 0, arrsize = 0, fd = 0;
+ struct stat statbuf;
+ int found = 0, nargs;
+
+ timefmt = "%a %b %e %k:%M:%S";
+
+ for (; *args && (**args == '+' || **args == '-'); args++) {
+ char *arg = *args+1;
+ if (!*arg || *arg == '-' || *arg == '+') {
+ args++;
+ break;
+ }
+
+ if (**args == '+') {
+ if (found)
+ break;
+ len = strlen(arg);
+ for (aptr = statelts; *aptr; aptr++)
+ if (!strncmp(*aptr, arg, len)) {
+ found++;
+ iwhich = aptr - statelts;
+ }
+ if (found > 1) {
+ zwarnnam(name, "%s: ambiguous stat element", arg, 0);
+ return 1;
+ } else if (found == 0) {
+ zwarnnam(name, "%s: no such stat element", arg, 0);
+ return 1;
+ }
+ /* if name of link requested, turn on lstat */
+ if (iwhich == ST_READLINK)
+ ops->ind['L'] = 1;
+ flags |= STF_PICK;
+ } else {
+ for (; *arg; arg++) {
+ if (strchr("glLnNorstT", *arg))
+ ops->ind[STOUC(*arg)] = 1;
+ else if (*arg == 'A') {
+ if (arg[1]) {
+ arrnam = arg+1;
+ } else if (!(arrnam = *++args)) {
+ zwarnnam(name, "missing parameter name",
+ NULL, 0);
+ return 1;
+ }
+ flags |= STF_ARRAY;
+ break;
+ } else if (*arg == 'H') {
+ if (arg[1]) {
+ hashnam = arg+1;
+ } else if (!(hashnam = *++args)) {
+ zwarnnam(name, "missing parameter name",
+ NULL, 0);
+ return 1;
+ }
+ flags |= STF_HASH;
+ break;
+ } else if (*arg == 'f') {
+ char *sfd;
+ ops->ind['f'] = 1;
+ if (arg[1]) {
+ sfd = arg+1;
+ } else if (!(sfd = *++args)) {
+ zwarnnam(name, "missing file descriptor", NULL, 0);
+ return 1;
+ }
+ fd = zstrtol(sfd, &sfd, 10);
+ if (*sfd) {
+ zwarnnam(name, "bad file descriptor", NULL, 0);
+ return 1;
+ }
+ break;
+ } else if (*arg == 'F') {
+ if (arg[1]) {
+ timefmt = arg+1;
+ } else if (!(timefmt = *++args)) {
+ zwarnnam(name, "missing time format", NULL, 0);
+ return 1;
+ }
+ /* force string format in order to use time format */
+ ops->ind['s'] = 1;
+ break;
+ } else {
+ zwarnnam(name, "bad option: -%c", NULL, *arg);
+ return 1;
+ }
+ }
+ }
+ }
+
+ if ((flags & STF_ARRAY) && (flags & STF_HASH)) {
+ /* We don't implement setting multiple variables at once */
+ zwarnnam(name, "both array and hash requested", NULL, 0);
+ return 1;
+ /* Alternate method would be to make -H blank arrnam etc etc *
+ * and so get 'silent loss' of earlier choice, which would *
+ * be similar to stat -A foo -A bar filename */
+ }
+
+ if (OPT_ISSET(ops,'l')) {
+ /* list types and return: can also list to array */
+ if (arrnam) {
+ arrptr = array = (char **)zalloc((ST_COUNT+1)*sizeof(char *));
+ array[ST_COUNT] = NULL;
+ }
+ for (aptr = statelts; *aptr; aptr++) {
+ if (arrnam) {
+ *arrptr++ = ztrdup(*aptr);
+ } else {
+ printf("%s", *aptr);
+ if (aptr[1])
+ putchar(' ');
+ }
+ }
+ if (arrnam) {
+ setaparam(arrnam, array);
+ if (errflag)
+ return 1;
+ } else
+ putchar('\n');
+ return 0;
+ }
+
+ if (!*args && !OPT_ISSET(ops,'f')) {
+ zwarnnam(name, "no files given", NULL, 0);
+ return 1;
+ } else if (*args && OPT_ISSET(ops,'f')) {
+ zwarnnam(name, "no files allowed with -f", NULL, 0);
+ return 1;
+ }
+
+ nargs = 0;
+ if (OPT_ISSET(ops,'f'))
+ nargs = 1;
+ else
+ for (aptr = args; *aptr; aptr++)
+ nargs++;
+
+ if (OPT_ISSET(ops,'g')) {
+ flags |= STF_GMT;
+ ops->ind['s'] = 1;
+ }
+ if (OPT_ISSET(ops,'s') || OPT_ISSET(ops,'r'))
+ flags |= STF_STRING;
+ if (OPT_ISSET(ops,'r') || !OPT_ISSET(ops,'s'))
+ flags |= STF_RAW;
+ if (OPT_ISSET(ops,'n'))
+ flags |= STF_FILE;
+ if (OPT_ISSET(ops,'o'))
+ flags |= STF_OCTAL;
+ if (OPT_ISSET(ops,'t'))
+ flags |= STF_NAME;
+
+ if (!(arrnam || hashnam)) {
+ if (nargs > 1)
+ flags |= STF_FILE;
+ if (!(flags & STF_PICK))
+ flags |= STF_NAME;
+ }
+
+ if (OPT_ISSET(ops,'N') || OPT_ISSET(ops,'f'))
+ flags &= ~STF_FILE;
+ if (OPT_ISSET(ops,'T') || OPT_ISSET(ops,'H'))
+ flags &= ~STF_NAME;
+
+ if (hashnam) {
+ if (nargs > 1) {
+ zwarnnam(name, "only one file allowed with -H", NULL, 0);
+ return 1;
+ }
+ arrsize = (flags & STF_PICK) ? 1 : ST_COUNT;
+ if (flags & STF_FILE)
+ arrsize++;
+ hashptr = hash = (char **)zshcalloc((arrsize+1)*2*sizeof(char *));
+ }
+
+ if (arrnam) {
+ arrsize = (flags & STF_PICK) ? 1 : ST_COUNT;
+ if (flags & STF_FILE)
+ arrsize++;
+ arrsize *= nargs;
+ arrptr = array = (char **)zshcalloc((arrsize+1)*sizeof(char *));
+ }
+
+ for (; OPT_ISSET(ops,'f') || *args; args++) {
+ char outbuf[PATH_MAX + 9]; /* "link " + link name + NULL */
+ int rval = OPT_ISSET(ops,'f') ? fstat(fd, &statbuf) :
+ OPT_ISSET(ops,'L') ? lstat(*args, &statbuf) :
+ stat(*args, &statbuf);
+ if (rval) {
+ if (OPT_ISSET(ops,'f'))
+ sprintf(outbuf, "%d", fd);
+ zwarnnam(name, "%s: %e", OPT_ISSET(ops,'f') ? outbuf : *args,
+ errno);
+ ret = 1;
+ if (OPT_ISSET(ops,'f') || arrnam)
+ break;
+ else
+ continue;
+ }
+
+ if (flags & STF_FILE) {
+ if (arrnam)
+ *arrptr++ = ztrdup(*args);
+ else if (hashnam) {
+ *hashptr++ = ztrdup(HNAMEKEY);
+ *hashptr++ = ztrdup(*args);
+ } else
+ printf("%s%s", *args, (flags & STF_PICK) ? " " : ":\n");
+ }
+ if (iwhich > -1) {
+ statprint(&statbuf, outbuf, *args, iwhich, flags);
+ if (arrnam)
+ *arrptr++ = ztrdup(outbuf);
+ else if (hashnam) {
+ /* STF_NAME explicitly turned off for ops.ind['H'] above */
+ *hashptr++ = ztrdup(statelts[iwhich]);
+ *hashptr++ = ztrdup(outbuf);
+ } else
+ printf("%s\n", outbuf);
+ } else {
+ int i;
+ for (i = 0; i < ST_COUNT; i++) {
+ statprint(&statbuf, outbuf, *args, i, flags);
+ if (arrnam)
+ *arrptr++= ztrdup(outbuf);
+ else if (hashnam) {
+ /* STF_NAME explicitly turned off for ops.ind['H'] above */
+ *hashptr++ = ztrdup(statelts[i]);
+ *hashptr++ = ztrdup(outbuf);
+ } else
+ printf("%s\n", outbuf);
+ }
+ }
+ if (OPT_ISSET(ops,'f'))
+ break;
+
+ if (!arrnam && !hashnam && args[1] && !(flags & STF_PICK))
+ putchar('\n');
+ }
+
+ if (arrnam) {
+ if (ret)
+ freearray(array);
+ else {
+ setaparam(arrnam, array);
+ if (errflag)
+ return 1;
+ }
+ }
+
+ if (hashnam) {
+ if (ret)
+ freearray(hash);
+ else {
+ sethparam(hashnam, hash);
+ if (errflag)
+ return 1;
+ }
+ }
+
+ return ret;
+}
+
+static struct builtin bintab[] = {
+ BUILTIN("stat", 0, bin_stat, 0, -1, 0, NULL, NULL),
+};
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+ return 0;
+}
+
+/**/
+int
+boot_(Module m)
+{
+ return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+}
+
+/**/
+int
+cleanup_(Module m)
+{
+ deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+ return 0;
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+ return 0;
+}