pfsallocatefile.c 6.22 KB

/**************************************************************************
 *                                                                        *
 *               Copyright (C) 1995, Silicon Graphics, Inc.               *
 *                                                                        *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright law.  They  may  not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *                                                                        *
 **************************************************************************/

#include <rmon.h>
#include "osint.h"
#include "controller.h"

s32 __osDumpInode(OSPfs *);

s32
osPfsAllocateFile(OSPfs *pfs, u16 company_code, u32 game_code,
	      u8 *game_name, u8 *ext_name, int file_size_in_bytes,
	      s32 *file_no)
{
	int  start_page, decleared, last_page;
	int	old_last_page = 0;
	s32 ret = 0;
	int file_size_in_pages ;
	__OSInode inode, backup_inode;
	__OSDir dir;
	u8 bank;
#ifdef	_PFS_1M_EXTENSION
	u8 startbank;
#endif
	u8 old_bank = 0;
	int firsttime = 0;
	s32 bytes;
	__OSInodeUnit fpage;

	if ((company_code == 0) || (game_code == 0))
		return(PFS_ERR_INVALID);

	file_size_in_pages = 
		(file_size_in_bytes + PFS_PAGE_SIZE -1) / PFS_PAGE_SIZE;

	/* Allocate a file */

	if (((ret = osPfsFindFile(pfs, company_code, game_code, 
	   game_name, ext_name, file_no))!= 0) && (ret != PFS_ERR_INVALID))
		return(ret);
	if (*file_no != -1) 
		/* If the file exists, return PFS_ERR_EXIST */
		return(PFS_ERR_EXIST);

	/* 
	 * Preallocate a file and declare file pages. Files 
	 * are not allow to grow on a write. The pages need to
	 * be decleared on open.
	 */

	ret = osPfsFreeBlocks(pfs, &bytes);
	if (file_size_in_bytes > (int)bytes)
		return(PFS_DATA_FULL);

	if (file_size_in_pages == 0) return(PFS_ERR_INVALID);

	/* get new file id*/
	
	if (((ret = osPfsFindFile(pfs, 0, 0, 0, 0, file_no)) != 0)
	    && (ret != PFS_ERR_INVALID))
	  return(ret);	
	if (*file_no == -1) return(PFS_DIR_FULL);

	/* declear pages */ 

	/* loop through all the banks */
	
#ifdef	_PFS_1M_EXTENSION
	if (pfs->banks < PFS_ID_BANK_1M) {
	  startbank = PFS_ID_BANK_256K;
	} else {
	  startbank = PFS_ID_BANK_1M;
	}
	for (bank = startbank; bank < pfs->banks; bank++) {
#else
	for (bank = PFS_ID_BANK_256K; bank < pfs->banks; bank++) {
#endif
	  if ((ret = __osPfsRWInode(pfs, &inode, PFS_READ, bank)) != 0)
	    return(ret);
	  ret =__osPfsDeclearPage(pfs, &inode, file_size_in_pages,
				  &start_page, bank, &decleared, &last_page);
	  if (ret) return(ret);
	  if (start_page != -1) { 	/* There is free space */
	    if (firsttime == 0) {
	      fpage.inode_t.page = (u8)start_page;
	      fpage.inode_t.bank = bank;
	    } else {			/* Writing previous bank inode */
	      backup_inode.inode_page[old_last_page].inode_t.bank = bank;
	      backup_inode.inode_page[old_last_page].inode_t.page = 
		(u8)start_page;
	      if ((ret = __osPfsRWInode(pfs, &backup_inode, PFS_WRITE,
					old_bank)) != 0)
		return(ret);
	    }
	    if (file_size_in_pages > decleared) {
	      bcopy(&inode, &backup_inode, sizeof(__OSInode));
	      old_last_page = last_page;
	      old_bank = bank;
	      file_size_in_pages -= decleared;
	      firsttime++;
	    } else {
	      file_size_in_pages = 0;
	      if ((ret = __osPfsRWInode(pfs, &inode, PFS_WRITE,	bank)) != 0)
		return(ret);
	      break;
	    }
	  }
	}
	if ((file_size_in_pages > 0) || (start_page == -1))
	  return(PFS_ERR_INCONSISTENT);
		
	/* setup Dir structure */

	dir.start_page = fpage;
	dir.company_code = company_code;
	dir.game_code = game_code;
	dir.data_sum = 0;

	bcopy(game_name, dir.game_name, PFS_FILE_NAME_LEN);
	bcopy(ext_name, dir.ext_name, PFS_FILE_EXT_LEN);

	/* write Dir structure back to Pack */

	ret = __osContRamWrite(pfs->queue, pfs->channel, 
			       (u16)(pfs->dir_table + (int)*file_no),
			       (u8 *)&dir, 0);
	return(ret);
}

s32
__osPfsDeclearPage(OSPfs *pfs, __OSInode *inode, int file_size_in_pages, 
 		   int *first_page, u8 bank, int *decleared, int *last_page)
{
	int j;
	int spage, old_page;
	s32 ret = 0;
	int offset;
	
#ifdef	_PFS_1M_EXTENSION
	offset = ((bank > PFS_ID_BANK_1M) ? 1 : pfs->inode_start_page);
#else
	offset = ((bank > PFS_ID_BANK_256K) ? 1 : pfs->inode_start_page);
#endif
	for (j = offset ; j <PFS_INODE_SIZE_PER_PAGE; j++) {
		if (inode->inode_page[j].ipage == PFS_PAGE_NOT_USED)
			break;
	}
	if (j == PFS_INODE_SIZE_PER_PAGE) {
		*first_page = -1;
		return(ret); 	/* no free page */
	}

	spage = j;
	*decleared = 1;
	old_page = j;
	j++;
	while((file_size_in_pages > *decleared)&& (j<PFS_INODE_SIZE_PER_PAGE)) {
		if (inode->inode_page[j].ipage == PFS_PAGE_NOT_USED) {
			inode->inode_page[old_page].inode_t.bank = (u8)bank;
			inode->inode_page[old_page].inode_t.page = (u8)j;
			old_page = j;
			(*decleared)++;
		}
		j++;
	}
	*first_page = spage;
	if ((j == (PFS_INODE_SIZE_PER_PAGE )) && 
		(file_size_in_pages > *decleared)) {
		*last_page = old_page;
		/* no enough free pages in this bank*/
	} else {
		/* mark the end page */
		inode->inode_page[old_page].ipage = PFS_EOF;	
		*last_page = 0;
	}
	return(ret);
}

#ifdef _DEBUG
s32
__osDumpInode(OSPfs *pfs)
{
	int j;
	__OSInode inode;
	s32 ret = 0;
	__OSDir dir;
	u8 bank, startbank;

#ifdef	_PFS_1M_EXTENSION
	if (pfs->banks < PFS_ID_BANK_1M) {
	  startbank = PFS_ID_BANK_256K;
	} else {
	  startbank = PFS_ID_BANK_1M;
	}
#else
	startbank = PFS_ID_BANK_256K;
#endif
	rmonPrintf("INODE:\n");
	for (bank = startbank; bank < pfs->banks; bank++) {
		rmonPrintf("\nBank %d:\n", bank);
		ret = __osPfsRWInode(pfs, &inode, PFS_READ, bank);
		for (j = 0; j < PFS_INODE_SIZE_PER_PAGE ; j++) {
		rmonPrintf("%x ", inode.inode_page[j].ipage);
		}
	}
	rmonPrintf("dir_size %d %d\n", pfs->dir_size, pfs->inode_start_page);
	for (j = 0; j < pfs->dir_size; j++) {
		__osContRamRead(pfs->queue, pfs->channel,
			(u16)(pfs->dir_table + (int)j), (u8 *)&dir);
			rmonPrintf("file %d game_code %d page %x c_code %d sum %d\n", j, dir.game_code, dir.start_page.ipage, dir.company_code, dir.data_sum);
	}
	rmonPrintf("End of Dump\n");
	return(ret);
}
#endif /* _DEBUG */