/*
 * catalog.c - get catalog information
 *
 */

/*
 *    SAM-QFS_notice_begin
 *
 *      Solaris 2.x Sun Storage & Archiving Management File System
 *
 *		Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
 *
 *		U.S. Government Rights - Commercial software. Government users are
 *	subject to the Sun Microsystems, Inc. standard license agreement and applicable
 *	provisions of the FAR and its supplements.
 *
 *      	Use is subject to license terms. Sun, Sun Microsystems and the Sun logo
 *	are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S.
 *	and other countries.
 *
 *    SAM-QFS_notice_end
 */

/*
 *	LGPL NOTICE
 *
 *	This library 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; either
 *	version 2.1 of the License, or (at your option) any later version.
 *
 *	This library is distributed in the hope that it will 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 library; if not, write to the Free Software
 *	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#pragma ident "$Revision$"

static char *_SrcFile = __FILE__;   /* Using __FILE__ makes duplicate strings */


#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

/*
 * SAM-FS public catalog header
 */
#include "pub/catalog.h"
#include "pub/sam_errno.h"

/*
 * SAM-FS headers.
 */
#include "sam/types.h"
#include "sam/custmsg.h"
#include "aml/catalog.h"
#include "aml/catlib.h"

struct catmapping {
	struct CatalogHdr *chp;
	upath_t name;
	int	nopen;
} cat_arr[MAX_CAT] = {
	NULL, "", 0,
	NULL, "", 0,
	NULL, "", 0,
	NULL, "", 0,
	NULL, "", 0
	};

static int first = 1;	/* indicates first catalog open */

int
sam_opencat(
const char *path,
struct sam_cat_tbl *buf,
size_t bufsize)
{
	int	i, size2copy;
	struct sam_cat_tbl tbl;
	struct CatalogHdr *ctp;
	char *media;

	if (path == NULL || buf == NULL || bufsize == 0) {
		errno = EINVAL;
		return (-1);
	}

	if (first) {
		if ((CatalogInit("cat api")) < 0) {
			errno = ER_UNABLE_TO_INIT_CATALOG;
			return (-1);
		}
		first = 0;
	} else {
		/*
		 * check to see if we already have this catalog open
		 */
		for (i = 0; i < MAX_CAT; i++) {
			if (0 != strncmp(cat_arr[i].name, path, sizeof (upath_t))) {
				/*
				 * Already opened and mmapped.
				 */
				cat_arr[i].nopen++;
				ctp = cat_arr[i].chp;
				goto copy;
			}
		}
	}

	/*
	 * Requested catalog not already open.
	 * find first empty array slot.
	 */
	i = 0;
	while ((i < MAX_CAT) && (cat_arr[i].chp != NULL)) i++;
	if (i >= MAX_CAT) {
		errno = ENFILE;
		return (-1);
	}

	/*
	 * get catalog header
	 */
	ctp = CatalogGetCatalogHeader(path);
	if (ctp == NULL) {
		/*
		 * call failed -- errno is set by CatalogGetCatalogHeader
		 */
		return (-1);
	}

	/*
	 * fill in catmapping array entry
	 */
	cat_arr[i].chp = ctp;
	strncpy(cat_arr[i].name, path, sizeof (upath_t));
	cat_arr[i].nopen++;

copy:
	/*
	 * copy fields of catalog table
	 */
	tbl.audit_time = ctp->ChAuditTime;
	tbl.version = ctp->ChVersion;
	tbl.count = ctp->ChNumofEntries;
	media = ctp->ChMediaType;
	tbl.media[0] = *media++;
	tbl.media[1] = *media;
	tbl.media[2] = '\0';

	size2copy = (bufsize <= sizeof (struct sam_cat_tbl)) ? bufsize :
		sizeof (struct sam_cat_tbl);

	memcpy(buf, &tbl, size2copy);

	return (i);
}

int
sam_closecat(
int	cat_handle)	/* catalog file desc. returned by sam_opencat */
{
	int i;

	/*
	 * check entry in array
	 */
	if ((cat_arr[cat_handle].chp == NULL) || (cat_arr[cat_handle].nopen <= 0) ||
			(cat_arr[cat_handle].name[0] == '\0')) {
		errno = EBADF;
		return (-1);
	}

	cat_arr[cat_handle].nopen--;

	if (cat_arr[cat_handle].nopen <= 0) {
		cat_arr[cat_handle].nopen = 0;
		cat_arr[cat_handle].chp = NULL;
		cat_arr[cat_handle].name[0] = '\0';
	}

	/*
	 * If no catalogs open, end all catalog processing
	 */
	for (i = 0; i < MAX_CAT; i++) {
		if (cat_arr[i].nopen) break;
	}

	if (i >= MAX_CAT) {
		/*
		 * none open
		 */
		CatalogTerm();
		first = 1;
	}

	return (0);
}

int
sam_getcatalog(
int	cat_handle,		/* catalog handle returned by sam_opencat */
uint	start_ent,		/* first entry in range to return */
uint	end_ent,		/* last entry in range to return */
struct	sam_cat_ent *buf,	/* ptr to buffer to hold entries returned */
size_t	entbufsize)		/* entry bufsize -- size of a single entry */

{
	int		i, n, size2copy;
	struct CatalogHdr	*ctp;		/* catalog table pointer */
	struct CatalogEntry	*cep;		/* catalog entry pointer */
	struct sam_cat_ent sce;			/* public sam catalog entry */

	/*
	 * check array entry for this fd
	 */
	if ((cat_arr[cat_handle].chp == NULL) || (cat_arr[cat_handle].nopen <= 0)) {
		errno = EBADF;
		return (-1);
	}

	ctp = cat_arr[cat_handle].chp;

	if ((start_ent > end_ent) || (buf == NULL)) {
		errno = EINVAL;
		return (-1);
	}

	n = CatalogGetEntries(ctp->ChEq, start_ent, end_ent, &cep);

	if (n < 0) {
		return (-1);
	}

	if (n > (end_ent - start_ent + 1)) {
		/*
		 * twilight zone -- got more than we asked for
		 */
		errno = EOVERFLOW;
		return (-1);
	}

	size2copy = entbufsize > sizeof (struct sam_cat_ent) ?
	    sizeof (struct sam_cat_ent) : entbufsize;

	for (i = 0; i < n; i++, cep++) {
		memset(&sce, 0, sizeof (struct sam_cat_ent));
		/*
		 * fill in fields for each entry
		 */
		sce.type = 0;	/* type not in catalog 3.5.0 and later */
		sce.status = (uint64_t)cep->CeStatus;
		strncpy(sce.media, cep->CeMtype, 3);
		sce.media[2] = '\0';
		strncpy(sce.vsn, cep->CeVsn, 32);
		sce.vsn[31] = '\0';
		sce.access = (int)cep->CeAccess;
		sce.capacity = (uint_t)cep->CeCapacity;
		sce.space = (uint_t)cep->CeSpace;
		sce.ptoc_fwa = (int)cep->m.CePtocFwa;
		sce.modification_time = cep->CeModTime;
		sce.mount_time = cep->CeMountTime;
		strncpy((char *)sce.bar_code, cep->CeBarCode, BARCODE_LEN + 1);

		/*
		 * copy over, move to the next one
		 */
		memcpy(buf, (char *) &sce, size2copy);
		buf = (struct sam_cat_ent *)(void *)((char *) buf + entbufsize);
	}

	return (n);
}
