/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1989-2006 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                   Eduardo Krell <ekrell@adexus.cl>                   *
*                                                                      *
***********************************************************************/
#pragma prototyped

/*
 * Glenn Fowler
 * David Korn
 * Eduardo Krell
 *
 * AT&T Research
 *
 * 3d file system implementation interface
 */

#ifndef _3D_H
#define _3D_H

#undef	_BLD_DEBUG

#if defined(__STDPP__directive) && defined(__STDPP__hide)
__STDPP__directive pragma pp:hide ftruncate mount readlink sbrk truncate utimes __utimes
#else
#define ftruncate	______ftruncate
#define mount		______mount
#define readlink	______readlink
#define sbrk		______sbrk
#define truncate	______truncate
#define utimes		______utimes
#define __utimes	________utimes
#endif

#if defined(__STDPP__directive) && defined(__STDPP__note)
__STDPP__directive pragma pp:note off64_t
#endif

#include <ast_std.h>

#include "lib_3d.h"

#include <ast.h>
#include <ls.h>
#include <int.h>
#include <sig.h>
#include <times.h>
#include <error.h>
#include <debug.h>
#include <hashkey.h>
#include <dlldefs.h>

#if _lib_strerror && defined(strerror)
#undef	strerror
extern char*		strerror();
#endif

#undef	mount
#define mount		______mount
#include <fs3d.h>
#undef	mount

#include "msg.h"

#if defined(__STDPP__directive) && defined(__STDPP__hide)
__STDPP__directive pragma pp:nohide ftruncate mount readlink sbrk truncate utimes __utimes
#else
#undef	ftruncate
#undef	mount
#undef	readlink
#undef	sbrk
#undef	truncate
#undef	utimes
#undef	__utimes
#endif

#if FS && defined(MIX)
#define LICENSED	1
#endif

#if defined(__STDPP__directive) && defined(__STDPP__note)
#if !_typ_off64_t && !noticed(off64_t)
#undef	off64_t
#ifdef _ast_int8_t
#define off64_t		_ast_int8_t
#else
#define off64_t		long
#endif
#endif
#endif

struct stat64;

#undef	fcntl
#undef	open
#undef	stat

#define MSG_read3d	(MSG_read|MSG_EXT(MSG_ARG_number,4))
#define MSG_write3d	(MSG_write|MSG_EXT(MSG_ARG_number,4))

struct Fs;

typedef long (*Sysfunc_t)();

typedef int (*Fs_get_t)(struct Fs*, char*, const char*, int);

typedef int (*Fs_set_t)(struct Fs*, const char*, int, const char*, int);

#define ATTR_MAX	121

#include "FEATURE/peek"
#include "FEATURE/syscall"
#include "FEATURE/syslib"

typedef struct Fs
{
	long		flags;
	short		fd;
	short		retry;
	short		specialsize;
	Fs_get_t	get;
	Fs_set_t	set;
	unsigned long	key;
	unsigned long	ack;
	unsigned long	call;
	unsigned long	terse;
	char		special[10];
	char		attr[ATTR_MAX];
	struct stat	st;
	char*		match;
	char*		service;
	short		matchsize;
	short		servicesize;
} Fs_t;

#if FS

typedef struct Mount
{
	long		channel;
	Fs_t*		fs;
	struct Mount*	global;
	char*		logical;
	char*		physical;
	char		attr[ATTR_MAX];
	short		logicalsize;
	short		physicalsize;
	short		flags;
} Mount_t;

typedef struct
{
	dev_t		dev;
	ino_t		ino;
	char		path[1];
} Dir_t;

#endif

typedef struct
{
#if FS
	Mount_t*	mount;
	Dir_t*		dir;
#endif
	short*		reserved;
	Msg_file_t	id;
	unsigned long	open;
	unsigned char	flags;
	unsigned char	oflag;
} File_t;

#if VCS
#include "vcs_3d.h"
#endif

#define NOSYS		nosys

#define TABLE_FD	(OPEN_MAX>22?22:(OPEN_MAX-1))	/* 0 for env	*/
#define TABLE_MAX	(1<<(TABBITS+7))/* max 3d table image size	*/
#define TABLE_PREFIX	"vpath "	/* for external consistency	*/
#define TABLE_VERSION	1		/* to verify TABLE_FD		*/

