Merge of master-melb:xfs-cmds:24394a by kenmcd.
Add getparents handle functions.
struct fsdmidata;
struct attrlist_cursor;
+struct parent_cursor;
+struct parent;
extern int path_to_handle (char *__path, void **__hanp, size_t *__hlen);
extern int path_to_fshandle (char *__path, void **__fshanp, size_t *__fshlen);
extern int attr_list_by_handle (void *__hanp, size_t __hlen, void *__buf,
size_t __bufsize, int __flags,
struct attrlist_cursor *__cursor);
+extern int getparents_by_handle(void *__hanp, size_t __hlen,
+ struct parent *__buf, size_t __bufsize,
+ struct parent_cursor *__cursor,
+ unsigned int *__count, unsigned int *__more);
+extern int getparentpaths_by_handle(void *__hanp, size_t __hlen,
+ struct parent *__buf, size_t __bufsize,
+ struct parent_cursor *__cursor,
+ unsigned int *__count, unsigned int *__more);
extern int fssetdm_by_handle (void *__hanp, size_t __hlen,
struct fsdmidata *__fsdmi);
void *buffer; /* returned names */
} xfs_fsop_attrlist_handlereq_t;
+typedef struct xfs_fsop_getparents_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle interface structure */
+ struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */
+ __u32 buflen; /* length of buffer supplied */
+ void *buffer; /* returned data */
+ __u32 *ocount; /* return number of links */
+ __u32 *omore; /* return whether more to come */
+} xfs_fsop_getparents_handlereq_t;
+
typedef struct xfs_attr_multiop {
__u32 am_opcode;
__s32 am_error;
((xfs_fsop_attrlist_handlereq_t*)arg)->buflen,
((xfs_fsop_attrlist_handlereq_t*)arg)->flags,
&(((xfs_fsop_attrlist_handlereq_t*)arg)->pos));
+ case SGI_XFS_GETPARENTS:
+ case SGI_XFS_GETPARENTPATHS:
+ return syssgi(cmd,
+ ((xfs_fsop_getparents_handlereq_t*)arg)->hreq.ihandle,
+ ((xfs_fsop_getparents_handlereq_t*)arg)->hreq.ihandlen,
+ ((xfs_fsop_getparents_handlereq_t*)arg)->buffer,
+ ((xfs_fsop_getparents_handlereq_t*)arg)->buflen,
+ &(((xfs_fsop_getparents_handlereq_t*)arg)->pos),
+ ((xfs_fsop_getparents_handlereq_t*)arg)->ocount,
+ ((xfs_fsop_getparents_handlereq_t*)arg)->omore);
case SGI_ATTR_MULTI_BY_HANDLE:
return syssgi(cmd,
((xfs_fsop_attrmulti_handlereq_t*)arg)->hreq.ihandle,
#define XFS_IOC_ATTRMULTI_BY_HANDLE SGI_ATTR_MULTI_BY_HANDLE
#define XFS_IOC_FSGEOMETRY XFS_FS_GEOMETRY
#define XFS_IOC_GOINGDOWN XFS_FS_GOINGDOWN
+#define XFS_IOC_GETPARENTS SGI_XFS_GETPARENTS
+#define XFS_IOC_GETPARENTPATHS SGI_XFS_GETPARENTPATHS
#endif /* __XFS_IRIX_H__ */
struct xfs_bstat;
struct attrlist_cursor;
+struct parent_cursor;
+struct parent;
extern jdm_fshandle_t *
jdm_getfshandle( char *mntpnt);
char *bufp, size_t bufsz, int flags,
struct attrlist_cursor *cursor);
+extern int
+jdm_getparents( jdm_fshandle_t *fshp,
+ xfs_bstat_t *statp,
+ struct parent *bufp, size_t bufsz,
+ struct parent_cursor *cursor,
+ unsigned int *count, unsigned int *more);
+
+extern int
+jdm_getparentpaths( jdm_fshandle_t *fshp,
+ xfs_bstat_t *statp,
+ struct parent *bufp, size_t bufsz,
+ struct parent_cursor *cursor,
+ unsigned int *count, unsigned int *more);
+
/* macro for determining the size of a structure member */
#define sizeofmember( t, m ) sizeof( ( ( t * )0 )->m )
--- /dev/null
+/*
+ * Copyright (c) 2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __PARENT_H__
+#define __PARENT_H__
+
+typedef struct parent {
+ __u64 p_ino;
+ __u32 p_gen;
+ __u16 p_reclen;
+ char p_name[1];
+} parent_t;
+
+typedef struct parent_cursor {
+ __u32 opaque[4]; /* an opaque cookie */
+} parent_cursor_t;
+
+#endif
LSRCFILES += sendfile.c
endif
-ifneq ($(PKG_PLATFORM),irix)
+ifeq ($(PKG_PLATFORM),irix)
+LSRCFILES += inject.c resblks.c shutdown.c
+CFILES += parent.c
+LCFLAGS += -DHAVE_PARENT
+else
+LSRCFILES += parent.c
CFILES += inject.c resblks.c shutdown.c
LCFLAGS += -DHAVE_INJECT -DHAVE_RESBLKS -DHAVE_SHUTDOWN
-else
-LSRCFILES += inject.c resblks.c shutdown.c
endif
ifeq ($(ENABLE_READLINE),yes)
inject_init();
mmap_init();
open_init();
+ parent_init();
pread_init();
prealloc_init();
pwrite_init();
#define mincore_init() do { } while (0)
#endif
+#ifdef HAVE_PARENT
+extern void parent_init(void);
+#else
+#define parent_init() do { } while (0)
+#endif
fd = open(path, oflags, mode);
if (fd < 0) {
- perror(path);
- return -1;
+ if ((errno == EISDIR) && (oflags & O_RDWR)) {
+ /* make it as if we asked for O_RDONLY & try again */
+ oflags &= ~O_RDWR;
+ oflags |= O_RDONLY;
+ flags |= IO_READONLY;
+ fd = open(path, oflags, mode);
+ if (fd < 0) {
+ perror(path);
+ return -1;
+ }
+ } else {
+ perror(path);
+ return -1;
+ }
}
if (!geom)
--- /dev/null
+/*
+ * Copyright (c) 2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <xfs/xfs.h>
+#include <xfs/command.h>
+#include <xfs/input.h>
+#include <xfs/path.h>
+#include <xfs/parent.h>
+#include <xfs/handle.h>
+#include <xfs/jdm.h>
+#include "init.h"
+#include "io.h"
+
+#define PARENTBUF_SZ 16384
+#define BSTATBUF_SZ 4096
+
+static cmdinfo_t parent_cmd;
+static int verbose_flag;
+static int err_status;
+static uint64_t inodes_checked;
+
+/*
+ * check out a parent entry to see if the values seem valid
+ */
+static void
+check_parent_entry(xfs_bstat_t *bstatp, parent_t *parent, char *mntpt)
+{
+ int sts;
+ char fullpath[PATH_MAX];
+ struct stat statbuf;
+ char *str;
+
+ sprintf(fullpath, _("%s%s"), mntpt, parent->p_name);
+
+ sts = lstat(fullpath, &statbuf);
+ if (sts != 0) {
+ fprintf(stderr,
+ _("inode-path for inode: %llu is incorrect - path non-existent\n"),
+ bstatp->bs_ino);
+ if (verbose_flag) {
+ fprintf(stderr,
+ _("path \"%s\" does not stat for inode: %llu; err = %s\n"),
+ fullpath,
+ bstatp->bs_ino,
+ strerror(errno));
+ }
+ err_status++;
+ return;
+ } else {
+ if (verbose_flag > 1) {
+ printf(_("path \"%s\" found\n"), fullpath);
+ }
+ }
+
+ if (statbuf.st_ino != bstatp->bs_ino) {
+ fprintf(stderr,
+ _("inode-path for inode: %llu is incorrect - wrong inode#\n"),
+ bstatp->bs_ino);
+ if (verbose_flag) {
+ fprintf(stderr,
+ _("ino mismatch for path \"%s\" %llu vs %llu\n"),
+ fullpath,
+ statbuf.st_ino,
+ bstatp->bs_ino);
+ }
+ err_status++;
+ return;
+ } else if (verbose_flag > 1) {
+ printf(_("inode number match: %llu\n"), statbuf.st_ino);
+ }
+
+ /* get parent path */
+ str = strrchr(fullpath, '/');
+ *str = '\0';
+ sts = stat(fullpath, &statbuf);
+ if (sts != 0) {
+ fprintf(stderr,
+ _("parent path \"%s\" does not stat: %s\n"),
+ fullpath,
+ strerror(errno));
+ err_status++;
+ return;
+ } else {
+ if (parent->p_ino != statbuf.st_ino) {
+ fprintf(stderr,
+ _("inode-path for inode: %llu is incorrect - wrong parent inode#\n"),
+ bstatp->bs_ino);
+ if (verbose_flag) {
+ fprintf(stderr,
+ _("ino mismatch for path \"%s\" %llu vs %llu\n"),
+ fullpath,
+ parent->p_ino,
+ statbuf.st_ino);
+ }
+ err_status++;
+ return;
+ } else {
+ if (verbose_flag > 1) {
+ printf(_("parent ino match for %llu\n"), parent->p_ino);
+ }
+ }
+ }
+}
+
+static void
+check_parents(parent_t *parentbuf, jdm_fshandle_t *fshandlep, xfs_bstat_t *statp, char *mntpt)
+{
+ int error, i;
+ __u32 count, more;
+ parent_t *entryp;
+ parent_cursor_t cursor;
+
+ memset(&cursor, 0, sizeof(cursor));
+ do {
+ error = jdm_getparentpaths(fshandlep,
+ statp,
+ parentbuf,
+ PARENTBUF_SZ,
+ &cursor,
+ &count,
+ &more);
+
+ if (error) {
+ fprintf(stderr, _("getparentpaths failed for ino %llu: %s\n"),
+ statp->bs_ino,
+ strerror(error));
+ err_status++;
+ break;
+ }
+
+ if (count == 0) {
+ /* no links for inode - something wrong here */
+ fprintf(stderr, _("inode-path for inode: %llu is missing\n"), statp->bs_ino);
+ err_status++;
+ break;
+ }
+
+ entryp = parentbuf;
+ for (i = 0; i < count; i++) {
+ check_parent_entry(statp, entryp, mntpt);
+ entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen);
+ }
+
+ } while(more);
+}
+
+static int
+do_bulkstat(parent_t *parentbuf, xfs_bstat_t *bstatbuf,
+ char *mntpt, int fsfd, jdm_fshandle_t *fshandlep)
+{
+ int error;
+ int buflenout;
+ ino64_t lastino = 0;
+ xfs_bstat_t *p;
+ xfs_bstat_t *endp;
+ xfs_fsop_bulkreq_t bulkreq;
+ struct stat mntstat;
+
+ if ((error = stat(mntpt, &mntstat))) {
+ fprintf(stderr, _("can't stat mount point \"%s\": %s\n"),
+ mntpt, strerror(error));
+ return 1;
+ }
+
+ bulkreq.lastip = &lastino;
+ bulkreq.icount = BSTATBUF_SZ;
+ bulkreq.ubuffer = (void *)bstatbuf;
+ bulkreq.ocount = &buflenout;
+
+ while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) {
+ if (*(bulkreq.ocount) == 0) {
+ return 0;
+ }
+ for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) {
+
+ /* inode being modified, get synced data with iget */
+ if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) {
+
+ if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) {
+ fprintf(stderr,
+ _("failed to get bulkstat information for inode %llu\n"),
+ p->bs_ino );
+ continue;
+ }
+ if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) {
+ fprintf(stderr,
+ _("failed to get valid bulkstat information for inode %llu\n"),
+ p->bs_ino );
+ continue;
+ }
+ }
+
+ /* skip root */
+ if (p->bs_ino == mntstat.st_ino) {
+ continue;
+ }
+
+ if (verbose_flag > 1) {
+ printf(_("checking inode %llu\n"), p->bs_ino);
+ }
+
+ /* print dotted progress */
+ if ((inodes_checked % 100) == 0 && verbose_flag == 1) {
+ printf("."); fflush(stdout);
+ }
+ inodes_checked++;
+
+ check_parents(parentbuf, fshandlep, p, mntpt);
+ }
+
+ }/*while*/
+
+ fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno));
+ return 1;
+}
+
+static int
+parent_check(void)
+{
+ static int tab_init;
+ char *mntpt;
+ fs_path_t *fs;
+ int fsfd;
+ jdm_fshandle_t *fshandlep;
+ parent_t *parentbuf;
+ xfs_bstat_t *bstatbuf;
+
+ err_status = 0;
+ inodes_checked = 0;
+
+ sync();
+
+ if (!tab_init) {
+ tab_init = 1;
+ fs_table_initialise();
+ }
+ fs = fs_table_lookup(file->name, FS_MOUNT_POINT);
+ if (!fs) {
+ fprintf(stderr, _("file argument, \"%s\", is not in a mounted XFS filesystem\n"),
+ file->name);
+ return 1;
+ }
+ mntpt = fs->fs_dir;
+ fsfd = file->fd;
+
+ fshandlep = jdm_getfshandle(mntpt);
+ if (fshandlep == 0) {
+ fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"),
+ mntpt,
+ strerror(errno));
+ return 1;
+ }
+
+ /* allocate buffers */
+ bstatbuf = (xfs_bstat_t *)calloc(BSTATBUF_SZ, sizeof(xfs_bstat_t));
+ parentbuf = (parent_t *)malloc(PARENTBUF_SZ);
+ if (!bstatbuf || !parentbuf) {
+ fprintf(stderr, _("unable to allocate buffers: %s\n"),
+ strerror(errno));
+ return 1;
+ }
+
+ if (do_bulkstat(parentbuf, bstatbuf, mntpt, fsfd, fshandlep) != 0)
+ err_status++;
+
+ if (err_status > 0)
+ fprintf(stderr, _("num errors: %d\n"), err_status);
+ else
+ printf(_("succeeded checking %llu inodes\n"), inodes_checked);
+
+ free(bstatbuf);
+ free(parentbuf);
+ return err_status;
+}
+
+static void
+print_parent_entry(parent_t *parent)
+{
+ printf(_("p_ino = %llu\n"), parent->p_ino);
+ printf(_("p_gen = %u\n"), parent->p_gen);
+ printf(_("p_reclen = %u\n"), parent->p_reclen);
+ printf(_("p_name = \"%s\"\n"),parent->p_name);
+}
+
+static int
+parent_list(int fullpath)
+{
+ void *handlep;
+ size_t handlen;
+ int error, i;
+ int retval = 1;
+ __u32 count, more;
+ parent_t *entryp;
+ parent_cursor_t cursor;
+ parent_t *parentbuf;
+ char *path = file->name;
+
+ parentbuf = (parent_t *)malloc(PARENTBUF_SZ);
+ if (!parentbuf) {
+ fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"),
+ progname, strerror(errno));
+ return 1;
+ }
+
+ /* XXXX for linux libhandle version - to set libhandle fsfd cache */
+ {
+ void *fshandle;
+ size_t fshlen;
+
+ if (path_to_fshandle(path, &fshandle, &fshlen) != 0) {
+ fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"),
+ progname, path, strerror(errno));
+ goto error;
+ }
+ }
+
+ if (path_to_handle(path, &handlep, &handlen) != 0) {
+ fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path);
+ goto error;
+ }
+
+ memset(&cursor, 0, sizeof(cursor));
+ do {
+ if (fullpath) {
+ error = getparentpaths_by_handle(handlep,
+ handlen,
+ parentbuf,
+ PARENTBUF_SZ,
+ &cursor,
+ &count,
+ &more);
+ } else {
+ error = getparents_by_handle(handlep,
+ handlen,
+ parentbuf,
+ PARENTBUF_SZ,
+ &cursor,
+ &count,
+ &more);
+ }
+
+ if (error) {
+ fprintf(stderr, _("%s: getparentpaths failed for \"%s\": %s\n"),
+ progname, path, strerror(errno));
+ goto error;
+ }
+
+ if (count == 0) {
+ /* no links for inode - something wrong here */
+ fprintf(stderr, _("%s: inode-path is missing\n"), progname);
+ goto error;
+ }
+
+ entryp = parentbuf;
+ for (i = 0; i < count; i++) {
+ print_parent_entry(entryp);
+ entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen);
+ }
+
+ } while(more);
+
+ retval = 0;
+error:
+ free(parentbuf);
+ return retval;
+}
+
+int
+parent_f(int argc, char **argv)
+{
+ int c;
+ int listpath_flag = 0;
+ int check_flag = 0;
+
+ verbose_flag = 0;
+
+ while ((c = getopt(argc, argv, "cpv")) != EOF) {
+ switch (c) {
+ case 'c':
+ check_flag = 1;
+ break;
+ case 'p':
+ listpath_flag = 1;
+ break;
+ case 'v':
+ verbose_flag++;
+ break;
+ default:
+ return command_usage(&parent_cmd);
+ }
+ }
+
+ if (!check_flag && !listpath_flag) /* default case */
+ exitcode = parent_list(listpath_flag);
+ else {
+ if (listpath_flag)
+ exitcode = parent_list(listpath_flag);
+ if (check_flag)
+ exitcode = parent_check();
+ }
+
+ return 0;
+}
+
+static void
+parent_help(void)
+{
+ printf(_(
+"\n"
+" list the current file's parents and their filenames\n"
+"\n"
+" -c -- check the current file's file system for parent consistency\n"
+" -p -- list the current file's parents and their full paths\n"
+" -v -- verbose mode\n"
+"\n"));
+}
+
+void
+parent_init(void)
+{
+ parent_cmd.name = _("parent");
+ parent_cmd.cfunc = parent_f;
+ parent_cmd.argmin = 0;
+ parent_cmd.argmax = -1;
+ parent_cmd.args = _("[-cpv]");
+ parent_cmd.flags = CMD_NOMAP_OK;
+ parent_cmd.oneline = _("print or check parent inodes");
+ parent_cmd.help = parent_help;
+
+ if (expert)
+ add_command(&parent_cmd);
+}
#include <xfs/xfs.h>
#include <xfs/handle.h>
+#include <xfs/parent.h>
/* just pick a value we know is more than big enough */
#define MAXHANSIZ 64
int flags,
struct attrlist_cursor *cursor)
{
- int fd;
+ int error, fd;
char *path;
xfs_fsop_attrlist_handlereq_t alhreq;
alhreq.buflen = bufsize;
alhreq.buffer = buf;
- return xfsctl(path, fd, XFS_IOC_ATTRLIST_BY_HANDLE, &alhreq);
+ error = xfsctl(path, fd, XFS_IOC_ATTRLIST_BY_HANDLE, &alhreq);
+
+ memcpy(cursor, &alhreq.pos, sizeof(alhreq.pos));
+ return error;
+}
+
+int
+getparents_by_handle(
+ void *hanp,
+ size_t hlen,
+ parent_t *buf,
+ size_t bufsiz,
+ parent_cursor_t *cursor,
+ unsigned int *count,
+ unsigned int *more)
+{
+#if !defined(__sgi__)
+ errno = EOPNOTSUPP;
+ return -1;
+#else
+
+ int error, fd;
+ char *path;
+ xfs_fsop_getparents_handlereq_t gphreq;
+
+ if ((fd = handle_to_fsfd(hanp, &path)) < 0)
+ return -1;
+
+ gphreq.hreq.fd = 0;
+ gphreq.hreq.path = NULL;
+ gphreq.hreq.oflags = O_LARGEFILE;
+ gphreq.hreq.ihandle = hanp;
+ gphreq.hreq.ihandlen = hlen;
+ gphreq.hreq.ohandle = NULL;
+ gphreq.hreq.ohandlen = NULL;
+ memcpy(&gphreq.pos, cursor, sizeof(gphreq.pos));
+ gphreq.buflen = bufsiz;
+ gphreq.buffer = buf;
+ gphreq.ocount = count;
+ gphreq.omore = more;
+
+ error = xfsctl(path, fd, XFS_IOC_GETPARENTS, &gphreq);
+
+ memcpy(cursor, &gphreq.pos, sizeof(gphreq.pos));
+ return error;
+#endif
+}
+
+int
+getparentpaths_by_handle(
+ void *hanp,
+ size_t hlen,
+ parent_t *buf,
+ size_t bufsiz,
+ parent_cursor_t *cursor,
+ unsigned int *count,
+ unsigned int *more)
+{
+#if !defined(__sgi__)
+ errno = EOPNOTSUPP;
+ return -1;
+#else
+ int error, fd;
+ char *path;
+ xfs_fsop_getparents_handlereq_t gphreq;
+
+ if ((fd = handle_to_fsfd(hanp, &path)) < 0)
+ return -1;
+
+ gphreq.hreq.fd = 0;
+ gphreq.hreq.path = NULL;
+ gphreq.hreq.oflags = O_LARGEFILE;
+ gphreq.hreq.ihandle = hanp;
+ gphreq.hreq.ihandlen = hlen;
+ gphreq.hreq.ohandle = NULL;
+ gphreq.hreq.ohandlen = NULL;
+ memcpy(&gphreq.pos, cursor, sizeof(gphreq.pos));
+ gphreq.buflen = bufsiz;
+ gphreq.buffer = buf;
+ gphreq.ocount = count;
+ gphreq.omore = more;
+
+ error = xfsctl(path, fd, XFS_IOC_GETPARENTPATHS, &gphreq);
+
+ memcpy(cursor, &gphreq.pos, sizeof(gphreq.pos));
+ return error;
+#endif
}
int
#include <xfs/xfs.h>
#include <xfs/handle.h>
#include <xfs/jdm.h>
+#include <xfs/parent.h>
/* internal fshandle - typecast to a void for external use */
#define FSHANDLE_SZ 8
bufp, bufsz, flags, cursor);
return rval;
}
+
+int
+jdm_getparents( jdm_fshandle_t *fshp,
+ xfs_bstat_t *statp,
+ parent_t *bufp, size_t bufsz,
+ parent_cursor_t *cursor,
+ unsigned int *count, unsigned int *more)
+{
+#if !defined(__sgi__)
+ errno = EOPNOTSUPP;
+ return -1;
+#else
+ register fshandle_t *fshandlep = ( fshandle_t * )fshp;
+ filehandle_t filehandle;
+
+ jdm_fill_filehandle( &filehandle, fshandlep, statp );
+ return getparents_by_handle (( void * )&filehandle,
+ sizeof( filehandle ),
+ bufp, bufsz, cursor, count, more);
+#endif
+}
+
+int
+jdm_getparentpaths( jdm_fshandle_t *fshp,
+ xfs_bstat_t *statp,
+ parent_t *bufp, size_t bufsz,
+ parent_cursor_t *cursor,
+ unsigned int *count, unsigned int *more)
+{
+#if !defined(__sgi__)
+ errno = EOPNOTSUPP;
+ return -1;
+#else
+ register fshandle_t *fshandlep = ( fshandle_t * )fshp;
+ filehandle_t filehandle;
+
+ jdm_fill_filehandle( &filehandle, fshandlep, statp );
+ return getparentpaths_by_handle (( void * )&filehandle,
+ sizeof( filehandle ),
+ bufp, bufsz, cursor, count, more);
+#endif
+}
.TH HANDLE 3
.SH NAME
-path_to_handle, path_to_fshandle, fd_to_handle, handle_to_fshandle, open_by_handle, readlink_by_handle, attr_multi_by_handle, attr_list_by_handle, fssetdm_by_handle, free_handle \- file handle operations
+path_to_handle, path_to_fshandle, fd_to_handle, handle_to_fshandle, open_by_handle, readlink_by_handle, attr_multi_by_handle, attr_list_by_handle, fssetdm_by_handle, free_handle, getparents_by_handle, getparentpaths_by_handle \- file handle operations
.SH C SYNOPSIS
.nf
.B #include <sys/types.h>
.B " struct fsdmidata *fssetdm);"
.PP
.B "void free_handle (void *hanp, size_t hlen);
+.PP
+.B "int getparents_by_handle(void *hanp, size_t hlen,"
+.B " parent_t *buf, size_t bufsiz,"
+.B " parent_cursor_t *cursor,"
+.B " unsigned int *count, unsigned int *more);"
+.PP
+.B "int getparentpaths_by_handle(void *hanp, size_t hlen,"
+.B " parent_t *buf, size_t bufsiz,"
+.B " parent_cursor_t *cursor,"
+.B " unsigned int *count, unsigned int *more);"
.Op
.SH DESCRIPTION
.PP
\f2fd_to_handle\f1(),
and
\f2handle_to_fshandle\f1().
+.P
+The \f2getparents_by_handle\f1() function returns an array
+of \f2parent_t\f1 structures for each hardlink to
+the inode represented by the given handle. The parent structure
+encodes the parent inode number, generation number and the
+basename of the link.
+This function is not operational on Linux.
+.P
+The \f2getparentpaths_by_handle\f1() function is identical to
+the \f2getparents_by_handle\f1() function except that instead
+of returning the basename it returns the path of the link up
+to the mount point.
+This function is also not operational on Linux.
.SH "SEE ALSO"
open(2),
readlink(2),
\f3statfs\f1
Selected statistics from \f2statfs\f1(2) and the XFS_IOC_FSGEOMETRY
system call on the filesystem where the current file resides.
+.TP
+\f3parent\f1 [ \f2\-cpv\f1 ]
+By default this command prints out the parent inode numbers,
+inode generation numbers and basenames of all the hardlinks which
+point to the inode of the current file.
+If the \f2-p\f1 option is specified, then the output is similar
+to the default output except pathnames up to the mount-point
+are printed out instead of the component name.
+If the \f2-c\f1 option is specified, then the file's filesystem
+will check all the parent attributes for consistency.
+If the \f2-v\f1 option is specified, then verbose output will be
+printed.
+Not currently operational on Linux.
.SH IRIX SEE ALSO
mkfs_xfs(1M),