/*
adapted from dos.h in the mach dos emulator for the linux dosemu dos
emulator.
Andrew.Tridgell@anu.edu.au 30th March 1993
*/

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

/* definitions to make mach emu code compatible with dosemu */

#define direct dirent
#ifdef __linux__
#define d_namlen d_reclen
#endif

#define MAX_DRIVE 26
#define PRINTER_BASE_DRIVE MAX_DRIVE
#define MAX_PRINTER 9

#define MAX_DRIVES (PRINTER_BASE_DRIVE + MAX_PRINTER + 1)

#define USE_DF_AND_AFS_STUFF

#ifdef __linux__
#define VOLUMELABEL "Linux"
#endif

#define FALSE 0
#define TRUE 1
//#define UNCHANGED 2
#define REDIRECT 3

#define d_Stub(s, a...)   d_printf("MFS: " s, ##a)
#define Debug0(args)		d_Stub args
#define Debug1(args)		d_Stub args

#if 0
typedef struct vm86_regs state_t;
#endif

#define MASK8(x)	((x) & 0xff)
#define MASK16(x)	((x) & 0xffff)
#define HIGH(x)		MASK8((unsigned long)(x) >> 8)
#define LOW(x)		MASK8((unsigned long)(x))
#undef WORD
#define WORD(x)		(unsigned)(uint16_t)(x)
#define SETHIGH(x,y) 	(*(x) = (*(x) & ~0xff00) | ((MASK8(y))<<8))
#define SETLOW(x,y) 	(*(x) = (*(x) & ~0xff) | (MASK8(y)))
#define SETWORD(x,y)	(*(x) = (*(x) & ~0xffff) | (MASK16(y)))

/*
 * Copyright (c) 1991 Carnegie Mellon University
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */
/*
 *
 * Purpose:
 *	V86 DOS disk emulation header file
 *
 * HISTORY:
 *
 * Log: mfs.h,v
 * Revision 1.1  2003/06/23 00:02:08  bartoldeman
 * Initial revision
 *
 * Revision 1.2  1995/05/23  06:04:49  root
 * fix for redirector open existing file function
 *
 * Revision 2.3  1995/04/08  22:33:34  root
 * Release dosemu0.60.0
 *
 * Revision 2.3  1995/04/08  22:33:34  root
 * Release dosemu0.60.0
 *
 * Revision 2.2  1995/02/25  22:38:15  root
 * *** empty log message ***
 *
 * Revision 2.1  1994/06/12  23:15:37  root
 * Wrapping up prior to release of DOSEMU0.52.
 *
 * Revision 2.1  1994/06/12  23:15:37  root
 * Wrapping up prior to release of DOSEMU0.52.
 *
 * Revision 1.7  1994/03/13  01:07:31  root
 * Poor attempt to optimize.
 *
 * Revision 1.6  1994/01/25  20:02:44  root
 * Exchange stderr <-> stdout.
 *
 * Revision 1.5  1994/01/20  21:14:24  root
 * Indent.
 *
 * Revision 1.4  1994/01/19  17:51:14  root
 * Added CDS_FLAG_NOTNET = 0x80 for mfs.c
 *
 * Revision 1.3  1993/12/22  11:45:36  root
 * Fixes for ftruncate
 *
 * Revision 1.2  1993/11/17  22:29:33  root
 * *** empty log message ***
 *
 * Revision 1.1  1993/11/12  12:32:17  root
 * Initial revision
 *
 * Revision 1.1  1993/07/07  00:49:06  root
 * Initial revision
 *
 * Revision 1.3  1993/05/04  05:29:22  root
 * added console switching, new parse commands, and serial emulation
 *
 * Revision 1.2  1993/04/07  21:04:26  root
 * big move
 *
 * Revision 1.1  1993/04/05  17:25:13  root
 * Initial revision
 *
 * Revision 2.3  91/12/06  15:29:23  grm
 * 	Redefined sda_cur_psp, and added psp_parent_psp.  The
 * 	psp_parent_psp was used to find out what the psp of the parent of
 * 	the command.com program was.  It seems that it is undefined.
 * 	[91/12/06            grm]
 *
 * Revision 2.2  91/12/05  16:42:08  grm
 * 	Added sft_rel and _abs_cluster macros.  Used to debug the
 * 	MS-Write network drive problem.
 * 	[91/12/04            grm]
 * 	Added constants for Dos 4+
 * 	[91/07/16  17:47:20  grm]
 *
 * 	Changed to allow for usage with Dos v4.01 and 5.00.
 * 	[91/06/28  18:53:42  grm]
 *
 * 	New Copyright
 * 	[91/05/28  15:12:28  grm]
 *
 * 	Added structures for the dos_general routines.
 * 	[91/04/30  13:43:58  grm]
 *
 * 	Structures and macros for the dos_fs.c
 * 	network redirector interface.
 * 	[91/04/30  13:36:42  grm]
 *
 * 	Name changed from dos_general.h to dos.h.
 * 	Added external declarations for dos_foo.c files.
 * 	[91/03/01  14:40:55  grm]
 *
 * 	Type works.  Interrim changes.
 * 	[91/02/11  18:22:47  grm]
 *
 * 	Fancy dir.
 * 	[91/02/06  16:59:01  grm]
 *
 * 	Created.
 * 	[91/02/06  14:29:39  grm]
 *
 */

