/*
 * Copyright (c) 2000-2001 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/jdm.h>

#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>

#include "types.h"
#include "fs.h"
#include "openutil.h"
#include "mlog.h"
#include "global.h"
#include "inventory.h"

static void var_skip_recurse( char *, void ( * )( xfs_ino_t ));
static int  var_create_component( char * );

void
var_create( void )
{
	char path[PATH_MAX];
	char *p;

	p = strcpy( path, XFSDUMP_DIRPATH );
	mlog( MLOG_DEBUG, "creating directory %s\n", path );

	do {
		p++;
		if ( *p == '/' ) {
			*p = '\0';
			if ( ! var_create_component( path ) )
				return;
			*p = '/';
		}
	} while ( *p );

	( void ) var_create_component( path );
}

static int
var_create_component( char *path )
{
	int rval = mkdir( path, 0755 );

	if ( rval && errno != EEXIST ) {
		mlog( MLOG_NORMAL, _("unable to create %s: %s\n"),
		      path, strerror( errno ));
		return 0;
	}
	if ( rval == 0 ) {
		rval = chown( path, 0, 0 );
		if ( rval ) {
			mlog( MLOG_NORMAL, _("unable to chown %s: %s\n"),
			      path, strerror( errno ));
		}
	}
	return 1;
}

void
var_skip( uuid_t *dumped_fsidp, void ( *cb )( xfs_ino_t ino ))
{
	uuid_t fsid;
	intgen_t rval;

	/* see if the fs uuid's match
	 */
	rval = fs_getid( XFSDUMP_DIRPATH, &fsid );
	if ( rval ) {
#ifdef HIDDEN
                /* NOTE: this will happen for non-XFS file systems */
                /*       and is expected, so no msg */
		mlog( MLOG_NORMAL, _(
		      "unable to determine uuid of fs containing %s: "
		      "%s\n"),
		      XFSDUMP_DIRPATH,
		      strerror( errno ));
#endif
		return;
	}

	if ( uuid_compare( *dumped_fsidp, fsid ) != 0) {
		return;
	}

	/* traverse the xfsdump directory, getting inode numbers of it
	 * and all of its children, and reporting those to the callback.
	 */
	var_skip_recurse( XFSDUMP_DIRPATH, cb );
}

static void
var_skip_recurse( char *base, void ( *cb )( xfs_ino_t ino ))
{
	struct stat64 statbuf;
	DIR *dirp;
	struct dirent *direntp;
	intgen_t rval;

	rval = lstat64( base, &statbuf );
	if ( rval ) {
		mlog( MLOG_NORMAL, _(
		      "unable to get status of %s: %s\n"),
		      base,
		      strerror( errno ));
		return;
	}

	mlog( MLOG_DEBUG,
	      "excluding %s from dump\n",
	      base );

	( * cb )( statbuf.st_ino );

	if ( ( statbuf.st_mode & S_IFMT ) != S_IFDIR ) {
		return;
	}

	dirp = opendir( base );
	if ( ! dirp ) {
		mlog( MLOG_NORMAL, _(
		      "unable to open directory %s\n"),
		      base );
		return;
	}

	while ( ( direntp = readdir( dirp )) != NULL ) {
		char *path;

		/* skip "." and ".."
		 */
		if ( *( direntp->d_name + 0 ) == '.'
		     &&
		     ( *( direntp->d_name + 1 ) == 0
		       ||
		       ( *( direntp->d_name + 1 ) == '.'
			 &&
			 *( direntp->d_name + 2 ) == 0 ))) {
			continue;
		}

		path = open_pathalloc( base, direntp->d_name, 0 );
		var_skip_recurse( path, cb );
		free( ( void * )path );
	}

	closedir( dirp );
}
