/*
 * The ARAnyM MetaDOS driver.
 *
 * 2002 STan
 *
 * Based on:
 * filesys.h,v 1.8 2001/06/13 20:21:15 fna Exp
 *
 * This file has been modified as part of the FreeMiNT project. See
 * the file Changes.MH for details and dates.
 */

# ifndef _filesys_h
# define _filesys_h

typedef struct proc PROC;

#include "mint/fsops.h"
#include "mint/file.h"
#include "mint/filedesc.h"

struct ucred;

# define DIRSEP(p)	(((p) == '\\') || ((p) == '/'))
# define MAX_LINKS	4
# define follow_links	((char *) -1L)


/*
 * external variables
 */
extern FILESYS *active_fs;
extern FILESYS *drives[NUM_DRIVES];
extern int aliasdrv[NUM_DRIVES];
extern long dosdrvs;


/*
 * exported functions
 */
long getxattr (FILESYS *fs, fcookie *fc, XATTR *xattr);
long getstat64 (FILESYS *fs, fcookie *fc, STAT *ptr);

void kill_cache(fcookie *dir, char *name);
long cache_lookup(fcookie *dir, char *name, fcookie *res);
void cache_init(void);
void clobber_cookie(fcookie *fc);
void init_filesys(void);
char *xfs_name(fcookie *fc);
void xfs_add(FILESYS *fs);
void close_filesys(void);
long _s_ync(void);
long _cdecl sys_s_ync(void);
long _cdecl sys_fsync(short fh);
long _cdecl relpath2cookie(struct proc *p, fcookie *dir, const char *path, char *lastnm,
		    fcookie *res, int depth);
long _cdecl path2cookie(struct proc *p, const char *path, char *lastname, fcookie *res);
void _cdecl release_cookie(fcookie *fc);
void dup_cookie(fcookie *new, fcookie *old);
int _cdecl denyshare(FILEPTR *list, FILEPTR *newfileptr);
int denyaccess(struct ucred *cred, XATTR *, ushort);
LOCK *denylock(ushort pid, LOCK *list, LOCK *newlock);
long dir_access(struct ucred *cred, fcookie *, ushort, ushort *);
int has_wild(const char *name);
void copy8_3(char *dest, const char *src);
int pat_match(const char *name, const char *template);
int samefile(fcookie *, fcookie *);


# ifndef NONBLOCKING_DMA
# define xfs_lock(fs, dev, func)
# define xfs_unlock(fs, dev, func)
# else
# ifdef DEBUG_INFO
# define xfs_lock(fs, dev, func)		\
({						\
	if (!(fs->fsflags & FS_REENTRANT_L2))	\
		xfs_block(fs, dev, func);	\
})
# define xfs_unlock(fs, dev, func)		\
({						\
	if (!(fs->fsflags & FS_REENTRANT_L2))	\
		xfs_deblock(fs, dev, func);	\
})
# else
# define xfs_lock(fs, dev, func)		\
({						\
	if (!(fs->fsflags & FS_REENTRANT_L2))	\
		xfs_block(fs, dev, NULL);	\
})
# define xfs_unlock(fs, dev, func)		\
({						\
	if (!(fs->fsflags & FS_REENTRANT_L2))	\
		xfs_deblock(fs, dev, NULL);	\
})
# endif /* DEBUG_INFO */
# endif

INLINE long
xfs_root(FILESYS *fs, int drv, fcookie *fc)
{
	long r;
	
	xfs_lock(fs, drv, "xfs_root");
	r = (*fs->root)(drv, fc);
	xfs_unlock(fs, drv, "xfs_root");
	
	return r;
}

INLINE long
xfs_lookup(FILESYS *fs, fcookie *dir, const char *name, fcookie *fc)
{
	long r;
	
	xfs_lock(fs, dir->dev, "xfs_lookup");
	r = (*fs->lookup)(dir, name, fc);
	xfs_unlock(fs, dir->dev, "xfs_lokup");
	
	return r;
}