#include <sys/types.h>

/*
 * Dos error codes
 */
/* MS-DOS version 2 error codes */
#define FUNC_NUM_INVALID		0x01
#define FILE_NOT_FOUND		0x02
#define PATH_NOT_FOUND		0x03
#define TOO_MANY_OPEN_FILES	0x04
#define ACCESS_DENIED		0x05
#define HANDLE_INVALID		0x06
#define MEM_CB_DEST		0x07
#define INSUF_MEM		0x08
#define MEM_BLK_ADDR_INVALID	0x09
#define ENV_INVALID		0x0a
#define FORMAT_INVALID		0x0b
#define ACCESS_CODE_INVALID	0x0c
#define DATA_INVALID		0x0d
#define UNKNOWN_UNIT		0x0e
#define DISK_DRIVE_INVALID	0x0f
#define ATT_REM_CUR_DIR		0x10
#define NOT_SAME_DEV		0x11
#define NO_MORE_FILES		0x12
/* mappings to critical-error codes */
#define WRITE_PROT_DISK		0x13
#define UNKNOWN_UNIT_CERR	0x14
#define DRIVE_NOT_READY		0x15
#define UNKNOWN_COMMAND		0x16
#define DATA_ERROR_CRC		0x17
#define BAD_REQ_STRUCT_LEN	0x18
#define SEEK_ERROR		0x19
#define UNKNOWN_MEDIA_TYPE	0x1a
#define SECTOR_NOT_FOUND	0x1b
#define PRINTER_OUT_OF_PAPER	0x1c
#define WRITE_FAULT		0x1d
#define READ_FAULT		0x1e
#define GENERAL_FAILURE		0x1f

/* MS-DOS version 3 and later extended error codes */
#define SHARING_VIOLATION	0x20
#define FILE_LOCK_VIOLATION	0x21
#define DISK_CHANGE_INVALID	0x22
#define FCB_UNAVAILABLE		0x23
#define SHARING_BUF_EXCEEDED	0x24

#define NETWORK_NAME_NOT_FOUND	0x35

#define FILE_ALREADY_EXISTS	0x50

#define DUPLICATE_REDIR		0x55

#define CDS_DEFAULT_ROOT_LEN	2

/* Something seems to depend on this structure being no more than 32
   bytes, otherwise dosemu crashes. Why? /MB */
struct dir_ent {
  char name[8];			/* dos name and ext */
  char ext[3];
  char d_name[256];             /* unix name as in readdir */
  u_short mode;			/* unix st_mode value */
  u_short long_path;            /* directory has long path */
  uint64_t size;		/* size of file */
  time_t time;			/* st_mtime */
  int attr;
};

struct dir_list {
  int nr_entries;
  int size;
  struct dir_ent *de;
};

struct dos_name {
  char name[8];
  char ext[3];
};

struct mfs_dirent
{
  const char *d_name;
  const char *d_long_name;
};

struct mfs_dir
{
  DIR *dir;
  struct mfs_dirent de;
  int fd;
  unsigned int nr;
};