#define TABBITS		5	/* max vpath,vmap table index bits (<6)	*/
#define TABSIZE		(1<<TABBITS)			/* v* tab size	*/
#define	VERMODE		(S_IRWXU|S_IRWXG|S_IRWXO)	/* ver dir mode	*/
#define INSTANCE	TABSIZE				/* under ver	*/

#define INTERCEPT_MAX	8		/* max # call intercept layers	*/

#define LICENSE_ALL	'+'		/* everything licensed		*/
#define LICENSE_NONE	'-'		/* nothing licensed		*/
#define LICENSE_SEP	','		/* feature separator		*/

/*
 * File_t flags
 */

#define RESERVED_FD	10		/* reserved fds >= this		*/

#define FILE_CLOEXEC	(1<<0)
#define FILE_ERROR	(1<<1)
#define FILE_LOCK	(1<<2)
#define FILE_OPEN	(1<<3)
#define FILE_REGULAR	(1<<4)
#define FILE_WRITE	(1<<5)
#define FILE_VIRTUAL	(1<<6)

#define FILE_LOCAL	(1<<8)

/*
 * map flags
 */

#define MAP_EXEC	(1<<0)		/* get info for exec		*/
#define MAP_INIT	(1<<1)		/* get info for init		*/

/*
 * Mount_t flags
 */

#define MOUNT_PRIMARY	(1<<0)

/*
 * pathreal() flags
 */

#define P_ABSOLUTE	(1<<0)		/* no relative conversion	*/
#define P_DOTDOT	(1<<1)		/* add /.. to end of path	*/
#define P_LSTAT		(1<<2)		/* lstat() calling		*/
#define P_NOOPAQUE	(1<<3)		/* remove if opaque object	*/
#define P_NOSLASH	(1<<4)		/* remove trailing /'s		*/
#define P_PATHONLY	(1<<5)		/* just canonicalize path	*/
#define P_READLINK	(1<<6)		/* readlink() calling		*/
#define P_SAFE		(1<<7)		/* must be in safe tree		*/
#define P_SLASH		(1<<8)		/* add trailing /		*/
#define P_TOP		(1<<9)		/* copy to top level		*/

#ifndef ENOTEMPTY
#define ENOTEMPTY	EEXIST
#endif

#define T_ALLOCATE	(1<<15)
#define T_PREFIX	(1<<14)
#define T_DELETE	(T_ALLOCATE|T_PREFIX)
#define T_SIZE		(T_PREFIX-1)

#define T_VALSIZE(p)	(((p)->valsize&T_SIZE)?((p)->valsize&T_SIZE):strlen((p)->val))

#define T_MOUNT		(T_SIZE-0)

#define FS_null		0
#define FS_option	1
#define FS_view		2
#define FS_pwd		3
#define FS_fs		4
#define FS_map		5
#define FS_safe		6
#define FS_fd		7
#define FS_intercept	8

#define FS_ACTIVE	(1<<0)
#define FS_BOUND	(1<<1)
#define FS_CLOSE	(1<<2)
#define FS_ERROR	(1<<3)
#define FS_FLUSH	(1<<4)
#define FS_FORK		(1<<5)
#define FS_FS		(1<<6)
#define FS_GLOBAL	(1<<7)
#define FS_INIT		(1<<8)
#define FS_INTERACTIVE	(1<<9)
#define FS_INTERNAL	(1<<10)
#define FS_LICENSED	(1<<11)
#define FS_LOAD		(1<<12)
#define FS_LOCK		(1<<13)
#define FS_MAGIC	(1<<14)
#define FS_MONITOR	(1L<<15)
#define FS_NAME		(1L<<16)
#define FS_ON		(1L<<17)
#define FS_OPEN		(1L<<18)
#define FS_RAW		(1L<<19)
#define FS_RECEIVE	(1L<<20)
#define FS_REFERENCED	(1L<<21)
#define FS_REGULAR	(1L<<22)
#define FS_UNIQUE	(1L<<23)
#define FS_VALIDATED	(1L<<24)
#define FS_WRITE	(1L<<25)

#define FS_LOCAL	(1L<<26)