INLINE DEVDRV *
xfs_getdev(FILESYS *fs, fcookie *fc, long *devsp)
{
	return (*fs->getdev)(fc, devsp);
}

INLINE long
xfs_getxattr(FILESYS *fs, fcookie *fc, XATTR *xattr)
{
	if (fs->getxattr)
	{
		long r;
		
		xfs_lock(fs, fc->dev, "xfs_getxattr");
		r = (*fs->getxattr)(fc, xattr);
		xfs_unlock(fs, fc->dev, "xfs_getxattr");
		
		return r;
	}
	
	return getxattr(fs, fc, xattr);
}

INLINE long
xfs_chattr(FILESYS *fs, fcookie *fc, int attr)
{
	long r;
	
	xfs_lock(fs, fc->dev, "xfs_chattr");
	r = (*fs->chattr)(fc, attr);
	xfs_unlock(fs, fc->dev, "xfs_chatr");
	
	return r;
}
INLINE long
xfs_chown(FILESYS *fs, fcookie *fc, int uid, int gid)
{
	long r;
	
	xfs_lock(fs, fc->dev, "xfs_chown");
	r = (*fs->chown)(fc, uid, gid);
	xfs_unlock(fs, fc->dev, "xfs_chown");
	
	return r;
}

INLINE long
xfs_chmode(FILESYS *fs, fcookie *fc, unsigned mode)
{
	long r;
	
	xfs_lock(fs, fc->dev, "xfs_chmod");
	r = (*fs->chmode)(fc, mode);
	xfs_unlock(fs, fc->dev, "xfs_chmod");
	
	return r;
}

INLINE long
xfs_mkdir(FILESYS *fs, fcookie *dir, const char *name, unsigned mode)
{
	long r;
	
	xfs_lock(fs, dir->dev, "xfs_mkdir");
	r = (*fs->mkdir)(dir, name, mode);
	xfs_unlock(fs, dir->dev, "xfs_mkdir");
	
	return r;
}
INLINE long
xfs_rmdir(FILESYS *fs, fcookie *dir, const char *name)
{
	long r;
	
	xfs_lock(fs, dir->dev, "xfs_rmdir");
	r = (*fs->rmdir)(dir, name);
	xfs_unlock(fs, dir->dev, "xfs_rmdir");
	
	return r;
}
INLINE long
xfs_creat(FILESYS *fs, fcookie *dir, const char *name, unsigned mode, int attr, fcookie *fc)
{
	long r;
	
	xfs_lock(fs, dir->dev, "xfs_creat");
	r = (*fs->creat)(dir, name, mode, attr, fc);
	xfs_unlock(fs, dir->dev, "xfs_creat");
	
	return r;
}
INLINE long
xfs_remove(FILESYS *fs, fcookie *dir, const char *name)
{
	long r;
	
	xfs_lock(fs, dir->dev, "xfs_remove");
	r = (*fs->remove)(dir, name);
	xfs_unlock(fs, dir->dev, "xfs_remove");
	
	return r;
}
INLINE long
xfs_getname(FILESYS *fs, fcookie *root, fcookie *dir, char *buf, int len)
{
	long r;
	
	xfs_lock(fs, root->dev, "xfs_getname");
	r = (*fs->getname)(root, dir, buf, len);
	xfs_unlock(fs, root->dev, "xfs_getname");
	
	return r;
}
INLINE long
xfs_rename(FILESYS *fs, fcookie *olddir, char *oldname, fcookie *newdir, const char *newname)
{
	long r;
	
	xfs_lock(fs, olddir->dev, "xfs_rename");
	r = (*fs->rename)(olddir, oldname, newdir, newname);
	xfs_unlock(fs, olddir->dev, "xfs_rename");
	
	return r;
}