#define _sdb_drive_letter(sdb)	(*(u_char  *)&sdb[sdb_drive_letter_off])
#define _sdb_template_name(sdb)	((char     *)&sdb[sdb_template_name_off])
#define _sdb_template_ext(sdb)	((char     *)&sdb[sdb_template_ext_off])
#define	_sdb_attribute(sdb)	(*(u_char  *)&sdb[sdb_attribute_off])
#define _sdb_dir_entry(sdb)	(*(u_short *)&sdb[sdb_dir_entry_off])
#define _sdb_p_cluster(sdb)	(*(u_short *)&sdb[sdb_p_cluster_off])
#define	_sdb_file_name(sdb)	((char     *)&sdb[sdb_file_name_off])
#define	_sdb_file_ext(sdb)	((char     *)&sdb[sdb_file_ext_off])
#define	_sdb_file_attr(sdb)	(*(u_char  *)&sdb[sdb_file_attr_off])
#define	_sdb_file_time(sdb)	(*(u_short *)&sdb[sdb_file_time_off])
#define	_sdb_file_date(sdb)	(*(u_short *)&sdb[sdb_file_date_off])
#define _sdb_file_st_cluster(sdb)(*(u_short *)&sdb[sdb_file_st_cluster_off])
#define _sdb_file_size(sdb)	(*(u_int   *)&sdb[sdb_file_size_off])
#define _sft_handle_cnt(sft) 	(*(u_short *)&sft[sft_handle_cnt_off])
#define _sft_open_mode(sft)  	(*(u_short *)&sft[sft_open_mode_off])
#define _sft_attribute_byte(sft) (*(u_char  *)&sft[sft_attribute_byte_off])
#define _sft_device_info(sft)  	(*(u_short *)&sft[sft_device_info_off])
#define	_sft_dev_drive_ptr(sft)	(*(u_int   *)&sft[sft_dev_drive_ptr_off])
#define	_sft_start_cluster(sft)	(*(u_short *)&sft[sft_start_cluster_off])
#define	_sft_time(sft)		(*(u_short *)&sft[sft_time_off])
#define	_sft_date(sft)		(*(u_short *)&sft[sft_date_off])
#define	_sft_size(sft)		(*(u_int   *)&sft[sft_size_off])
#define	_sft_position(sft)	(*(u_int   *)&sft[sft_position_off])
#define _sft_rel_cluster(sft)	(*(u_short *)&sft[sft_rel_cluster_off])
#define _sft_abs_cluster(sft)	(*(u_short *)&sft[sft_abs_cluster_off])
#define	_sft_directory_sector(sft) (*(u_short *)&sft[sft_directory_sector_off])
#define	_sft_directory_entry(sft)  (*(u_char  *)&sft[sft_directory_entry_off])
#define	_sft_name(sft)		( (char    *)&sft[sft_name_off])
#define	_sft_ext(sft)		( (char    *)&sft[sft_ext_off])
#define	_sft_fd(sft)		(*(u_short *)&sft[sft_fd_off])
#define	_sda_current_dta(sda)	(FARADDR((far_t *)&sda[sda_current_dta_off]))
#define	_sda_error_code(sda)		(*(u_short *)&sda[4])
#define _sda_cur_psp(sda)		(*(u_short *)&sda[sda_cur_psp_off])
#define __sda_cur_drive(sda)		(*(u_char *)&sda[sda_cur_drive_off])
#define _sda_filename1(sda)		((char  *)&sda[sda_filename1_off])
#define	_sda_filename2(sda)		((char  *)&sda[sda_filename2_off])
#define _sda_sdb(sda)			((sdb_t    )&sda[sda_sdb_off])
#define	_sda_cds(sda)		((cds_t)(uintptr_t)(FARPTR((far_t *)&sda[sda_cds_off])))
#define _sda_search_attribute(sda)	(*(u_char *)&sda[sda_search_attribute_off])
#define _sda_open_mode(sda)		(*(u_char *)&sda[sda_open_mode_off])
#define _sda_rename_source(sda)		((sdb_t    )&sda[sda_rename_source_off])
#define _sda_user_stack(sda)		((char *)(uintptr_t)(FARPTR((far_t *)&sda[sda_user_stack_off])))
#define _sda_ext_act(sda)		(*(u_short *)&sda[sda_ext_act_off])
#define _sda_ext_attr(sda)		(*(u_short *)&sda[sda_ext_attr_off])
#define _sda_ext_mode(sda)		(*(u_short *)&sda[sda_ext_mode_off])
#define _psp_parent_psp(psp)		(*(u_short *)&psp[0x16])
#define _psp_handles(psp)		((char *)(uintptr_t)(FARPTR((far_t *)&psp[0x34])))
#define _lol_dpbfarptr(lol)		(rFAR_FARt(READ_DWORD((lol)+lol_dpbfarptr_off)))
#define _lol_cdsfarptr(lol)		(rFAR_FARt(READ_DWORD((lol)+lol_cdsfarptr_off)))
#define _lol_last_drive(lol)		(READ_BYTE((lol)+lol_last_drive_off))
#define _lol_nuldev(lol)		        ((lol)+lol_nuldev_off)
#define _lol_njoined(lol)		((lol)+lol_njoined_off)