#define cancel(p)	(*(p)>=RESERVED_FD?(state.file[*(p)].reserved=0,CLOSE(*(p)),*(p)=0):(-1))
#define fsfd(p)		((((p)->flags&(FS_ERROR|FS_ON|FS_OPEN))==(FS_ON|FS_OPEN))?(p)->fd:((((p)->flags&(FS_BOUND|FS_ERROR|FS_INIT|FS_ON))==(FS_BOUND|FS_ON))?fsinit(p,-1):-1))
#define fson(p)		(((p)->flags&(FS_BOUND|FS_ERROR|FS_ON))==(FS_BOUND|FS_ON))
#define initialize()	do { if (!state.pid) init(0,0,0); else if (state.control.note) control(); } while(0)
#define monitored()	((state.path.monitor&&!state.path.mount)?state.path.monitor:(Mount_t*)0)
#define mounted()	((state.path.monitor&&state.path.mount)?state.path.monitor:(Mount_t*)0)
#if _hdr_alloca
#define reclaim()
#else
#define reclaim()	do { if (state.brk.beg) fix(); } while (0)
#endif
#define reserve(p)	((state.file[*(p)].flags|=FILE_LOCK,*(state.file[*(p)].reserved=(p)))<RESERVED_FD?close(*(p)):0)

#if FS
#define fgetmount(f)	((f)>=0&&(f)<=state.cache?state.file[f].mount:(Mount_t*)0)
#define fsmonitored(p)	((state.path.monitor=getmount((p),NiL))&&(state.path.monitor->fs->flags&(FS_ERROR|FS_MONITOR|FS_ON))==(FS_MONITOR|FS_ON))
#define fsmount(p)	(((p)->channel&&(p)->fs->fd)?((p)->channel==-1?-1:(p)->fs->fd):fschannel(p))
#define fssys(p,c)	(fson((p)->fs)&&(((p)->fs->call&MSG_MASK(c))||((p)->fs->flags&FS_GLOBAL)&&(fsmount(p),0)))
#endif

#define var_3d		"__="
#define var_pwd		"PWD="
#define var_shell	"SHELL="
#define var_view	"VPATH="

typedef struct
{
	char*		key;
	char*		val;
	unsigned short	keysize;
	unsigned short	valsize;
} Map_t;

typedef struct
{
	unsigned int	size;
	Map_t		table[TABSIZE];
} Table_t;

typedef struct
{
	int		level;
	int		open_level;
	int		synthesize;
	int		nlinks;
	char*		linkname;
	int		linksize;
#if FS
	Mount_t*	monitor;
#endif
	char*		mount;
	Table_t*	table;
#if VCS && defined(VCS_PATH_STATE)
	VCS_PATH_STATE;
#endif
	struct stat	st;
	char		name[4 * PATH_MAX];
} Path_t;

typedef struct
{
	Fs_t*		fs;
	char*		prefix;
	int		prelen;
} Visit_t;

struct Intercept_s; typedef struct Intercept_s Intercept_t;

typedef long (*Intercept_f)(Intercept_t*, int, int, void*, void*, void*, void*, void*, void*);

struct Intercept_s
{
	Intercept_f		call;
	unsigned long		mask;
};

#if _no_exit_exit
typedef void (*Exitfunc_t)(int);
#endif