INLINE long
xfs_opendir(FILESYS *fs, DIR *dirh, int flags)
{
	long r;
	
	xfs_lock(fs, dirh->fc.dev, "xfs_opendir");
	r = (*fs->opendir)(dirh, flags);
	xfs_unlock(fs, dirh->fc.dev, "xfs_opendir");
	
	return r;
}
INLINE long
xfs_readdir(FILESYS *fs, DIR *dirh, char *nm, int nmlen, fcookie *fc)
{
	long r;
	
	xfs_lock(fs, dirh->fc.dev, "xfs_readdir");
	r = (*fs->readdir)(dirh, nm, nmlen, fc);
	xfs_unlock(fs, dirh->fc.dev, "xfs_readdir");
	
	return r;
}
INLINE long
xfs_rewinddir(FILESYS *fs, DIR *dirh)
{
	long r;
	
	xfs_lock(fs, dirh->fc.dev, "xfs_rewinddir");
	r = (*fs->rewinddir)(dirh);
	xfs_unlock(fs, dirh->fc.dev, "xfs_rwinddir");
	
	return r;
}
INLINE long
xfs_closedir(FILESYS *fs, DIR *dirh)
{
	long r;
	
	xfs_lock(fs, dirh->fc.dev, "xfs_closedir");
	r = (*fs->closedir)(dirh);
	xfs_unlock(fs, dirh->fc.dev, "xfs_closedir");
	
	return r;
}

INLINE long
xfs_pathconf(FILESYS *fs, fcookie *dir, int which)
{
	return (*fs->pathconf)(dir, which);
}
INLINE long
xfs_dfree(FILESYS *fs, fcookie *dir, long *buf)
{
	long r;
	
	xfs_lock(fs, dir->dev, "xfs_dfree");
	r = (*fs->dfree)(dir, buf);
	xfs_unlock(fs, dir->dev, "xfs_dfree");
	
	return r;
}
INLINE long
xfs_writelabel(FILESYS *fs, fcookie *dir, const char *name)
{
	long r;
	
	xfs_lock(fs, dir->dev, "xfs_writelabel");
	r = (*fs->writelabel)(dir, name);
	xfs_unlock(fs, dir->dev, "xfs_writelabel");
	
	return r;
}
INLINE long
xfs_readlabel(FILESYS *fs, fcookie *dir, char *name, int namelen)
{
	long r;
	
	xfs_lock(fs, dir->dev, "xfs_readlabel");
	r = (*fs->readlabel)(dir, name, namelen);
	xfs_unlock(fs, dir->dev, "xfs_readlabel");
	
	return r;
}

INLINE long
xfs_symlink(FILESYS *fs, fcookie *dir, const char *name, const char *to)
{
	long r;
	
	xfs_lock(fs, dir->dev, "xfs_symlink");
	r = (*fs->symlink)(dir, name , to);
	xfs_unlock(fs, dir->dev, "xfs_symlink");
	
	return r;
}
INLINE long
xfs_readlink(FILESYS *fs, fcookie *fc, char *buf, int len)
{
	long r;
	
	xfs_lock(fs, fc->dev, "xfs_readlink");
	r = (*fs->readlink)(fc, buf, len);
	xfs_unlock(fs, fc->dev, "xfs_readlink");
	
	return r;
}
INLINE long
xfs_hardlink(FILESYS *fs, fcookie *fromdir, const char *fromname, fcookie *todir, const char *toname)
{
	long r;
	
	xfs_lock(fs, fromdir->dev, "xfs_hardlink");
	r = (*fs->hardlink)(fromdir, fromname, todir, toname);
	xfs_unlock(fs, fromdir->dev, "xfs_hardlink");
	
	return r;
}
INLINE long
xfs_fscntl(FILESYS *fs, fcookie *dir, const char *name, int cmd, long arg)
{
	long r;
	
	xfs_lock(fs, dir->dev, "xfs_fscntl");
	r = (*fs->fscntl)(dir, name, cmd, arg);
	xfs_unlock(fs, dir->dev, "xfs_fscntl");
	
	return r;
}
INLINE long
xfs_dskchng(FILESYS *fs, int drv, int mode)
{
	long r;
	
	xfs_lock(fs, drv, "xfs_dskchng");
	r = (*fs->dskchng)(drv, mode);
	xfs_unlock(fs, drv, "xfs_dskchng");
	
	return r;
}