#define Addr_8086(x,y)  MK_FP32((x),(y) & 0xffff)
#define FAR(x) (Addr_8086(x.segment, x.offset))
#define FARPTR(x) (Addr_8086((x)->segment, (x)->offset))
#define FARADDR(x) (SEGOFF2LINEAR((x)->segment, (x)->offset))

#define PSPPTR(x) (Addr_8086(x, 0))

struct drive_info
{
  char *root;
  int root_len;
  int options;
  #define read_only(x) (REDIR_CLIENT_SIG_OK(x.options) ? \
    (x.options & REDIR_DEVICE_READ_ONLY) : 0)
  #define cdrom(x) (REDIR_CLIENT_SIG_OK(x.options) ? \
    ((x.options & REDIR_DEVICE_CDROM_MASK) >> 1) : 0)
  #define permanent(x) (REDIR_CLIENT_SIG_OK(x.options) ? \
      (x.options & REDIR_DEVICE_PERMANENT) : 0)
  #define disabled(x) (REDIR_CLIENT_SIG_OK(x.options) ? \
      (x.options & REDIR_DEVICE_DISABLED) : 0)
  uint16_t user_param;
  int saved_cds_flags;
};

extern int mfs_enabled;

/* dos attribute byte flags */
#define REGULAR_FILE 	0x00
#define READ_ONLY_FILE	0x01
#define HIDDEN_FILE	0x02
#define SYSTEM_FILE	0x04
#define VOLUME_LABEL	0x08
#define DIRECTORY	0x10
#define ARCHIVE_NEEDED	0x20
#define DEVICE_FILE	0x40

/* dos access mode constants */
#define READ_ACC	0x00
#define WRITE_ACC	0x01
#define READ_WRITE_ACC	0x02

#define COMPAT_MODE	0x00
#define DENY_ALL	0x01
#define DENY_WRITE	0x02
#define DENY_READ	0x03
#define DENY_NONE	0x04
#define FCB_MODE	0x07

#define CHILD_INHERIT	0x00
#define NO_INHERIT	0x01

extern void build_ufs_path_(char *ufs, const char *path, int drive,
                           int lowercase);
extern int find_file(char *fpath, struct stat *st, int *doserror, int drive);
extern int get_dos_attr(const char *fname, int mode, int drive);
extern int set_fat_attr(int fd,int attr);
extern int set_dos_attr(char *fname, int attr, int drive);
extern int dos_utime(const char *fpath, time_t atime, time_t mtime, int drive);
extern void time_to_dos(time_t clock, u_short *date, u_short *time);
extern time_t time_to_unix(u_short dos_date, u_short dos_time);
extern void extract_filename(const char *filestring0, char *name, char *ext);
extern struct mfs_dir *dos_opendir(const char *name, int drive);
extern struct mfs_dirent *dos_readdir(struct mfs_dir *);
extern int dos_closedir(struct mfs_dir *dir);
extern void get_volume_label(char *fname, char *fext, char *lfn, int drive);
extern int dos_rename_lfn(const char *filename1, const char *filename2, int drive);
extern int dos_unlink_lfn(const char *fpath, int drive);
extern int dos_mkdir(const char *filename, int drive, int lfn);
extern int dos_rmdir(const char *filename, int drive, int lfn);

extern void register_cdrom(int drive, int device);
extern void unregister_cdrom(int drive);
extern int get_volume_label_cdrom(int drive, char *name);
extern int get_drive_from_path(char *path, int *drive);
extern int mfs_stat(const char *path, struct stat *sb, int drive);

/* returns drive number and any bits that are impossible for drive.
 * Should be checked against MAX_DRIVE to make sure it is actually
 * a drive, i.e. no impossible-for-drive bits are set. */
#define SFT_DRIVE(sft) ((sft_device_info(sft) & 0x88bf) ^ 0x8800)

struct file_fd
{
  char *name;
  int idx;
  int fd;
  int type;
  void *shlock;
  void **shemu_locks;  // for share modes emulation
  int mlemu_fds[2];    // for mandatory locks emulation
  struct stat st;
  int is_writable;
  int share_mode;
  u_short psp;
  uint64_t seek;
  uint64_t size;
  int lock_cnt;
};

#define MAX_OPENED_FILES 256
extern struct file_fd open_files[MAX_OPENED_FILES];

void mfs_priv_init(void);
void mfs_late_deinit(void);
void mfs_post_config(void);