typedef struct
{
	/* the first elements are explicitly initialized */

	const char*	id;
	char*		cmd;
	char		dot[2];
	char		null[1];
	char		one[2];
	char*		binsh;
	char		env3d[sizeof(var_3d)];
	char		envpwd[sizeof(var_pwd) + PATH_MAX];
	char		envshell[sizeof(var_shell) + PATH_MAX];
	char		envview[sizeof(var_view)];
	Fs_t		fs[TABSIZE];
	char		vdefault[8];
	char		opaque[8];
	int		limit;

	/* the rest are implicitly initialized */

	struct
	{
	short		monitor;
	short		name;
	}		call;
	struct
	{
	short		fd;
	unsigned long	internal;
	}		channel;
	struct
	{
	int		note;
	int		pathsize;
	char*		path;
	}		control;
#if VCS && defined(VCS_STATE)
	VCS_STATE;
#endif
	int		boundary;
	struct
	{
	char*		beg;
	char*		end;
	}		brk;
	int		cache;
	char**		env;
	char*		envpath;
	void*		freedirp;
	int		in_2d;
	gid_t		gid;
	int		kernel;
	int		level;
	char		license[64];
	int		open;
	pid_t		pid;
	char*		pwd;
	int		pwdsize;
	char		pwdbuf[PATH_MAX];
	long		ret;
	Fs_t*		safe;
	char*		shell;
	uid_t		uid;
	struct
	{
	char*		value;
	char*		invert;
	char*		next;
	int		valsize;
	int		invertsize;
	}		key;
	struct
	{
	short		fd;
	short		version;
	int		size;
	char		buf[TABLE_MAX];
	}		table;
	unsigned long	test;
	struct
	{
	unsigned long	call;
	short		count;
	pid_t		pid;
	}		trace;
	Table_t		vmap;
	Table_t		vmount;
	Table_t		vpath;
	Table_t		vsafe;
	Table_t		vintercept;
	File_t		file[OPEN_MAX];
	Visit_t		visit;
	Path_t		path;
	int		real;
	struct
	{
	int		size;
	Intercept_t	intercept[INTERCEPT_MAX];
	}		trap;
#if _no_exit_exit
	Exitfunc_t	libexit;
#endif
#if FS
	Mount_t*	global;
	Mount_t		mount[2 * TABSIZE];
#endif
} State_t;

#include "std_3d.h"

extern State_t		state;

extern int		bprintf(char**, char*, const char*, ...);
extern ssize_t		bvprintf(char**, char*, const char*, va_list);
extern void		calldump(char**, char*);
extern void		callinit(void);
extern int		checklink(const char*, struct stat*, int);
extern void		control(void);
extern int		fs3d_copy(int, int, struct stat*);
extern int		fs3d_dup(int, int);
extern int		fs3d_mkdir(const char*, mode_t);
extern int		fs3d_open(const char*, int, mode_t);
extern void		fsdrop(Fs_t*, int);
extern int		fsinit(Fs_t*, int);
extern unsigned long	getkey(const char*, const char*, int);
extern int		init(int, const char*, int);
extern int		instance(char*, char*, struct stat*, int);
extern int		iterate(Table_t*, int(*)(Map_t*, char*, int), char*, int);
extern int		keep(const char*, size_t, int);
extern int		mapdump(Table_t*, char*, int);
extern int		mapget(Map_t*, char*, int);
extern int		mapinit(const char*, int);
extern int		mapset(Table_t*, const char*, int, const char*, int);
extern int		nosys(void);
extern char*		pathcanon(char*, int);
extern char*		pathreal(const char*, int, struct stat*);
extern ssize_t		peek(int, void*, size_t);
extern Map_t*		search(Table_t*, const char*, int, const char*, int);
extern Sysfunc_t	sysfunc(int);
extern int		intercept(Intercept_f, unsigned long);

#if FS
extern int		fileinit(int, struct stat*, Mount_t*, int);
extern int		fscall(Mount_t*, long, int, ...);
extern int		fschannel(Mount_t*);
extern char*		fsreal(Mount_t*, long, const char*);
extern int		getattr(const char*, char*);
extern Mount_t*		getmount(const char*, const char**);
extern const char*	setattr(char*, const char*, const char*);
#endif

/*
 * non-standard standards
 */

#if ! _UWIN
extern void*		sbrk(ssize_t);
#endif

/*
 * backwards compatibility fixups
 * these should go away in 94 (ha!)
 */

#if _int_st_spare1
#define NIVIEW(p,v)	((p)->st_spare1=(v))
#else
#if _ary_st_spare4
#define NIVIEW(p,v)	((p)->st_spare4[0]=(v))
#else
#if _ary_st_pad4
#define NIVIEW(p,v)	((p)->st_pad4[0]=(v))
#else
#define NIVIEW(p,v)
#endif
#endif
#endif

#undef	IVIEW

#if _mem_st_rdev_stat
#define IVIEW(p,v)	do{NIVIEW(p,(v)&(INSTANCE-1));if(!S_ISBLK((p)->st_mode)&&!S_ISCHR((p)->st_mode))(p)->st_rdev=(v)&(INSTANCE-1);}while(0)
#else
#define IVIEW(p,v)	NIVIEW(p,(v)&(INSTANCE-1))
#endif

#endif