INLINE long
xfs_release(FILESYS *fs, fcookie *fc)
{
	return (*fs->release)(fc);
}
INLINE long
xfs_dupcookie(FILESYS *fs, fcookie *dst, fcookie *src)
{
	return (*fs->dupcookie)(dst, src);
}

INLINE long
xfs_mknod(FILESYS *fs, fcookie *dir, const char *name, ulong mode)
{
	long r;
	
	xfs_lock(fs, dir->dev, "xfs_mknod");
	r = (*fs->mknod)(dir, name, mode);
	xfs_unlock(fs, dir->dev, "xfs_mknod");
	
	return r;
}
INLINE long
xfs_unmount(FILESYS *fs, int drv)
{
	long r;
	
	xfs_lock(fs, drv, "xfs_unmount");
	r = (*fs->unmount)(drv);
	xfs_unlock(fs, drv, "xfs_unmount");
	
	return r;
}
INLINE long
xfs_stat64(FILESYS *fs, fcookie *fc, STAT *stat)
{
	if (fs->fsflags & FS_EXT_3)
	{
		long r;
		
		xfs_lock(fs, fc->dev, "xfs_stat64");
		r = (*fs->stat64)(fc, stat);
		xfs_unlock(fs, fc->dev, "xfs_stat64");
		
		return r;
	}
	
	return getstat64(fs, fc, stat);
}


INLINE long
xdd_open(FILEPTR *f)
{
	long r;
	
	xfs_lock(f->fc.fs, f->fc.dev, "xdd_open");
	r = (f->dev->open)(f);
	xfs_unlock(f->fc.fs, f->fc.dev, "xdd_open");
	
	return r;
}
INLINE long
xdd_write(FILEPTR *f, const char *buf, long bytes)
{
	long r;
	
	xfs_lock(f->fc.fs, f->fc.dev, "xdd_write");
	r = (f->dev->write)(f, buf, bytes);
	xfs_unlock(f->fc.fs, f->fc.dev, "xdd_write");
	
	return r;
}
INLINE long
xdd_read(FILEPTR *f, char *buf, long bytes)
{
	long r;
	
	xfs_lock(f->fc.fs, f->fc.dev, "xdd_read");
	r = (f->dev->read)(f, buf, bytes);
	xfs_unlock(f->fc.fs, f->fc.dev, "xdd_read");
	
	return r;
}
INLINE long
xdd_lseek(FILEPTR *f, long where, int whence)
{
	long r;
	
	xfs_lock(f->fc.fs, f->fc.dev, "xdd_lseek");
	r = (f->dev->lseek)(f, where, whence);
	xfs_unlock(f->fc.fs, f->fc.dev, "xdd_lseek");
	
	return r;
}
INLINE long
xdd_ioctl(FILEPTR *f, int mode, void *buf)
{
	long r;
	
	xfs_lock(f->fc.fs, f->fc.dev, "xdd_ioctl");
	r = (f->dev->ioctl)(f, mode, buf);
	xfs_unlock(f->fc.fs, f->fc.dev, "xdd_ioctl");
	
	return r;
}
INLINE long
xdd_datime(FILEPTR *f, ushort *timeptr, int rwflag)
{
	long r;
	
	xfs_lock(f->fc.fs, f->fc.dev, "xdd_datime");
	r = (f->dev->datime)(f, timeptr, rwflag);
	xfs_unlock(f->fc.fs, f->fc.dev, "xdd_datime");
	
	return r;
}
INLINE long
xdd_close(FILEPTR *f, int pid)
{
	long r;
	
	xfs_lock(f->fc.fs, f->fc.dev, "xdd_close");
	r = (f->dev->close)(f, pid);
	xfs_unlock(f->fc.fs, f->fc.dev, "xdd_close");
	
	return r;
}


# endif /* _filesys_h */
