"Fossies" - the Fresh Open Source Software Archive

Member "pcemu/mfs.c" (22 Jan 2001, 100580 Bytes) of package /linux/privat/old/pcemu-1.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mfs.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2 Work started by Tim Bird (tbird@novell.com) 28th October 1993
    3 
    4     
    5     added support for CONTROL_REDIRECTION in dos_fs_redirect.
    6     removed my_drive, and made drive arrays 0-based instead of
    7     first_drive based.
    8 
    9 
   10 This module is a port of the redirector handling in the mach dos
   11 emulator to the linux dos emulator. Started by
   12 Andrew.Tridgell@anu.edu.au on 30th March 1993
   13 
   14 
   15 
   16 version 1.4 12th May 1993
   17 
   18       added a cds_flags check in select_drive so the pointers can
   19       be recalculated when the cds moves. This means you can use the
   20       emufs drive immediately after it installs, even using it to load
   21       other device drivers in config.sys
   22 
   23       fixed the volume label bug, so now volume labels are enabled by default.
   24       We really should do something more useful with them.
   25 
   26       ran "indent" on mfs.c so emacs wouldn't choke in C mode
   27 
   28       did a quick fix for nested finds so they work if the inner find
   29       didn't finish.  I don't think it's quite right yet, probably
   30       find_first/next need to be completely rewritten to get perfect
   31       behaviour, ecially for programs that may try to hack directly with
   32       the search template/directory entry during a find.
   33 
   34       added Roberts patches so the root directory gets printed when initialised
   35 
   36 version 1.3 9th may 1993
   37 
   38       completely revamped find_file() so it can match mixed case names.
   39       This doesn't seem to have cost as much in speed as I thought
   40       it would. This actually involved changes to quite a few routines for
   41       it to work properly.
   42 
   43       added a check for the dos root passed to init_drive - you now get
   44       a "server not ronding" error with a bad path - this is still not good
   45       but's it's better than just accepting it.
   46 
   47 version 1.2 8th may 1993
   48 
   49       made some changes to get_dir() which make the redirector MUCH faster.
   50       It no longer stat's every file when searching for a file. This
   51       is most noticible when you have a long dos path.
   52 
   53       also added profiling. This is supported by profile.c and profile.h.
   54 
   55 version 1.2 7th may 1993
   56 
   57       more changes from Stephen Tweedie to fix the dos root length
   58       stuff, hopefully it will now work equally well with DRDOS and MSDOS.
   59 
   60       also change the way the calculate_dos_pointers() works - it's
   61       now done drive by drive which should be better
   62 
   63       also fixed for MS-DOS 6. It turned out that the problem was that
   64       an earlier speculative dos 6 compatability patch I did managed to get
   65       lost in all the 0.49v? ungrades. re-applying it fixed the problem.
   66       *grumble*. While I was doing that I fixed up non-cds filename finding
   67       (which should never be used anyway as we have a valid cds), and added
   68       a preliminary qualify_filename (which is currently turned off
   69       as it's broken)
   70 
   71 version 1.1 1st May 1993
   72 
   73       incorporated patches from Stephen Tweedie to
   74       fix things for DRDOS and to make the file attribute handling
   75       a lot saner. (thanks Stephen!)
   76 
   77       The main DRDOS change is to handle the fact that filenames appear
   78       to be in <DRIVE><PATH> format rather than <DRIVE>:\<PATH>. Hopefully
   79       the changes will not affect the operation under MS-DOS
   80 
   81 version 1.0 17th April 1993
   82 changes from mach dos emulator version 2.5:
   83 
   84    - changed SEND_FROM_EOF to SEEK_FROM_EOF and added code (untested!)
   85    - added better attribute mapping and set attribute capability
   86    - remove volume label to prevent "dir e:" bug
   87    - made get_attribute return file size
   88    - added multiple drive capability via multiple .sys files in config.sys
   89    - fixed so compatible with devlod so drives can be added on the fly
   90    - allow unix directory to be chosen with command line in config.sys
   91    - changed dos side (.asm) code to only use 1 .sys file (removed
   92      need for mfsini.exe)
   93    - ported linux.asm to use as86 syntax (Robert Sanders did this - thanks!)
   94    - added read-only option on drives
   95    - totally revamped drive selection to match Ralf's interrupt list
   96    - made reads and writes faster by not doing 4096 byte chunks
   97    - masked sigalrm in read and write to prevent crash under NFS
   98    - gave delete_file it's own hlist to prevent clashes with find_next
   99 
  100 TODO:
  101    - fix volume labels
  102    - get filename qualification working properly
  103    - anything else???
  104 
  105 */
  106 
  107 #if !defined(DISABLE_MFS)
  108 
  109 /* ### commented out #ifdef-#else ### */
  110 /* #ifdef linux */
  111 #define DOSEMU 1        /* this is a port to dosemu */
  112 /* #endif */
  113 
  114 #if PROFILE
  115 #include "profile.h"
  116 #else
  117 #define PS(x)
  118 #define PE(x)
  119 #endif
  120 
  121 #undef LITTLE_ENDIAN
  122 
  123 /*
  124  * Copyright (c) 1991 Carnegie Mellon University
  125  * All Rights Reserved.
  126  *
  127  * Permission to use, copy, modify and distribute this software and its
  128  * documentation is hereby granted, provided that both the copyright
  129  * notice and this permission notice appear in all copies of the
  130  * software, derivative works or modified versions, and any portions
  131  * thereof, and that both notices appear in supporting documentation.
  132  *
  133  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  134  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  135  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  136  *
  137  * Carnegie Mellon requests users of this software to return to
  138  *
  139  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  140  *  School of Computer Science
  141  *  Carnegie Mellon University
  142  *  Pittsburgh PA 15213-3890
  143  *
  144  * any improvements or extensions that they make and grant Carnegie Mellon
  145  * the rights to redistribute these changes.
  146  */
  147 /*
  148  *
  149  * Purpose:
  150  *  V86 DOS disk emulation routines
  151  *
  152  * HISTORY:
  153  * $Log: mfs.c,v $
  154  * Revision 1.1.1.1  2001/01/22 01:35:30  michaelh
  155  * Imported.
  156  *
  157  * Revision 1.2  2000/12/13 06:02:41  michaelh
  158  * Made all but mfs compile cleanly.
  159  *
  160  * Revision 1.1.1.1  2000/12/12 06:08:44  michaelh
  161  * Created.
  162  *
  163  * Revision 1.27  1994/03/04  15:23:54  root
  164  * Run through indent.
  165  *
  166  * Revision 1.26  1994/03/04  14:46:13  root
  167  * Volume change by Harald Koenig (koenig@nova.tat.physik.uni-tuebingen.de).
  168  *
  169  * Revision 1.25  1994/02/20  10:00:16  root
  170  * Removed an annoying show_regs();.
  171  *
  172  * Revision 1.24  1994/02/17  20:46:54  root
  173  * Thanks to Jim jwest@master.ceat.okstate.edu for pointing out a bug
  174  * I introduced into function 0x23. I also cleaned up another in the same
  175  * function.
  176  *
  177  * Revision 1.23  1994/02/10  20:41:14  root
  178  * Last cleanup prior to release of pl4.
  179  *
  180  * Revision 1.22  1994/02/10  17:40:26  root
  181  * Another hack for /directory/NUL references.
  182  *
  183  * Revision 1.21  1994/02/05  21:45:55  root
  184  * Changed all references within ssp's from !REG to !LWORD.
  185  *
  186  * Revision 1.20  1994/02/02  21:12:56  root
  187  * More work on pipes.
  188  *
  189  * Revision 1.19  1994/01/31  22:37:10  root
  190  * Partially fix create NEW truncate as opposed to create truncate.
  191  *
  192  * Revision 1.18  1994/01/30  14:29:51  root
  193  * Changed FCB callout for redirector, now inline and works with Create|O_TRUNC.
  194  *
  195  * Revision 1.17  1994/01/30  12:30:23  root
  196  * Changed dos_helper() to int 0xe6 from 0xe5.
  197  *
  198  * Revision 1.16  1994/01/27  21:47:09  root
  199  * Patches from Tim_R_Bird@Novell.COM to allow lredir.exe to run without
  200  * having emufs.sys.
  201  *
  202  * Revision 1.15  1994/01/25  20:02:44  root
  203  * Exchange stderr <-> stdout.
  204  *
  205  * Revision 1.14  1994/01/20  21:14:24  root
  206  * Indent.
  207  *
  208  * Revision 1.13  1994/01/19  17:51:14  root
  209  * Added a 'closer to correct' way of handling O_TRUNC requests.
  210  * Added first attempt at FCB support.
  211  * Added 0x80 flag to tell DOS it's not lanman redirector.
  212  * Added more code to findfirst/next routines, still needs more work!
  213  *
  214  * Revision 1.12  1994/01/12  21:27:15  root
  215  * Update to work with ../NUL device. Also added code to allow
  216  * mfs.c properly deal the GetRedirection with Novell-Lite Printers.
  217  *
  218  * Revision 1.11  1993/12/30  15:11:50  root
  219  * Fixed multiple emufs.sys problem.
  220  *
  221  * Revision 1.10  1993/12/22  12:27:43  root
  222  * Added lredir using environment vars by coosman@asterix.uni-muenster.de
  223  *
  224  * Revision 1.9  1993/12/22  11:45:36  root
  225  * Fixes for ftruncate, now when opening write only, truncate at sft_position
  226  * after first write.
  227  *
  228  * Revision 1.8  1993/12/05  20:59:03  root
  229  * Added ftruncate inplace of close/reopen for O_TRUNC
  230  *
  231  * Revision 1.7  1993/11/30  22:21:03  root
  232  * Final Freeze for release pl3
  233  *
  234  * Revision 1.6  1993/11/30  21:26:44  root
  235  * Chips First set of patches, WOW!
  236  *
  237  * Revision 1.5  1993/11/29  00:05:32  root
  238  * Add code for Open DOS write to Truncate File.
  239  *
  240  * Revision 1.4  1993/11/25  22:45:21  root
  241  * About to destroy keybaord routines.
  242  *
  243  * Revision 1.3  1993/11/23  22:24:53  root
  244  * Truncate file problem
  245  *
  246  * Revision 1.2  1993/11/17  22:29:33  root
  247  * Added \ to CWD returned dir
  248  *
  249  * Revision 1.2  1993/11/08  18:44:40  root
  250  * Added sft_size adjustment when writes extend file size.
  251  * Removed (commented) write 0 cnt to allow DOS creating HOLES via lseek.
  252  * Fixed findfirst/findnext calls that included Volume Label attribute.
  253  *
  254  * Revision 1.1  1993/07/07  00:49:06  root
  255  * Initial revision
  256  *
  257  * Revision 1.3  1993/05/04  05:29:22  root
  258  * added console switching, new parse commands, and serial emulation
  259  *
  260  *
  261  * Revision 2.5  92/05/22  15:59:38  grm
  262  *  Aesthetic change.
  263  *  [92/05/21            grm]
  264  *
  265  * Revision 2.4  92/02/02  23:02:37  rvb
  266  *  Fixed the build_ufs_path problem with '/' as DOSROOT.
  267  *  [92/01/29            grm]
  268  *
  269  * Revision 2.3  91/12/06  15:29:30  grm
  270  *  Added code to find out what the psp of the process which
  271  *  initializes the device drivers in config.sys was.  This seems to
  272  *  be undefined ([sarcasm] surprise surprise :-)).
  273  *  [91/12/06            grm]
  274  *
  275  * Revision 2.2  91/12/05  16:42:23  grm
  276  *  Added some initialization code for relative and absolute cluster
  277  *  offsets within the sft.  Added the debug_dump_sft procedure which
  278  *  dumps out the sft for a given file handle.  Fixed the MS-Write
  279  *  network drive bug by checking if my_drive == the file's
  280  *  sft_device_info's number.  This insidious bug could be the fault
  281  *  of the MS-Write program and not us.  It somehow corrupts it's
  282  *  copy of the file's cds.  This was a nasty one!  Ifdefed out the
  283  *  afs get_disk_space code.
  284  *  [91/12/04            grm]
  285  *  Added support for the DOSROOT functionality.
  286  *  Fixed the set_directory_name so that a trailing
  287  *  backslash wouldn't be the last character except
  288  *  for the root directory in the cds.
  289  *  [91/08/09  19:54:24  grm]
  290  *
  291  *  Corrected the code so that you can use different
  292  *  find_first/next lists.
  293  *  [91/07/16  17:50:46  grm]
  294  *
  295  *  Changed so that can be used with Dos v4.0 and 5.00
  296  *  [91/06/28  18:55:03  grm]
  297  *
  298  *  Initialization fixes.  Several small fixes.
  299  *  [91/06/14  11:57:29  grm]
  300  *
  301  *  New Copyright.  Fixed get_disk_space.
  302  *  [91/05/28  15:16:08  grm]
  303  *
  304  *  Exports lol, cds, and sda to other modules.
  305  *  [91/04/30  13:49:20  grm]
  306  *
  307  *  Works with version 1.1 of machfs.sys and
  308  *  mfsini.exe.  Fixed make_dir.
  309  *  [91/04/30  13:45:51  grm]
  310  *
  311  *  Created.
  312  *  [91/03/26  19:25:05  grm]
  313  *
  314  */
  315 
  316 #if !DOSEMU
  317 #include "base.h"
  318 #include "bios.h"
  319 #endif
  320 
  321 /* ### Added by DH ### */
  322 #include "global.h"
  323 /* ### End of addition ### */
  324 
  325 #include <stdio.h>
  326 #include <sys/file.h>
  327 #include <sys/ioctl.h>
  328 #include <sys/stat.h>
  329 #include <sys/types.h>
  330 #include <sys/time.h>
  331 #include <ctype.h>
  332 #include <errno.h>
  333 #include <sys/param.h>
  334 #include <stdlib.h>
  335 #include <malloc.h>
  336 
  337 #ifdef SOLARIS
  338 #include <fcntl.h>
  339 #include <sys/statvfs.h>
  340 #endif
  341 
  342 #if defined(SGI) || defined(RS6000)
  343 #include <sys/statfs.h>
  344 #else
  345 #include <sys/param.h>
  346 #if defined(BSD) || defined(OSF1)
  347 #include <sys/mount.h>
  348 #else
  349 #include <sys/vfs.h>
  350 #endif
  351 #endif
  352 
  353 
  354 #if !DOSEMU
  355 #include <mach/message.h>
  356 #include <mach/exception.h>
  357 
  358 #include "dos.h"
  359 #else
  360 #include "mfs.h"
  361 
  362 /* ### Commented out by DH ###
  363 *  #include "config.h"
  364 */
  365 /* For passing through GetRedirection Status */
  366 #include "memory.h"
  367 #include <dirent.h>
  368 #include <signal.h>
  369 #include <string.h>
  370 #endif
  371 
  372 
  373 /* these universal globals defined here (externed in dos.h) */
  374 boolean_t mach_fs_enabled = FALSE;
  375 
  376 #define INSTALLATION_CHECK  0x0
  377 #define REMOVE_DIRECTORY    0x1
  378 #define REMOVE_DIRECTORY_2  0x2
  379 #define MAKE_DIRECTORY      0x3
  380 #define MAKE_DIRECTORY_2    0x4
  381 #define SET_CURRENT_DIRECTORY   0x5
  382 #define CLOSE_FILE      0x6
  383 #define COMMIT_FILE     0x7
  384 #define READ_FILE       0x8
  385 #define WRITE_FILE      0x9
  386 #define LOCK_FILE_REGION    0xa
  387 #define UNLOCK_FILE_REGION  0xb
  388 #define GET_DISK_SPACE      0xc
  389 #define SET_FILE_ATTRIBUTES 0xe
  390 #define GET_FILE_ATTRIBUTES 0xf
  391 #define RENAME_FILE     0x11
  392 #define DELETE_FILE     0x13
  393 #define OPEN_EXISTING_FILE  0x16
  394 #define CREATE_TRUNCATE_FILE    0x17
  395 #define CREATE_TRUNCATE_NO_CDS  0x18
  396 #define FIND_FIRST_NO_CDS   0x19
  397 #define FIND_FIRST      0x1b
  398 #define FIND_NEXT       0x1c
  399 #define CLOSE_ALL       0x1d
  400 #define CONTROL_REDIRECT    0x1e
  401 #define PRINTER_SETUP  0x1f
  402 #define FLUSH_ALL_DISK_BUFFERS  0x20
  403 #define SEEK_FROM_EOF       0x21
  404 #define PROCESS_TERMINATED  0x22
  405 #define QUALIFY_FILENAME    0x23
  406 /*#define TURN_OFF_PRINTER   0x24 */
  407 #define MULTIPURPOSE_OPEN   0x2e    /* Used in DOS 4.0+ */
  408 #define PRINTER_MODE  0x25  /* Used in DOS 3.1+ */
  409 /* Used in DOS 4.0+ */
  410 /*#define UNDOCUMENTED_FUNCTION_2 0x25 */
  411 #define EXTENDED_ATTRIBUTES 0x2d/* Used in DOS 4.x */
  412 
  413 #define EOS     '\0'
  414 #define SLASH       '/'
  415 #define BACKSLASH   '\\'
  416 
  417 /* Need to know how many drives are redirected */
  418 u_char redirected_drives = 0;
  419 
  420 /* dos_disk.c */
  421 struct dir_ent *get_dir();
  422 void auspr();
  423 boolean_t dos_fs_dev(state_t *);
  424 
  425 boolean_t drives_initialized = FALSE;
  426 char *dos_roots[MAX_DRIVE];
  427 int dos_root_lens[MAX_DRIVE];
  428 boolean_t read_onlys[MAX_DRIVE];
  429 boolean_t finds_in_progress[MAX_DRIVE];
  430 boolean_t find_in_progress = FALSE;
  431 int current_drive = 0;
  432 u_char first_free_drive = 0;
  433 int num_drives = 0;
  434 int process_mask = 0;
  435 boolean_t read_only = FALSE;
  436 
  437 lol_t lol = NULL;
  438 far_t cdsfarptr;
  439 cds_t cds_base;
  440 cds_t cds;
  441 sda_t sda;
  442 u_short com_psp = (u_short) NULL;
  443 
  444 int dos_major;
  445 int dos_minor;
  446 
  447 char *dos_root = "";
  448 int dos_root_len = 0;
  449 
  450 /* initialize 'em to 3.1 to 3.3 */
  451 
  452 int sdb_drive_letter_off = 0x0;
  453 int sdb_template_name_off = 0x1;
  454 int sdb_template_ext_off = 0x9;
  455 int sdb_attribute_off = 0xc;
  456 int sdb_dir_entry_off = 0xd;
  457 int sdb_p_cluster_off = 0xf;
  458 int sdb_file_name_off = 0x15;
  459 int sdb_file_ext_off = 0x1d;
  460 int sdb_file_attr_off = 0x20;
  461 int sdb_file_time_off = 0x2b;
  462 int sdb_file_date_off = 0x2d;
  463 int sdb_file_st_cluster_off = 0x2f;
  464 int sdb_file_size_off = 0x31;
  465 
  466 int sft_handle_cnt_off = 0x0;
  467 int sft_open_mode_off = 0x2;
  468 int sft_attribute_byte_off = 0x4;
  469 int sft_device_info_off = 0x5;
  470 int sft_dev_drive_ptr_off = 0x7;
  471 int sft_fd_off = 0xb;
  472 int sft_start_cluster_off = 0xb;
  473 int sft_time_off = 0xd;
  474 int sft_date_off = 0xf;
  475 int sft_size_off = 0x11;
  476 int sft_position_off = 0x15;
  477 int sft_rel_cluster_off = 0x19;
  478 int sft_abs_cluster_off = 0x1b;
  479 int sft_directory_sector_off = 0x1d;
  480 int sft_directory_entry_off = 0x1f;
  481 int sft_name_off = 0x20;
  482 int sft_ext_off = 0x28;
  483 
  484 int cds_record_size = 0x51;
  485 int cds_current_path_off = 0x0;
  486 int cds_flags_off = 0x43;
  487 int cds_DBP_pointer_off = 0x45;
  488 int cds_cur_cluster_off = 0x49;
  489 int cds_rootlen_off = 0x4f;
  490 
  491 int sda_current_dta_off = 0xc;
  492 int sda_cur_psp_off = 0x10;
  493 int sda_filename1_off = 0x92;
  494 int sda_filename2_off = 0x112;
  495 int sda_sdb_off = 0x192;
  496 int sda_cds_off = 0x26c;
  497 int sda_search_attribute_off = 0x23a;
  498 int sda_open_mode_off = 0x23b;
  499 int sda_rename_source_off = 0x2b8;
  500 int sda_user_stack_off = 0x250;
  501 
  502 int lol_cdsfarptr_off = 0x16;
  503 int lol_last_drive_off = 0x21;
  504 
  505 /*
  506  * These offsets only meaningful for DOS 4 or greater:
  507  */
  508 int sda_ext_act_off = 0x2dd;
  509 int sda_ext_attr_off = 0x2df;
  510 int sda_ext_mode_off = 0x2e1;
  511 
  512 /* here are the functions used to interface dosemu with the mach
  513 dos redirector code */
  514 
  515 
  516 
  517 #include <sys/types.h>
  518 
  519 
  520 #ifndef MAXNAMLEN
  521 #define MAXNAMLEN 256
  522 #endif
  523 
  524 struct mydirect
  525 {
  526     u_long d_ino;
  527     u_short d_namlen;
  528     char d_name[MAXNAMLEN+1];
  529 };
  530 
  531 
  532 
  533 
  534 struct mydirect *dos_readdir(DIR *);
  535 
  536 #if DOSEMU
  537 int
  538 exchange_uids(void)
  539 {
  540 /* ### Added by DH ### */
  541     
  542 #if !defined(__hpux) && !defined(SOLARIS) && !defined(RS6000)
  543     if (setreuid(geteuid(), getuid()) ||
  544         setregid(getegid(), getgid())) {
  545         error("MFS: Cannot exchange real/effective uid or gid!\n");
  546         return (0);
  547     }
  548     return (1);
  549 #endif
  550 }
  551 
  552 #endif
  553 
  554 /* Try and work out if the current command is for any of my drives */
  555 int
  556 select_drive(state)
  557      state_t *state;
  558 {
  559   int dd;
  560   boolean_t found = 0;
  561   boolean_t check_cds = FALSE;
  562   boolean_t check_dpb = FALSE;
  563   boolean_t check_esdi_cds = FALSE;
  564   boolean_t check_sda_ffn = FALSE;
  565   boolean_t check_always = FALSE;
  566   boolean_t check_dssi_fn = FALSE;
  567 
  568   cds_t sda_cds = sda_cds(sda);
  569   cds_t esdi_cds = (cds_t) Addr(state, es, edi);
  570   sft_t sft = (u_char *) Addr(state, es, edi);
  571   int fn = LOW(state->eax);
  572 
  573 /* ### Next bit changed by DH ### */
  574   cdsfarptr.segment = (lol_cdsfarptr(lol) >> 16) & 0xffff;
  575   cdsfarptr.offset = (lol_cdsfarptr(lol) & 0xffff);
  576 
  577   cds_base = (cds_t) Addr_8086(cdsfarptr.segment, cdsfarptr.offset);
  578 
  579   Debug0((dbg_fd, "selecting drive fn=%x sda_cds=%p\n",
  580       fn, (void *) sda_cds));
  581 
  582   switch (fn) {
  583   case INSTALLATION_CHECK:  /* 0x0 */
  584   case CONTROL_REDIRECT:    /* 0x1e */
  585     check_always = TRUE;
  586     break;
  587   case QUALIFY_FILENAME:    /* 0x23 */
  588     check_dssi_fn = TRUE;
  589     break;
  590   case REMOVE_DIRECTORY:    /* 0x1 */
  591   case REMOVE_DIRECTORY_2:  /* 0x2 */
  592   case MAKE_DIRECTORY:      /* 0x3 */
  593   case MAKE_DIRECTORY_2:    /* 0x4 */
  594   case SET_CURRENT_DIRECTORY:   /* 0x5 */
  595   case SET_FILE_ATTRIBUTES: /* 0xe */
  596   case GET_FILE_ATTRIBUTES: /* 0xf */
  597   case RENAME_FILE:     /* 0x11 */
  598   case DELETE_FILE:     /* 0x13 */
  599   case CREATE_TRUNCATE_FILE:    /* 0x17 */
  600   case FIND_FIRST:      /* 0x1b */
  601     check_cds = TRUE;
  602     break;
  603 
  604   case CLOSE_FILE:      /* 0x6 */
  605   case COMMIT_FILE:     /* 0x7 */
  606   case READ_FILE:       /* 0x8 */
  607   case WRITE_FILE:      /* 0x9 */
  608   case LOCK_FILE_REGION:    /* 0xa */
  609   case UNLOCK_FILE_REGION:  /* 0xb */
  610   case SEEK_FROM_EOF:       /* 0x21 */
  611     check_dpb = TRUE;
  612     break;
  613 
  614   case GET_DISK_SPACE:      /* 0xc */
  615     check_esdi_cds = TRUE;
  616     break;
  617 
  618   case OPEN_EXISTING_FILE:  /* 0x16 */
  619   case MULTIPURPOSE_OPEN:   /* 0x2e */
  620   case FIND_FIRST_NO_CDS:   /* 0x19 */
  621   case CREATE_TRUNCATE_NO_CDS:  /* 0x18 */
  622     check_sda_ffn = TRUE;
  623     break;
  624 
  625   default:
  626     check_cds = TRUE;
  627     break;
  628     /* The rest are unknown - assume check_cds */
  629     /*
  630     case CREATE_TRUNCATE_NO_DIR 0x18
  631     case FIND_NEXT      0x1c
  632     case CLOSE_ALL      0x1d
  633     case FLUSH_ALL_DISK_BUFFERS 0x20
  634     case PROCESS_TERMINATED 0x22
  635     case UNDOCUMENTED_FUNCTION_2    0x25
  636     */
  637   }
  638 
  639   /* re-init the cds stuff for any drive that I think is mine, but
  640     where the cds flags seem to be unset. This allows me to reclaim a
  641     drive in the strange and unnatural case where the cds has moved. */
  642   for (dd = 0; dd < num_drives && !found; dd++)
  643     if (dos_roots[dd] && (cds_flags_r(drive_cds(dd)) &
  644               (CDS_FLAG_REMOTE | CDS_FLAG_READY)) !=
  645     (CDS_FLAG_REMOTE | CDS_FLAG_READY)) {
  646       calculate_drive_pointers(dd);
  647     }
  648 
  649   if (check_always)
  650     found = 1;
  651 
  652   if (!found && check_cds)
  653     for (dd = 0; dd < num_drives && !found; dd++) {
  654       if (!dos_roots[dd])
  655     continue;
  656       if (drive_cds(dd) == sda_cds)
  657     found = 1;
  658     }
  659 
  660   if (!found && check_esdi_cds)
  661     for (dd = 0; dd < num_drives && !found; dd++) {
  662       if (!dos_roots[dd])
  663     continue;
  664       if (drive_cds(dd) == esdi_cds)
  665     found = 1;
  666     }
  667 
  668   if (!found && check_dpb)
  669     for (dd = 0; dd < num_drives && !found; dd++) {
  670       if (!dos_roots[dd])
  671     continue;
  672       if ((sft_device_info_r(sft) & 0x1f) == dd)
  673     found = 1;
  674     }
  675 
  676   if (!found && check_sda_ffn) {
  677     char *fn1 = sda_filename1(sda);
  678 
  679     for (dd = 0; dd < num_drives && !found; dd++) {
  680       if (!dos_roots[dd])
  681     continue;
  682       /* removed ':' check so DRDOS would be happy,
  683          there is a slight worry about possible device name
  684          troubles with this - will PRN ever be interpreted as P:\RN ? */
  685       if ((toupper(fn1[0]) - 'A') == dd)
  686     found = 1;
  687     }
  688   }
  689 
  690   if (!found && check_dssi_fn) {
  691 
  692     char *nametmp;
  693     char *name = (char *) Addr(state, ds, esi);
  694 
  695     nametmp = (char *) malloc(MAXPATHLEN);
  696     strcpy(nametmp, cds_current_path(cds));
  697     Debug0((dbg_fd, "FNX=%.15s\n", name));
  698     for (dd = 0; dd < num_drives && !found; dd++) {
  699       if (!dos_roots[dd])
  700     continue;
  701       if ((toupper(name[0]) - 'A') == dd
  702       && (name[1] == ':' || name[1] == '\\'))
  703     found = 1;
  704     }
  705 
  706     if (found && name[0] == '.' && name[1] == '\\') {
  707       fprintf(stderr, "MFS: ---> %s\n", nametmp);
  708       if (nametmp[2] == '\\')
  709     strcat(nametmp, &name[2]);
  710       else
  711     strcat(nametmp, &name[1]);
  712       strcpy(name, nametmp);
  713       Debug0((dbg_fd, "name changed to %s\n", name));
  714     }
  715 
  716     free(nametmp);
  717   }
  718 
  719   /* for find next we will check the drive letter in the
  720      findfirst block which is in the DTA */
  721   if (!found && fn == FIND_NEXT) {
  722     u_char *dta = (u_char *)sda_current_dta(sda);
  723 
  724     for (dd = 0; dd < num_drives && !found; dd++) {
  725       if (!dos_roots[dd])
  726     continue;
  727       if ((*dta & ~0x80) == dd)
  728     found = 1;
  729     }
  730   }
  731 
  732   if (!found) {
  733     Debug0((dbg_fd, "no drive selected fn=%x\n", fn));
  734     if (fn == 0x1f) {
  735       SETWORD(&(state->ebx), WORD(state->ebx) - redirected_drives);
  736       Debug0((dbg_fd, "Passing %d to PRINTER SETUP anyway\n",
  737           (int) WORD(state->ebx)));
  738     }
  739     return (0);
  740   }
  741 
  742   /* dd is always 1 too large here because of for loop structure above */
  743   current_drive = dd - 1;
  744 
  745   cds = drive_cds(current_drive);
  746   find_in_progress = finds_in_progress[current_drive];
  747   dos_root = dos_roots[current_drive];
  748   dos_root_len = dos_root_lens[current_drive];
  749   read_only = read_onlys[current_drive];
  750 
  751   Debug0((dbg_fd, "selected drive %d: %s\n", current_drive, dos_root));
  752   return (1);
  753 }
  754 
  755 int
  756 get_dos_attr(int mode)
  757 {
  758   int attr = 0;
  759 
  760   if (mode & S_IFDIR)
  761     attr |= DIRECTORY;
  762   if (!(mode & S_IWRITE))
  763     attr |= READ_ONLY_FILE;
  764   if (!(mode & S_IEXEC))
  765     attr |= ARCHIVE_NEEDED;
  766   return (attr);
  767 }
  768 
  769 int
  770 get_unix_attr(int mode, int attr)
  771 {
  772 #define S_IWRITEA (S_IWUSR | S_IWGRP | S_IWOTH)
  773   mode &= ~(S_IFDIR | S_IWRITE | S_IEXEC);
  774   if (attr & DIRECTORY)
  775     mode |= S_IFDIR;
  776   if (!(attr & READ_ONLY_FILE))
  777     mode |= S_IWRITEA;
  778   if (!(attr & ARCHIVE_NEEDED))
  779     mode |= S_IEXEC;
  780   /* Apply current umask to rwx_group and rwx_other permissions */
  781   mode &= ~(process_mask & (S_IRWXG | S_IRWXO));
  782   /* Don't set WG or WO unless corresponding Rx is set! */
  783   mode &= ~(((mode & S_IROTH) ? 0 : S_IWOTH) |
  784         ((mode & S_IRGRP) ? 0 : S_IWGRP));
  785   return (mode);
  786 }
  787 
  788 int
  789 get_disk_space(char *cwd, int *free, int *total)
  790 {
  791 #ifdef SOLARIS
  792     struct statvfs fsbuf;
  793     if (statvfs(cwd, &fsbuf) >= 0)
  794 #else
  795     struct statfs fsbuf;
  796 #ifdef SGI
  797     if (statfs(cwd, &fsbuf, sizeof (struct statfs), 0) >= 0)
  798 #else
  799     if (statfs(cwd, &fsbuf) >= 0)
  800 #endif
  801 #endif
  802     {
  803 #ifdef SGI
  804         *free = fsbuf.f_bsize * fsbuf.f_bfree / 512;
  805 #else
  806         *free = fsbuf.f_bsize * fsbuf.f_bavail / 512;
  807 #endif
  808         *total = fsbuf.f_bsize * fsbuf.f_blocks / 512;
  809         return (1);
  810     }
  811     else
  812         return (0);
  813 }
  814 
  815 void
  816 init_all_drives()
  817 {
  818   int dd;
  819 
  820   if (!drives_initialized) {
  821     drives_initialized = TRUE;
  822     for (dd = 0; dd < MAX_DRIVE; dd++) {
  823       dos_roots[dd] = NULL;
  824       dos_root_lens[dd] = 0;
  825       finds_in_progress[dd] = FALSE;
  826       read_onlys[dd] = FALSE;
  827     }
  828     process_mask = umask(0);
  829     umask(process_mask);
  830   }
  831 }
  832 
  833 /*
  834   *  this routine takes care of things
  835   * like getting environment variables
  836   * and such.  \ is used as an escape character.
  837   * \\ -> \
  838   * \${VAR} -> value of environment variable VAR
  839   * \T -> current tmp directory
  840   *
  841   */
  842 void
  843 get_unix_path(char *new_path, char *path)
  844 {
  845   char str[MAXPATHLEN];
  846   char var[256];
  847   char *orig_path = path;
  848   char *val;
  849   char *tmp_str;
  850   int i;
  851   int esc;
  852   extern char tmpdir[];
  853 
  854   i = 0;
  855   esc = 0;
  856   for (; *path != 0; path++) {
  857       if (esc) {
  858           switch (*path) {
  859           case '\\':        /* really meant a \ */
  860               str[i++] = '\\';
  861               break;
  862           case 'T':     /* the name of the temporary directory */
  863               strncpy(&str[i], tmpdir, MAXPATHLEN - 2 - i);
  864               str[MAXPATHLEN - 2] = 0;
  865               i = strlen(str);
  866               break;
  867           case '$':     /* substitute an environment variable. */
  868               path++;
  869               if (*path != '{') {
  870                   var[0] = *path;
  871                   var[1] = 0;
  872               }
  873               else {
  874                   for (tmp_str = var; *path != 0 && tmp_str != &var[255]; tmp_str++) {
  875                       path++;
  876                       if (*path == '}')
  877                           break;
  878                       *tmp_str = *path;
  879                   }
  880                   *tmp_str = 0;
  881                   val = getenv(var);
  882                   if (val == NULL) {
  883                       Debug0((dbg_fd,
  884                               "In path=%s, Environment Variable $%s is not set.\n",
  885                               orig_path, var));
  886                       break;
  887                   }
  888                   strncpy(&str[i], val, MAXPATHLEN - 2 - i);
  889                   str[MAXPATHLEN - 2] = 0;
  890                   i = strlen(str);
  891                   esc = 0;
  892                   break;
  893               }
  894           }
  895       }
  896       else {
  897           if (*path == '\\') {
  898               esc = 1;
  899           }
  900           else {
  901               str[i++] = *path;
  902           }
  903       }
  904       if (i >= MAXPATHLEN - 2) {
  905           i = MAXPATHLEN - 2;
  906           break;
  907       }
  908   }
  909   if (i == 0 || str[i - 1] != '/')
  910       str[i++] = '/';
  911   str[i] = 0;
  912   strcpy(new_path, str);
  913   Debug0((dbg_fd,
  914           "unix_path returning %s from %s.\n",
  915           new_path, orig_path));
  916   return;
  917 }
  918 
  919 int
  920 init_drive(int dd, char *path, char *options)
  921 {
  922   struct stat st;
  923   char *new_path;
  924 
  925   new_path = malloc(MAXPATHLEN + 1);
  926   if (new_path == NULL) {
  927     Debug0((dbg_fd,
  928         "Out of memory in path %s.\n",
  929         path));
  930     return ((int) NULL);
  931   }
  932   get_unix_path(new_path, path);
  933   Debug0((dbg_fd, "new_path=%s\n", new_path));
  934   dos_roots[dd] = new_path;
  935   dos_root_lens[dd] = strlen(dos_roots[dd]);
  936   Debug0((dbg_fd, "next_aval %d path %s opts %s root %s length %d\n",
  937       dd, path, options, dos_roots[dd], dos_root_lens[dd]));
  938 
  939   /* now a kludge to find the true name of the path */
  940   if (dos_root_lens[dd] != 1) {
  941     boolean_t find_file();
  942 
  943     dos_roots[dd][dos_root_lens[dd] - 1] = 0;
  944     dos_root_len = 1;
  945     dos_root = "/";
  946     if (!find_file(dos_roots[dd], &st)) {
  947       error("MFS ERROR: couldn't find root path %s\n", dos_roots[dd]);
  948       return (0);
  949     }
  950     if (!(st.st_mode & S_IFDIR)) {
  951       error("MFS ERROR: root path is not a directory %s\n", dos_roots[dd]);
  952       return (0);
  953     }
  954     dos_roots[dd][dos_root_lens[dd] - 1] = '/';
  955   }
  956 
  957   if (num_drives <= dd)
  958     num_drives = dd + 1;
  959   read_onlys[dd] = (options && (toupper(options[0]) == 'R'));
  960   Debug0((dbg_fd, "initialised drive %d as %s\n  with access of %s\n", dd, dos_roots[dd],
  961       read_onlys[dd] ? "READ_ONLY" : "READ_WRITE"));
  962   /*
  963   calculate_drive_pointers (dd);
  964 */
  965   return (1);
  966 }
  967 
  968 /***************************
  969  * mfs_redirector - perform redirector emulation for int 2f, ah=11
  970  * on entry - nothing
  971  * on exit - returns non-zero if call was handled
  972  *  returns 0 if call was not handled, and should be passed on.
  973  * notes:
  974  ***************************/
  975 int
  976 mfs_redirector(void)
  977 {
  978   int dos_fs_redirect();
  979   int ret;
  980 
  981 #if DOSEMU
  982   if (!exchange_uids())
  983     return 0;
  984 #endif
  985 
  986   PS(MFS);
  987   ret = dos_fs_redirect(&REGS);
  988   PE(MFS);
  989 
  990 /* ### Added Code = %d to line below ### */
  991   Debug0((dbg_fd, "Finished dos_fs_redirect. Code = %d\n", ret));
  992 
  993   finds_in_progress[current_drive] = find_in_progress;
  994 
  995 #if DOSEMU
  996   exchange_uids();
  997 #endif
  998 
  999   switch (ret) {
 1000   case FALSE:
 1001     REG(eflags) |= CF;
 1002     return 1;
 1003   case TRUE:
 1004     REG(eflags) &= ~CF;
 1005     return 1;
 1006   case UNCHANGED:
 1007     return 1;
 1008   case REDIRECT:
 1009     return 0;
 1010   }
 1011 
 1012   return 0;
 1013 }
 1014 
 1015 int
 1016 mfs_intentry(void)
 1017 {
 1018   boolean_t result;
 1019 
 1020 #if DOSEMU
 1021   if (!exchange_uids())
 1022     return 0;
 1023 #endif
 1024 
 1025   result = dos_fs_dev(&REGS);
 1026 #if DOSEMU
 1027   exchange_uids();
 1028 #endif
 1029   return (result);
 1030 }
 1031 
 1032 /* include a few necessary functions from dos_disk.c in the mach
 1033    code as well */
 1034 boolean_t
 1035 extract_filename(filename, name, ext)
 1036      char *filename;
 1037      char *name;
 1038      char *ext;
 1039 {
 1040   int pos;
 1041   int dec_found;
 1042   boolean_t invalid;
 1043   int end_pos;
 1044   int slen;
 1045   int flen;
 1046 
 1047   pos = 1;
 1048   end_pos = 0;
 1049   dec_found = 0;
 1050   invalid = FALSE;
 1051   while ((pos < 13) && !invalid) {
 1052     char ch = filename[pos];
 1053 
 1054     if (ch == 0) {
 1055       end_pos = pos - 1;
 1056       pos = 20;
 1057       continue;
 1058     }
 1059     if (dec_found) {
 1060       /* are there more than one .'s ? */
 1061       if (ch == '.') {
 1062     invalid = TRUE;
 1063     continue;
 1064       }
 1065       /* is extension > 3 long ? */
 1066       if (pos - dec_found > 3) {
 1067     invalid = TRUE;
 1068     continue;
 1069       }
 1070     }
 1071     else {
 1072       /* is filename > 8 long ? */
 1073       if ((pos > 7) && (ch != '.')) {
 1074     invalid = TRUE;
 1075     continue;
 1076       }
 1077     }
 1078     switch (ch) {
 1079     case '.':
 1080       dec_found = pos;
 1081       break;
 1082     case '"':
 1083     case '/':
 1084     case '\\':
 1085     case '[':
 1086     case ']':
 1087     case ':':
 1088     case '<':
 1089     case '>':
 1090     case '+':
 1091     case '=':
 1092     case ';':
 1093     case ',':
 1094       invalid = TRUE;
 1095       break;
 1096     default:
 1097       break;
 1098     }
 1099     pos++;
 1100   }
 1101   if (invalid)
 1102     return (FALSE);
 1103 
 1104   if ((pos > 11) && (pos != 20))
 1105     return (FALSE);
 1106 
 1107   if (dec_found == 0) {
 1108     slen = end_pos + 1;
 1109   }
 1110   else {
 1111     slen = dec_found;
 1112   }
 1113   strncpy(name, filename, slen);
 1114   if (slen < 8) {
 1115     if ((flen = 8 - slen) > 0)
 1116       strncpy((name + slen), "        ", flen);
 1117   }
 1118 
 1119   if (dec_found) {
 1120     if (end_pos) {
 1121       slen = end_pos - dec_found;
 1122     }
 1123     else {
 1124       slen = 3;
 1125     }
 1126     strncpy(ext, (filename + dec_found + 1), slen);
 1127     if (3 - slen > 0)
 1128       strncpy((ext + slen), "   ", 3 - slen);
 1129   }
 1130   else {
 1131     strncpy(ext, "   ", 3);
 1132   }
 1133 
 1134   for (pos = 0; pos < 8; pos++) {
 1135     char ch = name[pos];
 1136 
 1137     if (isalpha(ch) && islower(ch))
 1138       name[pos] = toupper(ch);
 1139   }
 1140 
 1141   for (pos = 0; pos < 3; pos++) {
 1142     char ch = ext[pos];
 1143 
 1144     if (isalpha(ch) && islower(ch))
 1145       ext[pos] = toupper(ch);
 1146   }
 1147 
 1148   return (TRUE);
 1149 }
 1150 
 1151 struct dir_ent *
 1152 make_entry()
 1153 {
 1154   struct dir_ent *entry;
 1155 
 1156   entry = (struct dir_ent *) malloc(sizeof(struct dir_ent));
 1157 
 1158   entry->next = NULL;
 1159 
 1160   return (entry);
 1161 }
 1162 
 1163 void
 1164 free_list(list)
 1165      struct dir_ent *list;
 1166 {
 1167   struct dir_ent *next;
 1168 
 1169   if (list == NULL)
 1170     return;
 1171 
 1172   while (list->next != NULL) {
 1173     next = list->next;
 1174     free(list);
 1175     list = next;
 1176   }
 1177   free(list);
 1178 }
 1179 
 1180 struct dir_ent *
 1181 _get_dir(char *name, char *mname, char *mext)
 1182 {
 1183   DIR *cur_dir;
 1184   struct mydirect *cur_ent;
 1185   struct dir_ent *dir_list;
 1186   struct dir_ent *entry;
 1187   struct stat sbuf;
 1188   int pos;
 1189   int dec_found;
 1190   boolean_t invalid;
 1191   int end_pos;
 1192   int slen;
 1193   int flen;
 1194   char buf[256];
 1195   char *sptr;
 1196   char fname[8];
 1197   char fext[3];
 1198   boolean_t find_file();
 1199   boolean_t compare();
 1200 
 1201   (void) find_file(name, &sbuf);
 1202 
 1203   if ((cur_dir = opendir(name)) == NULL) {
 1204     extern int errno;
 1205 
 1206     Debug0((dbg_fd, "get_dir(): couldn't open '%s' errno = %s\n", name, strerror(errno)));
 1207     return (NULL);
 1208   }
 1209 
 1210   Debug0((dbg_fd, "get_dir() opened '%s'\n", name));
 1211 
 1212   dir_list = NULL;
 1213   entry = dir_list;
 1214 
 1215 #if 1
 1216   if (strncasecmp(mname, "NUL     ", strlen(mname)) == 0 &&
 1217       strncasecmp(mext, "   ", strlen(mname)) == 0) {
 1218     entry = make_entry();
 1219     dir_list = entry;
 1220     entry->next = NULL;
 1221 
 1222     strncpy(entry->name, mname, 8);
 1223     strncpy(entry->ext, mext, 3);
 1224     entry->mode = S_IFREG;
 1225     entry->size = 0;
 1226     entry->time = 0;
 1227 
 1228     closedir(cur_dir);
 1229     return (dir_list);
 1230   }
 1231   else
 1232 #endif
 1233     while (cur_ent = dos_readdir(cur_dir)) {
 1234       if (cur_ent->d_ino == 0)
 1235     continue;
 1236       if (cur_ent->d_namlen > 13)
 1237     continue;
 1238       if (cur_ent->d_name[0] == '.') {
 1239     if (cur_ent->d_namlen > 2)
 1240       continue;
 1241     if (strncasecmp(name, dos_root, strlen(name)) == 0)
 1242       continue;
 1243     if ((cur_ent->d_namlen == 2) &&
 1244         (cur_ent->d_name[1] != '.'))
 1245       continue;
 1246     strncpy(fname, "..", cur_ent->d_namlen);
 1247     strncpy(fname + cur_ent->d_namlen, "        ",
 1248         8 - cur_ent->d_namlen);
 1249     strncpy(fext, "   ", 3);
 1250       }
 1251       else {
 1252     if (!extract_filename(cur_ent->d_name,
 1253                   fname, fext))
 1254       continue;
 1255     if (mname && mext && !compare(fname, fext, mname, mext))
 1256       continue;
 1257       }
 1258 
 1259       if (entry == NULL) {
 1260     entry = make_entry();
 1261     dir_list = entry;
 1262       }
 1263       else {
 1264     entry->next = make_entry();
 1265     entry = entry->next;
 1266       }
 1267       entry->next = NULL;
 1268 
 1269       strncpy(entry->name, fname, 8);
 1270       strncpy(entry->ext, fext, 3);
 1271 
 1272       strcpy(buf, name);
 1273       slen = strlen(buf);
 1274       sptr = buf + slen + 1;
 1275       buf[slen] = '/';
 1276       strcpy(sptr, cur_ent->d_name);
 1277 
 1278       if (!find_file(buf, &sbuf)) {
 1279     Debug0((dbg_fd, "Can't findfile\n", buf));
 1280     entry->mode = S_IFREG;
 1281     entry->size = 0;
 1282     entry->time = 0;
 1283       }
 1284       else {
 1285     entry->mode = sbuf.st_mode;
 1286     entry->size = sbuf.st_size;
 1287     entry->time = sbuf.st_mtime;
 1288       }
 1289 
 1290     }
 1291   closedir(cur_dir);
 1292   return (dir_list);
 1293 }
 1294 
 1295 struct dir_ent *
 1296 get_dir(char *name, char *fname, char *fext)
 1297 {
 1298   struct dir_ent *r;
 1299 
 1300   PS(GETDIR);
 1301   r = _get_dir(name, fname, fext);
 1302   PE(GETDIR);
 1303   return (r);
 1304 }
 1305 
 1306 /*
 1307  * Another useless specialized parsing routine!
 1308  * Assumes that a legal string is passed in.
 1309  */
 1310 void
 1311 auspr(filestring, name, ext)
 1312      char *filestring;
 1313      char *name;
 1314      char *ext;
 1315 {
 1316   int pos = 0;
 1317   int dot_pos = 0;
 1318   int elen;
 1319 
 1320   Debug1((dbg_fd, "auspr '%s'\n", filestring));
 1321   for (pos = 0;; pos++) {
 1322     if (filestring[pos] == '.') {
 1323       dot_pos = pos;
 1324       continue;
 1325     }
 1326     if (filestring[pos] == '\0')
 1327       break;
 1328   }
 1329 
 1330   if (dot_pos > 0) {
 1331     strncpy(name, filestring, dot_pos);
 1332     if (8 - dot_pos > 0)
 1333       strncpy(name + dot_pos, "        ", 8 - dot_pos);
 1334     elen = pos - dot_pos - 1;
 1335     strncpy(ext, filestring + dot_pos + 1, elen);
 1336     if (3 - elen > 0)
 1337       strncpy(ext + elen, "   ", 3 - elen);
 1338   }
 1339   else {
 1340     strncpy(name, filestring, pos);
 1341     if (8 - pos > 0)
 1342       strncpy(name + pos, "        ", 8 - pos);
 1343     strncpy(ext, "   ", 3);
 1344   }
 1345 
 1346   for (pos = 0; pos < 8; pos++) {
 1347     char ch = name[pos];
 1348 
 1349     if (isalpha(ch) && islower(ch))
 1350       name[pos] = toupper(ch);
 1351   }
 1352 
 1353   for (pos = 0; pos < 3; pos++) {
 1354     char ch = ext[pos];
 1355 
 1356     if (isalpha(ch) && islower(ch))
 1357       ext[pos] = toupper(ch);
 1358   }
 1359 }
 1360 
 1361 void
 1362 init_dos_offsets(ver)
 1363      int ver;
 1364 {
 1365   Debug0((dbg_fd, "dos_fs: using dos version = %d.\n", ver));
 1366   switch (ver) {
 1367   case DOSVER_31_33:
 1368     {
 1369       sdb_drive_letter_off = 0x0;
 1370       sdb_template_name_off = 0x1;
 1371       sdb_template_ext_off = 0x9;
 1372       sdb_attribute_off = 0xc;
 1373       sdb_dir_entry_off = 0xd;
 1374       sdb_p_cluster_off = 0xf;
 1375       sdb_file_name_off = 0x15;
 1376       sdb_file_ext_off = 0x1d;
 1377       sdb_file_attr_off = 0x20;
 1378       sdb_file_time_off = 0x2b;
 1379       sdb_file_date_off = 0x2d;
 1380       sdb_file_st_cluster_off = 0x2f;
 1381       sdb_file_size_off = 0x31;
 1382 
 1383       sft_handle_cnt_off = 0x0;
 1384       sft_open_mode_off = 0x2;
 1385       sft_attribute_byte_off = 0x4;
 1386       sft_device_info_off = 0x5;
 1387       sft_dev_drive_ptr_off = 0x7;
 1388       sft_fd_off = 0xb;
 1389       sft_start_cluster_off = 0xb;
 1390       sft_time_off = 0xd;
 1391       sft_date_off = 0xf;
 1392       sft_size_off = 0x11;
 1393       sft_position_off = 0x15;
 1394       sft_rel_cluster_off = 0x19;
 1395       sft_abs_cluster_off = 0x1b;
 1396       sft_directory_sector_off = 0x1d;
 1397       sft_directory_entry_off = 0x1f;
 1398       sft_name_off = 0x20;
 1399       sft_ext_off = 0x28;
 1400 
 1401       cds_record_size = 0x51;
 1402       cds_current_path_off = 0x0;
 1403       cds_flags_off = 0x43;
 1404       cds_rootlen_off = 0x4f;
 1405 
 1406       sda_current_dta_off = 0xc;
 1407       sda_cur_psp_off = 0x10;
 1408       sda_filename1_off = 0x92;
 1409       sda_filename2_off = 0x112;
 1410       sda_sdb_off = 0x192;
 1411       sda_cds_off = 0x26c;
 1412       sda_search_attribute_off = 0x23a;
 1413       sda_open_mode_off = 0x23b;
 1414       sda_rename_source_off = 0x2b8;
 1415       sda_user_stack_off = 0x250;
 1416 
 1417       lol_cdsfarptr_off = 0x16;
 1418       lol_last_drive_off = 0x21;
 1419       break;
 1420     }
 1421   case DOSVER_50:
 1422   case DOSVER_41:
 1423     {
 1424       sdb_drive_letter_off = 0x0;
 1425       sdb_template_name_off = 0x1;
 1426       sdb_template_ext_off = 0x9;
 1427       sdb_attribute_off = 0xc;
 1428       sdb_dir_entry_off = 0xd;
 1429       sdb_p_cluster_off = 0xf;
 1430       sdb_file_name_off = 0x15;
 1431       sdb_file_ext_off = 0x1d;
 1432       sdb_file_attr_off = 0x20;
 1433       sdb_file_time_off = 0x2b;
 1434       sdb_file_date_off = 0x2d;
 1435       sdb_file_st_cluster_off = 0x2f;
 1436       sdb_file_size_off = 0x31;
 1437 
 1438       /* same */ sft_handle_cnt_off = 0x0;
 1439       sft_open_mode_off = 0x2;
 1440       sft_attribute_byte_off = 0x4;
 1441       sft_device_info_off = 0x5;
 1442       sft_dev_drive_ptr_off = 0x7;
 1443       sft_fd_off = 0xb;
 1444       sft_start_cluster_off = 0xb;
 1445       sft_time_off = 0xd;
 1446       sft_date_off = 0xf;
 1447       sft_size_off = 0x11;
 1448       sft_position_off = 0x15;
 1449       sft_rel_cluster_off = 0x19;
 1450       sft_abs_cluster_off = 0x1b;
 1451       sft_directory_sector_off = 0x1d;
 1452       sft_directory_entry_off = 0x1f;
 1453       sft_name_off = 0x20;
 1454       sft_ext_off = 0x28;
 1455 
 1456       /* done */ cds_record_size = 0x58;
 1457       cds_current_path_off = 0x0;
 1458       cds_flags_off = 0x43;
 1459       cds_rootlen_off = 0x4f;
 1460 
 1461       /* done */ sda_current_dta_off = 0xc;
 1462       sda_cur_psp_off = 0x10;
 1463       sda_filename1_off = 0x9e;
 1464       sda_filename2_off = 0x11e;
 1465       sda_sdb_off = 0x19e;
 1466       sda_cds_off = 0x282;
 1467       sda_search_attribute_off = 0x24d;
 1468       sda_open_mode_off = 0x24e;
 1469       sda_ext_act_off = 0x2dd;
 1470       sda_ext_attr_off = 0x2df;
 1471       sda_ext_mode_off = 0x2e1;
 1472       sda_rename_source_off = 0x300;
 1473       sda_user_stack_off = 0x264;
 1474 
 1475       /* same */ lol_cdsfarptr_off = 0x16;
 1476       lol_last_drive_off = 0x21;
 1477 
 1478       break;
 1479     }
 1480     /* at the moment dos 6 is the same as dos 5,
 1481      anyone care to fix these for dos 6 ?? */
 1482   case DOSVER_60:
 1483   default:
 1484     {
 1485       sdb_drive_letter_off = 0x0;
 1486       sdb_template_name_off = 0x1;
 1487       sdb_template_ext_off = 0x9;
 1488       sdb_attribute_off = 0xc;
 1489       sdb_dir_entry_off = 0xd;
 1490       sdb_p_cluster_off = 0xf;
 1491       sdb_file_name_off = 0x15;
 1492       sdb_file_ext_off = 0x1d;
 1493       sdb_file_attr_off = 0x20;
 1494       sdb_file_time_off = 0x2b;
 1495       sdb_file_date_off = 0x2d;
 1496       sdb_file_st_cluster_off = 0x2f;
 1497       sdb_file_size_off = 0x31;
 1498 
 1499       /* same */ sft_handle_cnt_off = 0x0;
 1500       sft_open_mode_off = 0x2;
 1501       sft_attribute_byte_off = 0x4;
 1502       sft_device_info_off = 0x5;
 1503       sft_dev_drive_ptr_off = 0x7;
 1504       sft_fd_off = 0xb;
 1505       sft_start_cluster_off = 0xb;
 1506       sft_time_off = 0xd;
 1507       sft_date_off = 0xf;
 1508       sft_size_off = 0x11;
 1509       sft_position_off = 0x15;
 1510       sft_rel_cluster_off = 0x19;
 1511       sft_abs_cluster_off = 0x1b;
 1512       sft_directory_sector_off = 0x1d;
 1513       sft_directory_entry_off = 0x1f;
 1514       sft_name_off = 0x20;
 1515       sft_ext_off = 0x28;
 1516 
 1517       /* done */ cds_record_size = 0x58;
 1518       cds_current_path_off = 0x0;
 1519       cds_flags_off = 0x43;
 1520       cds_rootlen_off = 0x4f;
 1521 
 1522       /* done */ sda_current_dta_off = 0xc;
 1523       sda_cur_psp_off = 0x10;
 1524       sda_filename1_off = 0x9e;
 1525       sda_filename2_off = 0x11e;
 1526       sda_sdb_off = 0x19e;
 1527       sda_cds_off = 0x282;
 1528       sda_search_attribute_off = 0x24d;
 1529       sda_open_mode_off = 0x24e;
 1530       sda_ext_act_off = 0x2dd;
 1531       sda_ext_attr_off = 0x2df;
 1532       sda_ext_mode_off = 0x2e1;
 1533       sda_rename_source_off = 0x300;
 1534       sda_user_stack_off = 0x264;
 1535 
 1536       /* same */ lol_cdsfarptr_off = 0x16;
 1537       lol_last_drive_off = 0x21;
 1538 
 1539       break;
 1540     }
 1541   }
 1542 }
 1543 
 1544 void
 1545 init_dos_side()
 1546 {
 1547   mach_fs_enabled = TRUE;
 1548 }
 1549 
 1550 struct mydirect *
 1551 dos_readdir(dir)
 1552      DIR *dir;
 1553 {
 1554     static struct mydirect retdir;
 1555     struct dirent *ret;
 1556     sigset_t newmask, oldmask;
 1557     
 1558 #if DOSEMU
 1559     sigfillset(&newmask);
 1560     
 1561     /* temporarily block our alarms so NFS reads don't choke */
 1562     sigprocmask(SIG_SETMASK, &newmask, &oldmask);
 1563 #endif
 1564 
 1565     ret = readdir(dir);
 1566 
 1567     if (ret)
 1568     {
 1569         retdir.d_ino = ret->d_ino;
 1570         retdir.d_namlen = strlen(ret->d_name);
 1571         strncpy(retdir.d_name,  ret->d_name, sizeof retdir.d_name);
 1572 
 1573 #if DOSEMU
 1574         /* restore the blocked alarm */
 1575         sigprocmask(SIG_SETMASK, &oldmask, NULL);
 1576 #endif
 1577         
 1578         return (&retdir);
 1579     }
 1580 
 1581 #if DOSEMU
 1582   /* restore the blocked alarm */
 1583   sigprocmask(SIG_SETMASK, &oldmask, NULL);
 1584 #endif
 1585 
 1586   return NULL;
 1587 }
 1588 
 1589 int
 1590 dos_read(fd, data, cnt)
 1591      int fd;
 1592      char *data;
 1593      int cnt;
 1594 {
 1595   int ret;
 1596   sigset_t newmask, oldmask;
 1597 
 1598   if (cnt <= 0)
 1599     return (0);
 1600 
 1601 #if DOSEMU
 1602   sigfillset(&newmask);
 1603 
 1604   /* temporarily block our alarms so NFS reads don't choke */
 1605   sigprocmask(SIG_SETMASK, &newmask, &oldmask);
 1606 #endif
 1607 
 1608   ret = read(fd, data, cnt);
 1609 
 1610 #if DOSEMU
 1611   /* restore the blocked alarm */
 1612   sigprocmask(SIG_SETMASK, &oldmask, NULL);
 1613 #endif
 1614 
 1615   return (ret);
 1616 }
 1617 
 1618 int
 1619 dos_write(fd, data, cnt)
 1620      int fd;
 1621      char *data;
 1622      int cnt;
 1623 {
 1624   int ret;
 1625   sigset_t oldmask, newmask;
 1626 
 1627   if (cnt <= 0)
 1628     return (0);
 1629 
 1630 #if DOSEMU
 1631   sigfillset(&newmask);
 1632 
 1633   /* temporarily block our alarms so NFS reads don't choke */
 1634   sigprocmask(SIG_SETMASK, &newmask, &oldmask);
 1635 #endif
 1636 
 1637   ret = write(fd, data, cnt);
 1638 
 1639   Debug0((dbg_fd, "Wrote %10.10s\n", data));
 1640 
 1641 #if DOSEMU
 1642   /* restore the blocked alarm */
 1643   sigprocmask(SIG_SETMASK, &oldmask, NULL);
 1644 #endif
 1645 
 1646   return (ret);
 1647 }
 1648 
 1649 int
 1650 calculate_drive_pointers(int dd)
 1651 {
 1652   far_t cdsfarptr;
 1653   char *cwd;
 1654   cds_t cds_base;
 1655 
 1656   if (!lol)
 1657     return (0);
 1658   if (!dos_roots[dd])
 1659     return (0);
 1660 
 1661 /* ### Next bit changed by DH ### */
 1662   cdsfarptr.segment = (lol_cdsfarptr(lol) >> 16) & 0xffff;
 1663   cdsfarptr.offset = (lol_cdsfarptr(lol) & 0xffff);
 1664 
 1665   cds_base = (cds_t) Addr_8086(cdsfarptr.segment, cdsfarptr.offset);
 1666 
 1667   cds = drive_cds(dd);
 1668 
 1669   /* if it's already done then don't bother */
 1670   if ((cds_flags_r(cds) & (CDS_FLAG_REMOTE | CDS_FLAG_READY)) ==
 1671       (CDS_FLAG_REMOTE | CDS_FLAG_READY))
 1672     return (1);
 1673 
 1674   Debug0((dbg_fd, "Calculated DOS Information for %d:\n", dd));
 1675   Debug0((dbg_fd, "  cwd=%20s\n", cds_current_path(cds)));
 1676   Debug0((dbg_fd, "  cds flags =%x\n", cds_flags_r(cds)));
 1677   Debug0((dbg_fd, "  cdsfar = %x, %x\n", cdsfarptr.segment,
 1678       cdsfarptr.offset));
 1679 
 1680 /* ### Added by DH ### */
 1681 {
 1682     u_short tmp = cds_flags_r(cds);
 1683 
 1684     tmp |= (CDS_FLAG_REMOTE | CDS_FLAG_READY | CDS_FLAG_NOTNET);
 1685 
 1686     cds_flags_w(cds,tmp);
 1687 }
 1688 /* ### End of addition ### */
 1689 /* ### Commented out by DH ### 
 1690 *  cds_flags(cds) |= (CDS_FLAG_REMOTE | CDS_FLAG_READY | CDS_FLAG_NOTNET);
 1691 */
 1692 
 1693   cwd = cds_current_path(cds);
 1694   sprintf(cwd, "%c:\\", 'A' + dd);
 1695 /* ### Added by DH ### */
 1696 {
 1697     u_short tmp = strlen(cwd)-1;
 1698     cds_rootlen_w(cds, tmp);
 1699 }
 1700 /* ### End of addition ### */
 1701 /* ### Commented out by DH ###
 1702 *  cds_rootlen(cds) = strlen(cwd) - 1;
 1703 */
 1704   Debug0((dbg_fd, "cds_current_path=%s\n", cwd));
 1705   return (1);
 1706 }
 1707 
 1708 boolean_t dos_fs_dev(state_t *state)
 1709 {
 1710   static int init_count = 0;
 1711   u_char drive_to_redirect;
 1712   int dos_ver;
 1713 
 1714   Debug0((dbg_fd, "emufs operation: 0x%08lx\n", state->ebx));
 1715 
 1716   if (WORD(state->ebx) == 0x500) {
 1717     init_all_drives();
 1718     mach_fs_enabled = TRUE;
 1719 
 1720     lol = (lol_t) Addr(state, es, edx);
 1721     sda = (sda_t) Addr(state, ds, esi);
 1722     dos_major = LOW(state->ecx);
 1723     dos_minor = HIGH(state->ecx);
 1724     Debug0((dbg_fd, "dos_fs: dos_major:minor = 0x%d:%d.\n",
 1725         dos_major, dos_minor));
 1726     Debug0((dbg_fd, "lol=%p\n", (void *) lol));
 1727     Debug0((dbg_fd, "sda=%p\n", (void *) sda));
 1728     if ((dos_major == 3) && (dos_minor > 9) && (dos_minor <= 31)) {
 1729       dos_ver = DOSVER_31_33;
 1730     }
 1731     else if ((dos_major == 4) && (dos_minor >= 0) && (dos_minor <= 1)) {
 1732       dos_ver = DOSVER_41;
 1733     }
 1734     else if ((dos_major == 5) && (dos_minor >= 0)) {
 1735       dos_ver = DOSVER_50;
 1736     }
 1737     else if ((dos_major >= 6) && (dos_minor >= 0)) {
 1738       dos_ver = DOSVER_60;
 1739     }
 1740     else {
 1741       dos_ver = 0;
 1742     }
 1743     init_dos_offsets(dos_ver);
 1744     SETWORD(&(state->eax), 1);
 1745   }
 1746 
 1747   if (WORD(state->ebx) == 0) {
 1748     u_char *ptr;
 1749 
 1750     ptr = (u_char *) Addr_8086(state->es, state->edi) + 22;
 1751 
 1752     drive_to_redirect = *ptr;
 1753     /* if we've never set our first free drive, set it now, and */
 1754     /* initialize our drive tables */
 1755     if (first_free_drive == 0) {
 1756       first_free_drive = drive_to_redirect;
 1757       init_all_drives();
 1758     }
 1759 
 1760     if (drive_to_redirect - (int) first_free_drive < 0) {
 1761       SETWORD(&(state->eax), 0);
 1762       Debug0((dbg_fd, "Invalid drive - maybe increase LASTDRIVE= in config.sys?\n"));
 1763       return (UNCHANGED);
 1764     }
 1765 
 1766     *(ptr - 9) = 1;
 1767     Debug0((dbg_fd, "first_free_drive = %d\n", first_free_drive));
 1768     {
 1769 /* ### Commented out by DH ###
 1770 *      u_short *seg = (u_short *) (ptr - 2);
 1771 *      u_short *ofs = (u_short *) (ptr - 4);
 1772 */
 1773 /* ### Changed next line from (char *) Addr_8086(*seg, *off) ### */
 1774       char *clineptr = (char *) FARPTR(ptr-4);
 1775       char *dirnameptr = (char *) Addr_8086(state->ds, state->esi);
 1776       char cline[256];
 1777       char *t;
 1778       int i = 0;
 1779 
 1780       while (*clineptr != '\n' && *clineptr != '\r')
 1781     cline[i++] = *(clineptr++);
 1782       cline[i] = 0;
 1783 
 1784       t = strtok(cline, " \n\r\t");
 1785       if (t) {
 1786     t = strtok(NULL, " \n\r\t");
 1787       }
 1788 
 1789       if (!init_drive(drive_to_redirect, t,
 1790               t ? strtok(NULL, " \n\r\t") : NULL)) {
 1791     SETWORD(&(state->eax), 0);
 1792     return (UNCHANGED);
 1793       }
 1794 
 1795       if (strncmp(dirnameptr - 10, "directory ", 10) == 0) {
 1796     *dirnameptr = 0;
 1797     strncpy(dirnameptr, dos_roots[drive_to_redirect], 128);
 1798     strcat(dirnameptr, "\n\r$");
 1799       }
 1800       else
 1801     Debug0((dbg_fd, "WARNING! old version of emufs.sys!\n"));
 1802     }
 1803 
 1804     mach_fs_enabled = TRUE;
 1805 
 1806     /*
 1807      * So that machfs.sys v1.1+ will know that
 1808      * we're running Mach too.
 1809      */
 1810     SETWORD(&(state->eax), 1);
 1811 
 1812     return (UNCHANGED);
 1813   }
 1814 
 1815   return (UNCHANGED);
 1816 }
 1817 
 1818 void
 1819 time_to_dos(clock, date, time)
 1820      time_t *clock;
 1821      u_short *date;
 1822      u_short *time;
 1823 {
 1824   struct tm *tm;
 1825 
 1826   tm = localtime(clock);
 1827 
 1828 /* ### Added by DH ### */
 1829 {
 1830     u_short tmp = ((((tm->tm_year - 80) & 0x1f) << 9) |
 1831        (((tm->tm_mon + 1) & 0xf) << 5) |
 1832        (tm->tm_mday & 0x1f));
 1833 
 1834     Write2Bytes(date, tmp);
 1835 
 1836     tmp = (((tm->tm_hour & 0x1f) << 0xb) |
 1837        ((tm->tm_min & 0x3f) << 5));
 1838     Write2Bytes(time,tmp);
 1839 }
 1840 /* ### End of addition ### */
 1841 }
 1842 
 1843 int
 1844 strip_char(ptr, ch)
 1845      char *ptr;
 1846      char ch;
 1847 {
 1848   int len = 0;
 1849   char *wptr;
 1850   char *rptr;
 1851 
 1852   wptr = ptr;
 1853   rptr = ptr;
 1854 
 1855   while (*rptr != EOS) {
 1856     if (*rptr == ch) {
 1857       rptr++;
 1858     }
 1859     else {
 1860       if (wptr != rptr)
 1861     *wptr = *rptr;
 1862       wptr++;
 1863       rptr++;
 1864       len++;
 1865     }
 1866   }
 1867   *wptr = EOS;
 1868 
 1869   return (len);
 1870 }
 1871 
 1872 static void
 1873 path_to_ufs(char *ufs, char *path, int PreserveEnvVar)
 1874 {
 1875   char ch;
 1876   int len = 0, inenv = 0;
 1877   char *wptr = ufs;
 1878   char *rptr = path;
 1879 
 1880   while ((ch = *rptr++) != EOS) {
 1881     switch (ch) {
 1882     case ' ':
 1883       rptr++;
 1884       continue;
 1885     case BACKSLASH:
 1886       if (PreserveEnvVar) { /* Check for environment variable */
 1887     if ((rptr[0] == '$') && (rptr[1] == '{'))
 1888       inenv = 1;
 1889     else
 1890       ch = SLASH;
 1891       }
 1892       else
 1893     ch = SLASH;
 1894       *wptr = ch;
 1895       break;
 1896     case '}':
 1897       inenv = 0;
 1898     default:
 1899       if (!inenv)
 1900     *wptr = tolower(ch);
 1901       else
 1902     *wptr = ch;
 1903 
 1904       break;
 1905     }
 1906     wptr++;
 1907     len++;
 1908   }
 1909   *wptr = EOS;
 1910 
 1911   if (ufs[len] == '.')
 1912     ufs[len] = EOS;
 1913 
 1914   Debug0((dbg_fd, "dos_gen: path_to_ufs '%s'\n", ufs));
 1915 }
 1916 
 1917 void
 1918 build_ufs_path(ufs, path)
 1919      char *ufs;
 1920      char *path;
 1921 {
 1922   strcpy(ufs, dos_root);
 1923 
 1924   Debug0((dbg_fd, "dos_fs: build_ufs_path for DOS path '%s'\n", path));
 1925 
 1926   /* Skip over leading <drive>:\ */
 1927   path += cds_rootlen_r(cds);
 1928 
 1929   path_to_ufs(ufs + dos_root_len, path, 0);
 1930 
 1931   /* remove any double slashes */
 1932   path = ufs;
 1933   while (*path) {
 1934     if (*path == '/' && *(path + 1) == '/')
 1935       strcpy(path, path + 1);
 1936     else
 1937       path++;
 1938   }
 1939 
 1940   Debug0((dbg_fd, "dos_fs: build_ufs_path result is '%s'\n", ufs));
 1941 }
 1942 
 1943 /*
 1944  * scan a directory for a matching filename
 1945  */
 1946 boolean_t
 1947 scan_dir(char *path, char *name)
 1948 {
 1949   DIR *cur_dir;
 1950   struct mydirect *cur_ent;
 1951 
 1952   /* handle null paths */
 1953   if (*path == 0)
 1954     path = "/";
 1955 
 1956   /* open the directory */
 1957   if ((cur_dir = opendir(path)) == NULL) {
 1958     Debug0((dbg_fd, "scan_dir(): failed to open dir: %s\n", path));
 1959     return (FALSE);
 1960   }
 1961 
 1962   /* now scan for matching names */
 1963   while (cur_ent = dos_readdir(cur_dir)) {
 1964     if (cur_ent->d_ino == 0)
 1965       continue;
 1966     if (cur_ent->d_name[0] == '.' &&
 1967     strncasecmp(path, dos_root, strlen(path)) != 0)
 1968       continue;
 1969     if (strcasecmp(name, cur_ent->d_name) != 0)
 1970       continue;
 1971 
 1972     /* we've found the file, change it's name and return */
 1973     strcpy(name, cur_ent->d_name);
 1974     closedir(cur_dir);
 1975     return (TRUE);
 1976   }
 1977 
 1978   closedir(cur_dir);
 1979   return (FALSE);
 1980 }
 1981 
 1982 #ifndef OLD_FIND_FILE
 1983 /*
 1984  * a new find_file that will do complete upper/lower case matching for the
 1985  * whole path
 1986  */
 1987 boolean_t
 1988 _find_file(char *fpath, struct stat * st)
 1989 {
 1990   char *slash1, *slash2;
 1991 
 1992   Debug0((dbg_fd, "find file %s\n", fpath));
 1993 
 1994   /* first see if the path exists as is */
 1995   if (stat(fpath, st) == 0)
 1996     return (TRUE);
 1997 
 1998   /* if it isn't an absolute path then we're in trouble */
 1999   if (*fpath != '/') {
 2000     error("MFS: non-absolute path in find_file: %s\n", fpath);
 2001     return (FALSE);
 2002   }
 2003 
 2004   /* slash1 will point to the beginning of the section we're looking
 2005      at, and slash2 will point at the end */
 2006   slash1 = fpath + dos_root_len - 1;
 2007 
 2008   /* maybe if we make it all lower case, this is a "best guess" */
 2009   for (slash2 = slash1; *slash2; ++slash2)
 2010     *slash2 = tolower(*slash2);
 2011   if (stat(fpath, st) == 0)
 2012     return (TRUE);
 2013 
 2014   if (!strncmp((char *) (fpath + strlen(fpath) - 3), "nul", 3)) {
 2015     Debug0((dbg_fd, "nul cmpr\n"));
 2016     stat("/dev/null", st);
 2017     return (TRUE);
 2018   }
 2019 
 2020   /* now match each part of the path name separately, trying the names
 2021      as is first, then tring to scan the directory for matching names */
 2022   while (slash1) {
 2023     slash2 = strchr(slash1 + 1, '/');
 2024     if (slash2)
 2025       *slash2 = 0;
 2026     if (stat(fpath, st) == 0) {
 2027       /* the file exists as is */
 2028       if (st->st_mode & S_IFDIR || !slash2) {
 2029     if (slash2)
 2030       *slash2 = '/';
 2031     slash1 = slash2;
 2032     continue;
 2033       }
 2034 
 2035       Debug0((dbg_fd, "find_file(): not a directory: %s\n", fpath));
 2036       if (slash2)
 2037     *slash2 = '/';
 2038       return (FALSE);
 2039     }
 2040     else {
 2041       *slash1 = 0;
 2042       if (!scan_dir(fpath, slash1 + 1)) {
 2043     *slash1 = '/';
 2044     Debug0((dbg_fd, "find_file(): no match: %s\n", fpath));
 2045     if (slash2)
 2046       *slash2 = '/';
 2047     return (FALSE);
 2048       }
 2049       *slash1 = '/';
 2050       if (slash2)
 2051     *slash2 = '/';
 2052       slash1 = slash2;
 2053     }
 2054   }
 2055 
 2056   /* we've found the file - now stat it */
 2057   if (stat(fpath, st) != 0) {
 2058     Debug0((dbg_fd, "find_file(): can't stat %s\n", fpath));
 2059     return (FALSE);
 2060   }
 2061 
 2062   Debug0((dbg_fd, "found file %s\n", fpath));
 2063   return (TRUE);
 2064 }
 2065 
 2066 #else
 2067 /*
 2068  * function: file_file
 2069  *
 2070  * Finds file fpath using stat.
 2071  * If file exists under given name, it returns true.
 2072  * This routine also checks for uppercase and lowercase
 2073  * versions of last component of filename.  It returns
 2074  * the stat structure modified appropriately and converts
 2075  * the string to the matching case or to uppercase if there
 2076  * is no match.
 2077  */
 2078 boolean_t
 2079 _find_file(fpath, st)
 2080      char *fpath;
 2081      struct stat *st;
 2082 {
 2083   int i;
 2084   int len = 0;
 2085 
 2086   /* Check original name */
 2087   Debug0((dbg_fd, "Find file trying '%s'\n", fpath));
 2088   if (stat(fpath, st) == 0)
 2089     return (TRUE);
 2090 
 2091   /* Restore to lower case */
 2092   for (i = 0; fpath[i] != EOS; i++) {
 2093     if (isalpha(fpath[i]) && isupper(fpath[i]))
 2094       fpath[i] = (char) tolower(fpath[i]);
 2095     len++;
 2096   }
 2097   Debug0((dbg_fd, "Find file trying '%s'\n", fpath));
 2098   if (stat(fpath, st) == 0)
 2099     return (TRUE);
 2100 
 2101   /* Force each component from the end to have upper case */
 2102   i = len - 1;
 2103   while (i >= 0) {
 2104     /* Check upper case version of component */
 2105     for (; i >= 0; i--) {
 2106       if (fpath[i] == SLASH) {
 2107     i--;
 2108     break;
 2109       }
 2110       if (isalpha(fpath[i]) && islower(fpath[i]))
 2111     fpath[i] = (char) toupper(fpath[i]);
 2112     }
 2113     Debug0((dbg_fd, "Find file trying '%s'\n", fpath));
 2114     if (stat(fpath, st) == 0)
 2115       return (TRUE);
 2116   }
 2117 
 2118   /* Restore to lower case */
 2119   for (i = 0; fpath[i] != EOS; i++) {
 2120     if (isalpha(fpath[i]) && isupper(fpath[i]))
 2121       fpath[i] = (char) tolower(fpath[i]);
 2122   }
 2123   return (FALSE);
 2124 }
 2125 
 2126 #endif
 2127 boolean_t
 2128 find_file(fpath, st)
 2129      char *fpath;
 2130      struct stat *st;
 2131 {
 2132   boolean_t r;
 2133 
 2134   PS(FINDFILE);
 2135   r = _find_file(fpath, st);
 2136   PE(FINDFILE);
 2137   return (r);
 2138 }
 2139 
 2140 boolean_t
 2141 compare(fname, fext, mname, mext)
 2142      char *fname;
 2143      char *fext;
 2144      char *mname;
 2145      char *mext;
 2146 {
 2147   int i;
 2148 
 2149 #if 0
 2150   Debug0((dbg_fd, "dos_gen: compare '%.8s'.'%.3s' to '%.8s'.'%.3s'\n",
 2151       mname, mext, fname, fext));
 2152 #endif
 2153   /* match name first */
 2154   for (i = 0; i < 8; i++) {
 2155     if (mname[i] == '?') {
 2156       i++;
 2157       continue;
 2158     }
 2159     if (mname[i] == ' ') {
 2160       if (fname[i] == ' ') {
 2161     break;
 2162       }
 2163       else {
 2164     return (FALSE);
 2165       }
 2166     }
 2167     if (mname[i] == '*') {
 2168       break;
 2169     }
 2170     if (isalpha(mname[i]) && isalpha(fname[i])) {
 2171       char x = isupper(mname[i]) ?
 2172       mname[i] : toupper(mname[i]);
 2173       char y = isupper(fname[i]) ?
 2174       fname[i] : toupper(fname[i]);
 2175 
 2176       if (x != y)
 2177     return (FALSE);
 2178     }
 2179     else if (mname[i] != fname[i]) {
 2180       return (FALSE);
 2181     }
 2182   }
 2183   /* if got here then name matches */
 2184   /* match ext next */
 2185   for (i = 0; i < 3; i++) {
 2186     if (mext[i] == '?') {
 2187       i++;
 2188       continue;
 2189     }
 2190     if (mext[i] == ' ') {
 2191       if (fext[i] == ' ') {
 2192     break;
 2193       }
 2194       else {
 2195     return (FALSE);
 2196       }
 2197     }
 2198     if (mext[i] == '*') {
 2199       break;
 2200     }
 2201     if (isalpha(mext[i]) && isalpha(fext[i])) {
 2202       char x = isupper(mext[i]) ?
 2203       mext[i] : toupper(mext[i]);
 2204       char y = isupper(fext[i]) ?
 2205       fext[i] : toupper(fext[i]);
 2206 
 2207       if (x != y)
 2208     return (FALSE);
 2209     }
 2210     else if (mext[i] != fext[i]) {
 2211       return (FALSE);
 2212     }
 2213   }
 2214   return (TRUE);
 2215 }
 2216 
 2217 struct dir_ent *
 2218 _match_filename_prune_list(list, name, ext)
 2219      struct dir_ent *list;
 2220      char *name;
 2221      char *ext;
 2222 {
 2223   int num_quest;
 2224   u_char nq[13];
 2225   int num_ast;
 2226   u_char na[2];
 2227   int i;
 2228   struct dir_ent *last_ptr;
 2229   struct dir_ent *tmp_ptr;
 2230   struct dir_ent *first_ptr;
 2231 
 2232   /* special case checks */
 2233   if ((strncmp(name, "????????", 8) == 0) &&
 2234       (strncmp(ext, "???", 3) == 0))
 2235     return (list);
 2236 
 2237   /* more special case checks */
 2238   if ((strncmp(name, "????????", 8) == 0) &&
 2239       (strncmp(ext, "   ", 3) == 0))
 2240     return (list);
 2241 
 2242   first_ptr = NULL;
 2243   last_ptr = NULL;
 2244 
 2245   while (list != NULL) {
 2246       if (compare(list->name, list->ext, name, ext)) {
 2247           if (first_ptr == NULL) {
 2248               first_ptr = list;
 2249           }
 2250           last_ptr = list;
 2251           tmp_ptr = list->next;
 2252           list = tmp_ptr;
 2253       }
 2254       else {
 2255 /* ### Added by DH ### */
 2256           if (last_ptr)
 2257               last_ptr->next = list->next;
 2258           tmp_ptr = list->next;
 2259           free(list);
 2260           list = tmp_ptr;
 2261       }
 2262   }
 2263   return (first_ptr);
 2264 }
 2265 
 2266 struct dir_ent *
 2267 match_filename_prune_list(list, name, ext)
 2268      struct dir_ent *list;
 2269      char *name;
 2270      char *ext;
 2271 {
 2272   struct dir_ent *r;
 2273 
 2274   PS(MATCH);
 2275   r = _match_filename_prune_list(list, name, ext);
 2276   PE(MATCH);
 2277   return (r);
 2278 }
 2279 
 2280 #define HLIST_STACK_SIZE 32
 2281 int hlist_stack_indx = 0;
 2282 struct dir_ent *hlist = NULL;
 2283 struct dir_ent *hlist_stack[HLIST_STACK_SIZE];
 2284 
 2285 boolean_t
 2286 hlist_push(hlist)
 2287      struct dir_ent *hlist;
 2288 {
 2289   Debug0((dbg_fd, "hlist_push: %x\n", hlist_stack_indx));
 2290   if (hlist_stack_indx >= HLIST_STACK_SIZE) {
 2291     return (FALSE);
 2292   }
 2293   else {
 2294     hlist_stack[hlist_stack_indx] = hlist;
 2295     hlist_stack_indx++;
 2296   }
 2297   return (TRUE);
 2298 }
 2299 
 2300 struct dir_ent *
 2301 hlist_pop()
 2302 {
 2303   Debug0((dbg_fd, "hlist_pop: %x\n", hlist_stack_indx));
 2304   if (hlist_stack_indx <= 0)
 2305     return ((struct dir_ent *) NULL);
 2306   hlist_stack_indx--;
 2307   return (hlist_stack[hlist_stack_indx]);
 2308 }
 2309 
 2310 /* ### #ifdef'd out by DH ### */
 2311 #ifdef NOTDEFINED
 2312 void
 2313 debug_dump_sft(handle)
 2314      char handle;
 2315 {
 2316   u_short *ptr;
 2317   u_char *sptr;
 2318   int sftn;
 2319 
 2320   ptr = (u_short *) (FARPTR((far_t *) (lol + 0x4)));
 2321 
 2322   Debug0((dbg_fd, "SFT: han = 0x%x, sftptr = %p\n",
 2323       handle, (void *) ptr));
 2324 
 2325   /* Assume 3.1 or 3.3 Dos */
 2326   sftn = handle;
 2327   while (TRUE) {
 2328     if ((*ptr == 0xffff) && (ptr[2] < sftn)) {
 2329       Debug0((dbg_fd, "handle invalid.\n"));
 2330       break;
 2331     }
 2332     if (ptr[2] > sftn) {
 2333       sptr = (u_char *) & ptr[3];
 2334       while (sftn--)
 2335     sptr += 0x35;       /* dos 3.1 3.3 */
 2336       Debug0((dbg_fd, "handle_count = %x\n",
 2337           sft_handle_cnt_r(sptr)));
 2338       Debug0((dbg_fd, "open_mode = %x\n",
 2339           sft_open_mode(sptr)));
 2340       Debug0((dbg_fd, "attribute byte = %x\n",
 2341           sft_attribute_byte(sptr)));
 2342       Debug0((dbg_fd, "device_info = %x\n",
 2343           sft_device_info(sptr)));
 2344       Debug0((dbg_fd, "dev_drive_ptr = %lx\n",
 2345           sft_dev_drive_ptr(sptr)));
 2346       Debug0((dbg_fd, "starting cluster = %x\n",
 2347           sft_start_cluster(sptr)));
 2348       fprintf(dbg_fd, "file time = %x\n",
 2349           sft_time(sptr));
 2350       fprintf(dbg_fd, "file date = %x\n",
 2351           sft_date(sptr));
 2352       fprintf(dbg_fd, "file size = %lx\n",
 2353           sft_size(sptr));
 2354       fprintf(dbg_fd, "pos = %lx\n",
 2355           sft_position(sptr));
 2356       fprintf(dbg_fd, "rel cluster = %x\n",
 2357           sft_rel_cluster(sptr));
 2358       fprintf(dbg_fd, "abs cluster = %x\n",
 2359           sft_abs_cluster(sptr));
 2360       fprintf(dbg_fd, "dir sector = %x\n",
 2361           sft_directory_sector(sptr));
 2362       fprintf(dbg_fd, "dir entry = %x\n",
 2363           sft_directory_entry(sptr));
 2364       fprintf(dbg_fd, "name = %.8s\n",
 2365           sft_name(sptr));
 2366       fprintf(dbg_fd, "ext = %.3s\n",
 2367           sft_ext(sptr));
 2368       return;
 2369     }
 2370     sftn -= ptr[2];
 2371     ptr = (u_short *) Addr_8086(ptr[1], ptr[0]);
 2372   }
 2373 }
 2374 #endif
 2375 
 2376 /* convert forward slashes to back slashes for DOS */
 2377 
 2378 void
 2379 path_to_dos(char *path)
 2380 {
 2381   char *s;
 2382 
 2383   for (s = path; (s = strchr(s, '/')) != NULL; ++s)
 2384     *s = '\\';
 2385 }
 2386 
 2387 int
 2388 GetRedirection(state, index)
 2389      state_t *state;
 2390      u_short index;
 2391 {
 2392   int dd;
 2393   u_short returnBX;     /* see notes below */
 2394   u_short returnCX;
 2395   char *resourceName;
 2396   char *deviceName;
 2397   u_short *userStack;
 2398 
 2399   /* Set number of redirected drives to 0 prior to getting new
 2400        Count */
 2401   /* BH has device status 0=valid */
 2402   /* BL has the device type - 3 for printer, 4 for disk */
 2403   /* CX is supposed to be used to return the stored redirection parameter */
 2404   /* I'm going to cheat and return a read-only flag in it */
 2405   Debug0((dbg_fd, "GetRedirection, index=%d\n", index));
 2406   for (dd = 0; dd < num_drives; dd++) {
 2407     if (dos_roots[dd]) {
 2408       if (index == 0) {
 2409     /* return information for this drive */
 2410     Debug0((dbg_fd, "redirection root =%s\n", dos_roots[dd]));
 2411     deviceName = (char *) Addr(state, ds, esi);
 2412     deviceName[0] = 'A' + dd;
 2413     deviceName[1] = ':';
 2414     deviceName[2] = EOS;
 2415     resourceName = (char *) Addr(state, es, edi);
 2416 /* ### Changed next line from "\\\\LINUX\\FS" ### */
 2417     strcpy(resourceName, LINUX_RESOURCE);
 2418     strcat(resourceName, dos_roots[dd]);
 2419     path_to_dos(resourceName);
 2420     Debug0((dbg_fd, "resource name =%s\n", resourceName));
 2421     Debug0((dbg_fd, "device name =%s\n", deviceName));
 2422     userStack = (u_short *) sda_user_stack(sda);
 2423 
 2424     /* have to return BX, and CX on the user return stack */
 2425     /* return a "valid" disk redirection */
 2426     returnBX = 4;       /*BH=0, BL=4 */
 2427 
 2428     /* set the high bit of the return CL so that */
 2429     /* NetWare shell doesn't get confused */
 2430     returnCX = read_onlys[dd] | 0x80;
 2431 
 2432     Debug0((dbg_fd, "GetRedirection "
 2433         "user stack=%p, CX=%x\n",
 2434         (void *) userStack, returnCX));
 2435 /* ### Commented out by DH ### 
 2436 *   userStack[1] = returnBX;
 2437 *   userStack[2] = returnCX;
 2438 */
 2439 /* ### Added by DH ### */
 2440     Write2Bytes(userStack+1, returnBX);
 2441     Write2Bytes(userStack+2, returnCX);
 2442 /* ### End of addition ### */
 2443     /* XXXTRB - should set session number in returnBP if */
 2444     /* we are doing an extended getredirection */
 2445     return (TRUE);
 2446       }
 2447       else {
 2448     /* count down until the index is exhausted */
 2449     index--;
 2450       }
 2451     }
 2452   }
 2453   if (IS_REDIRECTED(0x2f)) {
 2454     redirected_drives = WORD(state->ebx) - index;
 2455     SETWORD(&(state->ebx), index);
 2456     Debug0((dbg_fd, "GetRedirect passing index of %d, Total redirected=%d\n", index, redirected_drives));
 2457     return (REDIRECT);
 2458   }
 2459 
 2460   SETWORD(&(state->eax), NO_MORE_FILES);
 2461   return (FALSE);
 2462 }
 2463 
 2464 /*****************************
 2465  * RedirectDevice - redirect a drive to the Linux file system
 2466  * on entry:
 2467  *      cds_base should be set
 2468  * on exit:
 2469  * notes:
 2470  *****************************/
 2471 int
 2472 RedirectDevice(state_t * state)
 2473 {
 2474   char *resourceName;
 2475   char *deviceName;
 2476   char path[256];
 2477 
 2478   /* first, see if this is our resource to be redirected */
 2479   resourceName = (char *) Addr(state, es, edi);
 2480   deviceName = (char *) Addr(state, ds, esi);
 2481 
 2482   Debug0((dbg_fd, "RedirectDevice %s to %s\n", deviceName, resourceName));
 2483   if (strncmp(resourceName, LINUX_RESOURCE,
 2484           strlen(LINUX_RESOURCE)) != 0) {
 2485     /* pass call on to next redirector, if any */
 2486     return (REDIRECT);
 2487   }
 2488   /* see what device is to be redirected */
 2489   /* we only support disk redirection right now */
 2490   if (LOW(state->ebx) != 4 || deviceName[1] != ':') {
 2491     SETWORD(&(state->eax), FUNC_NUM_IVALID);
 2492     return (FALSE);
 2493   }
 2494   current_drive = toupper(deviceName[0]) - 'A';
 2495 
 2496   /* see if drive is in range of valid drives */
 2497   if (current_drive < 0 || current_drive > lol_last_drive(lol)) {
 2498     SETWORD(&(state->eax), DISK_DRIVE_INVALID);
 2499     return (FALSE);
 2500   }
 2501   cds = drive_cds(current_drive);
 2502   /* see if drive is already redirected */
 2503   if (cds_flags_r(cds) & CDS_FLAG_REMOTE) {
 2504     SETWORD(&(state->eax), DUPLICATE_REDIR);
 2505     return (FALSE);
 2506   }
 2507   /* see if drive is currently substituted */
 2508   if (cds_flags_r(cds) & CDS_FLAG_SUBST) {
 2509     SETWORD(&(state->eax), DUPLICATE_REDIR);
 2510     return (FALSE);
 2511   }
 2512 
 2513   path_to_ufs(path, &resourceName[strlen(LINUX_RESOURCE)], 1);
 2514 
 2515   /* if low bit of CX is set, then set for read only access */
 2516   Debug0((dbg_fd, "read-only attribute = %d\n",
 2517       (int) (state->ecx & 1)));
 2518   if (init_drive(current_drive, path, (state->ecx & 1) ? "R" : NULL) == 0) {
 2519     SETWORD(&(state->eax), NETWORK_NAME_NOT_FOUND);
 2520     return (FALSE);
 2521   }
 2522   else {
 2523     return (TRUE);
 2524   }
 2525 }
 2526 
 2527 /*****************************
 2528  * CancelRedirection - cancel a drive redirection
 2529  * on entry:
 2530  *      cds_base should be set
 2531  * on exit:
 2532  * notes:
 2533  *****************************/
 2534 int
 2535 CancelRedirection(state_t * state)
 2536 {
 2537   char *deviceName;
 2538   char *path;
 2539   far_t DBPptr;
 2540 
 2541   /* first, see if this is one of our current redirections */
 2542   deviceName = (char *) Addr(state, ds, esi);
 2543 
 2544   Debug0((dbg_fd, "CancelRedirection on %s\n", deviceName));
 2545   if (deviceName[1] != ':') {
 2546     /* we only handle drive redirections, pass it through */
 2547     return (REDIRECT);
 2548   }
 2549   current_drive = toupper(deviceName[0]) - 'A';
 2550 
 2551   /* see if drive is in range of valid drives */
 2552   if (current_drive < 0 || current_drive > lol_last_drive(lol)) {
 2553     SETWORD(&(state->eax), DISK_DRIVE_INVALID);
 2554     return (FALSE);
 2555   }
 2556   cds = drive_cds(current_drive);
 2557   if (dos_roots[current_drive] == NULL) {
 2558     /* we don't own this drive, pass it through to next redirector */
 2559     return (REDIRECT);
 2560   }
 2561 
 2562   /* first, clean up my information */
 2563   free(dos_roots[current_drive]);
 2564   dos_roots[current_drive] = NULL;
 2565   dos_root_lens[current_drive] = 0;
 2566   finds_in_progress[current_drive] = FALSE;
 2567   read_onlys[current_drive] = FALSE;
 2568 
 2569   /* reset information in the CDS for this drive */
 2570   cds_flags_w(cds,0);       /* default to a "not ready" drive */
 2571 
 2572   path = cds_current_path(cds);
 2573   /* set the current path for the drive */
 2574   path[0] = current_drive + 'A';
 2575   path[1] = ':';
 2576   path[2] = '\\';
 2577   path[3] = EOS;
 2578   cds_rootlen_w(cds, CDS_DEFAULT_ROOT_LEN);
 2579   cds_cur_cluster(cds,0);   /* reset us at the root of the drive */
 2580 
 2581   /* see if there is a physical drive behind this redirection */
 2582 /* ### Next bit changed by DH ### */
 2583   DBPptr.segment = (cds_DBP_pointer(cds) >> 16) & 0xffff;
 2584   DBPptr.offset = (cds_DBP_pointer(cds) & 0xffff);
 2585   if (DBPptr.offset | DBPptr.segment) {
 2586     /* if DBP_pointer is non-NULL, set the drive status to ready */
 2587     cds_flags_w(cds, CDS_FLAG_READY);
 2588   }
 2589 
 2590   Debug0((dbg_fd, "CancelRedirection on %s completed\n", deviceName));
 2591   return (TRUE);
 2592 }
 2593 
 2594 int
 2595 dos_fs_redirect(state)
 2596      state_t *state;
 2597 {
 2598     char *filename1;
 2599     char *filename2;
 2600     char *dta;
 2601     long s_pos;
 2602     u_char attr;
 2603     u_char subfunc;
 2604     int mode;
 2605     /* ### Added = 0 (bug fix) to next line by DH ### */
 2606     u_short FCBcall = 0;
 2607     u_char create_file;
 2608     int fd;
 2609     int cnt;
 2610     int ret = REDIRECT;
 2611     cds_t my_cds;
 2612     sft_t sft;
 2613     sdb_t sdb;
 2614     int i;
 2615     int bs_pos;
 2616     char fname[8];
 2617     char fext[3];
 2618     char fpath[256];
 2619     char buf[256];
 2620     struct dir_ent *tmp;
 2621     struct stat st;
 2622     static char last_find_name[8] = "";
 2623     static char last_find_ext[3] = "";
 2624     static u_char last_find_dir = 0;
 2625     static u_char last_find_drive = 0;
 2626     char *resourceName;
 2627     char *deviceName;
 2628     
 2629     if (!mach_fs_enabled)
 2630         return (REDIRECT);
 2631     
 2632     my_cds = sda_cds(sda);
 2633     
 2634     sft = (u_char *) Addr(state, es, edi);
 2635     
 2636     Debug0((dbg_fd, "Entering dos_fs_redirect\n"));
 2637     
 2638     if (!select_drive(state))
 2639         return (REDIRECT);
 2640     
 2641     filename1 = sda_filename1(sda);
 2642     filename2 = sda_filename2(sda);
 2643     sdb = sda_sdb(sda);
 2644     dta = sda_current_dta(sda);
 2645     
 2646 #if 0
 2647     Debug0((dbg_fd, "CDS current path: %s\n", cds_current_path(cds)));
 2648     Debug0((dbg_fd, "Filename1 %s\n", filename1));
 2649     Debug0((dbg_fd, "Filename2 %s\n", filename2));
 2650     Debug0((dbg_fd, "sft %x\n", sft));
 2651     Debug0((dbg_fd, "dta %x\n", dta));
 2652     fflush(NULL);
 2653 #endif
 2654     
 2655     switch (LOW(state->eax)) {
 2656     case INSTALLATION_CHECK:    /* 0x00 */
 2657         Debug0((dbg_fd, "Installation check\n"));
 2658         SETLOW(&(state->eax), 0xFF);
 2659         return (TRUE);
 2660     case REMOVE_DIRECTORY:  /* 0x01 */
 2661     case REMOVE_DIRECTORY_2:    /* 0x02 */
 2662         Debug0((dbg_fd, "Remove Directory %s\n", filename1));
 2663         if (read_only) {
 2664             SETWORD(&(state->eax), ACCESS_DENIED);
 2665             return (FALSE);
 2666         }
 2667         
 2668         build_ufs_path(fpath, filename1);
 2669         if (find_file(fpath, &st)) {
 2670             /* ### Removed ', 0755' from line below ### */
 2671             if (rmdir(fpath) != 0) {
 2672                 Debug0((dbg_fd, "failed to remove directory %s\n", fpath));
 2673                 SETWORD(&(state->eax), ACCESS_DENIED);
 2674                 return (FALSE);
 2675             }
 2676         }
 2677         else {
 2678             Debug0((dbg_fd, "couldn't find directory %s\n", fpath));
 2679             SETWORD(&(state->eax), PATH_NOT_FOUND);
 2680             return (FALSE);
 2681         }
 2682         return (TRUE);
 2683     case MAKE_DIRECTORY:        /* 0x03 */
 2684     case MAKE_DIRECTORY_2:  /* 0x04 */
 2685         Debug0((dbg_fd, "Make Directory %s\n", filename1));
 2686         if (read_only) {
 2687             SETWORD(&(state->eax), ACCESS_DENIED);
 2688             return (FALSE);
 2689         }
 2690         build_ufs_path(fpath, filename1);
 2691         if (find_file(fpath, &st)) {
 2692             Debug0((dbg_fd, "make failed already dir or file '%s'\n",
 2693                     fpath));
 2694             SETWORD(&(state->eax), ACCESS_DENIED);
 2695             return (FALSE);
 2696         }
 2697         if (mkdir(fpath, 0755) != 0) {
 2698             for (i = 0, bs_pos = 0; fpath[i] != EOS; i++) {
 2699                 if (fpath[i] == SLASH)
 2700                     bs_pos = i;
 2701             }
 2702             strncpy(buf, fpath, bs_pos);
 2703             buf[bs_pos] = EOS;
 2704             find_file(buf, &st);
 2705             strncpy(fpath, buf, bs_pos);
 2706             Debug0((dbg_fd, "trying '%s'\n", fpath));
 2707             if (mkdir(fpath, 0755) != 0) {
 2708                 Debug0((dbg_fd, "make directory failed '%s'\n",
 2709                         fpath));
 2710                 SETWORD(&(state->eax), PATH_NOT_FOUND);
 2711                 return (FALSE);
 2712             }
 2713         }
 2714         return (TRUE);
 2715     case SET_CURRENT_DIRECTORY: /* 0x05 */
 2716         Debug0((dbg_fd, "set directory to: %s\n", filename1));
 2717         build_ufs_path(fpath, filename1);
 2718         Debug0((dbg_fd, "set directory to ufs path: %s\n", fpath));
 2719         
 2720         /* Try the given path */
 2721         if (!find_file(fpath, &st)) {
 2722             SETWORD(&(state->eax), PATH_NOT_FOUND);
 2723             return (FALSE);
 2724         }
 2725         if (!(st.st_mode & S_IFDIR)) {
 2726             SETWORD(&(state->eax), PATH_NOT_FOUND);
 2727             Debug0((dbg_fd, "Set Directory %s not found\n", fpath));
 2728             return (FALSE);
 2729         }
 2730         /* what we do now is update the cds_current_path, although it is
 2731            probably superflous in most cases as dos seems to do it for us */
 2732     {
 2733         char *fp, *cwd;
 2734         
 2735         fp = fpath + strlen(dos_root);
 2736         
 2737         /* Skip over leading <drive>:\ */
 2738         cwd = cds_current_path(cds) + cds_rootlen_r(cds) + 1;
 2739         
 2740         /* now copy the rest of the path, changing / to \ */
 2741         do
 2742             *cwd++ = (*fp == '/' ? '\\' : *fp);
 2743         while (*fp++);
 2744     }
 2745         Debug0((dbg_fd, "New CWD is %s\n", cds_current_path(cds)));
 2746         return (TRUE);
 2747     case CLOSE_FILE:        /* 0x06 */
 2748         fd = sft_fd_r(sft);
 2749         Debug0((dbg_fd, "Close file %x\n", fd));
 2750         Debug0((dbg_fd, "Handle cnt %d\n",
 2751                 sft_handle_cnt_r(sft)));
 2752         /* ### Added by DH ### */
 2753     {
 2754         u_short tmp = sft_handle_cnt_r(sft) -1;
 2755         sft_handle_cnt_w(sft, tmp);
 2756     }
 2757         /* ### End of addition ### */
 2758         
 2759         if (sft_handle_cnt_r(sft) > 0) {
 2760             Debug0((dbg_fd, "Still more handles\n"));
 2761             return (TRUE);
 2762         }
 2763         else if (close(fd) != 0) {
 2764             Debug0((dbg_fd, "Close file fails\n"));
 2765             return (FALSE);
 2766         }
 2767         else {
 2768             Debug0((dbg_fd, "Close file succeeds\n"));
 2769             return (TRUE);
 2770         }
 2771     case READ_FILE:
 2772     {               /* 0x08 */
 2773         int return_val;
 2774         int itisnow;
 2775         
 2776         cnt = WORD(state->ecx);
 2777         fd = sft_fd_r(sft);
 2778         Debug0((dbg_fd, "Read file fd=%x, dta=%p, cnt=%d\n",
 2779                 fd, (void *) dta, cnt));
 2780         Debug0((dbg_fd, "Read file pos = %ld\n",
 2781                 sft_position_r(sft)));
 2782         Debug0((dbg_fd, "Handle cnt %d\n",
 2783                 sft_handle_cnt_r(sft)));
 2784         itisnow = lseek(fd, sft_position_r(sft), L_SET);
 2785         Debug0((dbg_fd, "Actual pos %d\n",
 2786                 itisnow));
 2787         ret = dos_read(fd, dta, cnt);
 2788         Debug0((dbg_fd, "Read returned : %d\n",
 2789                 ret));
 2790         if (ret < 0) {
 2791             Debug0((dbg_fd, "ERROR IS: %s\n", strerror(errno)));
 2792             return (FALSE);
 2793         }
 2794         else if (ret < cnt) {
 2795             SETWORD(&(state->ecx), ret);
 2796             return_val = TRUE;
 2797         }
 2798         else {
 2799             SETWORD(&(state->ecx), cnt);
 2800             return_val = TRUE;
 2801         }
 2802         /* ### Added by DH ### */
 2803     {
 2804         u_long tmp = sft_position_r(sft) + ret;
 2805         
 2806         sft_position_w(sft, tmp);
 2807     }
 2808         /* ### End of addition ### */
 2809         
 2810         sft_abs_cluster(sft, 0x174a);   /* XXX a test */
 2811         Debug0((dbg_fd, "File data %c %c %c\n",
 2812                 dta[0], dta[1], dta[2]));
 2813         Debug0((dbg_fd, "Read file pos after = %ld\n",
 2814                 sft_position_r(sft)));
 2815         return (return_val);
 2816     }
 2817     case WRITE_FILE:        /* 0x09 */
 2818         cnt = WORD(state->ecx);
 2819         fd = sft_fd_r(sft);
 2820         
 2821         Debug0((dbg_fd, "Write file fd=%x count=%x sft_mode=%x\n", fd, cnt, sft_open_mode_r(sft)));
 2822         if (read_only) {
 2823             SETWORD(&(state->eax), ACCESS_DENIED);
 2824             return (FALSE);
 2825         }
 2826         
 2827         /* According to U DOS 2, any write with a (cnt)=CX=0 should truncate fd to
 2828            sft_size , do to how ftruncate works, I'll only do an ftruncate
 2829            if the file's size is greater than the current file position. */
 2830         
 2831         if (!cnt && sft_size_r(sft) > sft_position_r(sft)) {
 2832             Debug0((dbg_fd, "Applying O_TRUNC at %x\n", s_pos));
 2833             if (ftruncate(fd, (off_t) sft_position_r(sft))) {
 2834                 Debug0((dbg_fd, "O_TRUNC failed\n"));
 2835                 SETWORD(&(state->eax), ACCESS_DENIED);
 2836                 return (FALSE);
 2837             }
 2838             /* ###  Added by DH ### */
 2839         {
 2840             u_long tmp = sft_position_r(sft);
 2841             
 2842             sft_size_w(sft, tmp);
 2843         }
 2844             /* ### End of addition ### */
 2845         }
 2846         
 2847         if (us_debug_level > Debug_Level_0) {
 2848             s_pos = lseek(fd, sft_position_r(sft), L_SET);
 2849         }
 2850         Debug0((dbg_fd, "Handle cnt %d\n",
 2851                 sft_handle_cnt_r(sft)));
 2852         Debug0((dbg_fd, "sft_size = %x, sft_pos = %x, dta = %p, cnt = %x\n", sft_size_r(sft), sft_position_r(sft), (void *) dta, cnt));
 2853         if (us_debug_level > Debug_Level_0) {
 2854             ret = dos_write(fd, dta, cnt);
 2855             if ((ret + s_pos) > sft_size_r(sft)) {
 2856                 sft_size_w(sft, ret+s_pos);
 2857             }
 2858         }
 2859         Debug0((dbg_fd, "write operation done,ret=%x\n", ret));
 2860         if (us_debug_level > Debug_Level_0)
 2861             if (ret < 0) {
 2862                 Debug0((dbg_fd, "Write Failed : %s\n", strerror(errno)));
 2863                 return (FALSE);
 2864             }
 2865         Debug0((dbg_fd, "sft_position=%lu, Sft_size=%lu\n",
 2866                 sft_position_r(sft), sft_size_r(sft)));
 2867         SETWORD(&(state->ecx), ret);
 2868         /* ### Added by DH ### */
 2869     {
 2870         u_long pos = sft_position_r(sft) + ret;
 2871         
 2872         sft_position_w(sft, pos);
 2873     }
 2874         /* ### end of addition ### */
 2875         
 2876         sft_abs_cluster(sft,0x174a);    /* XXX a test */
 2877         if (us_debug_level > Debug_Level_0)
 2878             return (TRUE);
 2879     case GET_DISK_SPACE:
 2880     {               /* 0x0c */
 2881 #ifdef USE_DF_AND_AFS_STUFF
 2882         int free, tot;
 2883         
 2884         Debug0((dbg_fd, "Get Disk Space\n"));
 2885         build_ufs_path(fpath, cds_current_path(cds));
 2886         
 2887         if (find_file(fpath, &st)) {
 2888             if (get_disk_space(fpath, &free, &tot)) {
 2889                 int spc = 1;
 2890                 int bps = 512;
 2891                 int tmpf, tmpt;
 2892                 
 2893                 if ((tot > 256 * 256) || (free > 256 * 256)) {
 2894                     tmpf = free * bps * spc;
 2895                     tmpt = tot * bps * spc;
 2896                     
 2897                     spc = 8;
 2898                     bps = 1024;
 2899                     
 2900                     free = (tmpf / bps) / spc;
 2901                     tot = (tmpt / bps) / spc;
 2902                 }
 2903                 
 2904                 SETWORD(&(state->eax), spc);
 2905                 SETWORD(&(state->edx), free);
 2906                 SETWORD(&(state->ecx), bps);
 2907                 SETWORD(&(state->ebx), tot);
 2908                 Debug0((dbg_fd, "free=%d, tot=%d, bps=%d, spc=%d\n",
 2909                         free, tot, bps, spc));
 2910                 
 2911                 return (TRUE);
 2912             }
 2913             else {
 2914                 Debug0((dbg_fd, "no ret gds\n"));
 2915             }
 2916         }
 2917 #endif /* USE_DF_AND_AFS_STUFF */
 2918         break;
 2919     }
 2920     case SET_FILE_ATTRIBUTES:   /* 0x0e */
 2921     {
 2922         /* ### Changed next line from *(u_short *).... to Read2Bytes(u_short,...) ### */
 2923         u_short att = Read2Bytes(u_short,Addr(state, ss, esp));
 2924         
 2925         Debug0((dbg_fd, "Set File Attributes %s 0%o\n", filename1, att));
 2926         if (read_only) {
 2927             SETWORD(&(state->eax), ACCESS_DENIED);
 2928             return (FALSE);
 2929         }
 2930         
 2931         build_ufs_path(fpath, filename1);
 2932         Debug0((dbg_fd, "Set attr: '%s' --> 0%o\n", fpath, att));
 2933         if (!find_file(fpath, &st)) {
 2934             SETWORD(&(state->eax), FILE_NOT_FOUND);
 2935             return (FALSE);
 2936         }
 2937         if (chmod(fpath, get_unix_attr(st.st_mode, att)) != 0) {
 2938             SETWORD(&(state->eax), ACCESS_DENIED);
 2939             return (FALSE);
 2940         }
 2941     }
 2942         return (TRUE);
 2943         
 2944         break;
 2945     case GET_FILE_ATTRIBUTES:   /* 0x0f */
 2946         Debug0((dbg_fd, "Get File Attributes %s\n", filename1));
 2947         build_ufs_path(fpath, filename1);
 2948         if (!find_file(fpath, &st)) {
 2949             Debug0((dbg_fd, "Get failed: '%s'\n", fpath));
 2950             SETWORD(&(state->eax), FILE_NOT_FOUND);
 2951             return (FALSE);
 2952         }
 2953         
 2954         SETWORD(&(state->eax), get_dos_attr(st.st_mode));
 2955         state->ebx = st.st_size >> 16;
 2956         state->edi = MASK16(st.st_size);
 2957         return (TRUE);
 2958     case RENAME_FILE:       /* 0x11 */
 2959         Debug0((dbg_fd, "Rename file fn1=%s fn2=%s\n", filename1, filename2));
 2960         if (read_only) {
 2961             SETWORD(&(state->eax), ACCESS_DENIED);
 2962             return (FALSE);
 2963         }
 2964         build_ufs_path(fpath, filename2);
 2965         for (i = 0, bs_pos = 0; fpath[i] != EOS; i++) {
 2966             if (fpath[i] == SLASH)
 2967                 bs_pos = i;
 2968         }
 2969         strncpy(buf, fpath, bs_pos);
 2970         buf[bs_pos] = EOS;
 2971         find_file(buf, &st);
 2972         strncpy(fpath, buf, bs_pos);
 2973         
 2974         build_ufs_path(buf, filename1);
 2975         if (!find_file(buf, &st)) {
 2976             Debug0((dbg_fd, "Rename '%s' error.\n", fpath));
 2977             SETWORD(&(state->eax), PATH_NOT_FOUND);
 2978             return (FALSE);
 2979         }
 2980         
 2981         if (rename(buf, fpath) != 0) {
 2982             SETWORD(&(state->eax), PATH_NOT_FOUND);
 2983             return (FALSE);
 2984         }
 2985         else {
 2986             Debug0((dbg_fd, "Rename file %s to %s\n",
 2987                     fpath, buf));
 2988             return (TRUE);
 2989         }
 2990     case DELETE_FILE:       /* 0x13 */
 2991     {
 2992         struct dir_ent *de = NULL;
 2993         
 2994         Debug0((dbg_fd, "Delete file %s\n", filename1));
 2995         if (read_only) {
 2996             SETWORD(&(state->eax), ACCESS_DENIED);
 2997             return (FALSE);
 2998         }
 2999         build_ufs_path(fpath, filename1);
 3000         for (i = 0, bs_pos = 0; fpath[i] != EOS; i++) {
 3001             if (fpath[i] == SLASH)
 3002                 bs_pos = i;
 3003         }
 3004         fpath[bs_pos] = EOS;
 3005         auspr(fpath + bs_pos + 1, fname, fext);
 3006         if (bs_pos == 0) {
 3007             bs_pos = -1;
 3008             strcpy(fpath, "/");
 3009         }
 3010         
 3011         de = match_filename_prune_list(get_dir(fpath, fname, fext),
 3012                                        fname, fext);
 3013         
 3014         if (de == NULL) {
 3015             build_ufs_path(fpath, filename1);
 3016             if (!find_file(fpath, &st)) {
 3017                 SETWORD(&(state->eax), FILE_NOT_FOUND);
 3018                 return (FALSE);
 3019             }
 3020             if (unlink(fpath) != 0) {
 3021                 Debug0((dbg_fd, "Deleted %s\n", fpath));
 3022                 SETWORD(&(state->eax), FILE_NOT_FOUND);
 3023                 return (FALSE);
 3024             }
 3025             return (TRUE);
 3026         }
 3027         
 3028         while (de != NULL) {
 3029             if ((de->mode & S_IFMT) == S_IFREG) {
 3030                 strncpy(fpath + bs_pos + 1, de->name, 8);
 3031                 fpath[bs_pos] = SLASH;
 3032                 fpath[bs_pos + 9] = '.';
 3033                 fpath[bs_pos + 13] = EOS;
 3034                 strncpy(fpath + bs_pos + 10, de->ext, 3);
 3035                 strip_char(fpath, ' ');
 3036                 cnt = strlen(fpath);
 3037                 if (fpath[cnt - 1] == '.')
 3038                     fpath[cnt - 1] = EOS;
 3039                 if (find_file(fpath, &st)) {
 3040                     unlink(fpath);
 3041                     Debug0((dbg_fd, "Deleted %s\n", fpath));
 3042                 }
 3043             }
 3044             tmp = de->next;
 3045             free(de);
 3046             de = tmp;
 3047         }
 3048         return (TRUE);
 3049     }
 3050         
 3051     case OPEN_EXISTING_FILE:    /* 0x16 */
 3052         mode = sft_open_mode_r(sft);
 3053         FCBcall = mode & 0x8000;
 3054         Debug0((dbg_fd, "mode=0x%x\n", mode));
 3055         mode = sda_open_mode(sda) & 0x3;
 3056         /* ### Changed next bit from *(u_short *)... to Read2Bytes(u_short,...) ### */
 3057     {
 3058         BYTE *tmp = Addr(state, ss, uesp);
 3059         attr = Read2Bytes(u_short, tmp);
 3060     }
 3061         Debug0((dbg_fd, "Open existing file %s\n", filename1));
 3062         Debug0((dbg_fd, "mode=0x%x, attr=0%o\n", mode, attr));
 3063         
 3064     do_open_existing:
 3065         if (read_only && mode != O_RDONLY) {
 3066             SETWORD(&(state->eax), ACCESS_DENIED);
 3067             return (FALSE);
 3068         }
 3069         build_ufs_path(fpath, filename1);
 3070         if (!find_file(fpath, &st)) {
 3071             Debug0((dbg_fd, "open failed: '%s'\n", fpath));
 3072             SETWORD(&(state->eax), FILE_NOT_FOUND);
 3073             return (FALSE);
 3074         }
 3075         
 3076         if (st.st_mode & S_IFDIR) {
 3077             Debug0((dbg_fd, "S_IFDIR: '%s'\n", fpath));
 3078             SETWORD(&(state->eax), FILE_NOT_FOUND);
 3079             return (FALSE);
 3080         }
 3081         if (mode == READ_ACC) {
 3082             mode = O_RDONLY;
 3083         }
 3084         else if (mode == WRITE_ACC) {
 3085             mode = O_WRONLY;
 3086         }
 3087         else if (mode == READ_WRITE_ACC) {
 3088             mode = O_RDWR;
 3089         }
 3090         else {
 3091             Debug0((dbg_fd, "Illegal access_mode 0x%x\n", mode));
 3092             mode = O_RDONLY;
 3093         }
 3094         if (read_only && mode != O_RDONLY) {
 3095             SETWORD(&(state->eax), ACCESS_DENIED);
 3096             return (FALSE);
 3097         }
 3098         
 3099         /* Handle DOS requests for drive:\patch\NUL */
 3100         if (!strncmp((char *) (fpath + strlen(fpath) - 3), "nul", 3)) {
 3101             if ((fd = open("/dev/null", mode)) < 0) {
 3102                 Debug0((dbg_fd, "access denied:'%s'\n", fpath));
 3103                 SETWORD(&(state->eax), ACCESS_DENIED);
 3104                 return (FALSE);
 3105             }
 3106         }
 3107         else if ((fd = open(fpath, mode)) < 0) {
 3108             Debug0((dbg_fd, "access denied:'%s'\n", fpath));
 3109             SETWORD(&(state->eax), ACCESS_DENIED);
 3110             return (FALSE);
 3111         }
 3112         
 3113         for (i = 0, bs_pos = 0; fpath[i] != EOS; i++) {
 3114             if (fpath[i] == SLASH)
 3115                 bs_pos = i;
 3116         }
 3117         
 3118         auspr(fpath + bs_pos + 1,
 3119               sft_name(sft),
 3120               sft_ext(sft));
 3121         if (FCBcall)
 3122             /* ### Added by DH ### */
 3123         {
 3124             u_short tmp = sft_open_mode_r(sft) | 0x00f0;
 3125             
 3126             sft_open_mode_w(sft, tmp);
 3127         }
 3128         /* ### end of addition ### */
 3129         else
 3130             /* ### Added by DH ### */
 3131         {
 3132             u_short tmp = sft_open_mode_r(sft) & 0x7f;
 3133             
 3134             sft_open_mode_w(sft, tmp);
 3135         }
 3136         /* ### end of addition ## */
 3137         sft_dev_drive_ptr(sft,0);
 3138         sft_directory_entry(sft) = 0;
 3139         sft_directory_sector(sft,0);
 3140 #ifdef NOTEST
 3141         sft_attribute_byte(sft) = attr;
 3142 #else
 3143         sft_attribute_byte(sft) = 0x20;
 3144 #endif /* NOTEST */
 3145         sft_device_info_w(sft, current_drive + 0x8040);
 3146         time_to_dos(&st.st_mtime,
 3147                     &sft_date(sft), &sft_time(sft));
 3148         sft_size_w(sft, st.st_size);
 3149         sft_position_w(sft, 0);
 3150         sft_fd_w(sft, fd);
 3151         Debug0((dbg_fd, "open succeeds: '%s' fd = 0x%x\n", fpath, fd));
 3152         Debug0((dbg_fd, "Size : %ld\n", (long) st.st_size));
 3153         
 3154         /* If FCB open requested, we need to call int2f 0x120c */
 3155         if (FCBcall) {
 3156             u_short *ssp;
 3157             
 3158             Debug0((dbg_fd, "FCB Open calling int2f 0x120c\n"));
 3159             if (!LWORD(esp))
 3160                 ssp = (SEG_ADR((us *), ss, sp)) + 0x8000;
 3161             else
 3162                 ssp = SEG_ADR((us *), ss, sp);
 3163             /* ### Commented out by DH ###
 3164              *      *--ssp = REG(eflags);
 3165              *      *--ssp = REG(cs);
 3166              *      *--ssp = REG(eip);
 3167              */
 3168             /* ### Added by DH ### */
 3169             Write2Bytes(ssp-1, REG(eflags));
 3170             Write2Bytes(ssp-2, REG(cs));
 3171             Write2Bytes(ssp-3, REG(eip));
 3172             /* ### End of addition ### */
 3173             REG(esp) -= 6;
 3174             REG(cs) = (us) INTE7_SEG;
 3175             REG(eip) = (us) INTE7_OFF;
 3176             
 3177             /* clear TF (trap flag, singlestep), IF (interrupt flag), and
 3178              * NT (nested task) bits of EFLAGS
 3179              */
 3180             REG(eflags) &= ~(TF | IF | NT);
 3181             
 3182         }
 3183         
 3184         return (TRUE);
 3185     case CREATE_TRUNCATE_NO_CDS:    /* 0x18 */
 3186     case CREATE_TRUNCATE_FILE:  /* 0x17 */
 3187         
 3188         FCBcall = sft_open_mode_r(sft) & 0x8000;
 3189         Debug0((dbg_fd, "FCBcall=0x%x\n", FCBcall));
 3190         
 3191         /* 01 in high byte = create new, 00 s just create truncate */
 3192         create_file = *(u_char *) (Addr(state, ss, uesp) + 1);
 3193         
 3194         /* ### Changed next line from *(u_short *)... to Read2Bytes(u_short,...) ### */
 3195         attr = Read2Bytes(u_short,Addr(state, ss, uesp));
 3196         Debug0((dbg_fd, "CHECK attr=0x%x, create=0x%x\n", attr, create_file));
 3197         
 3198         /* make it a byte - we thus ignore the new bit */
 3199         attr &= 0xFF;
 3200         
 3201         Debug0((dbg_fd, "Create truncate file %s attr=%x\n", filename1, attr));
 3202         
 3203     do_create_truncate:
 3204         if (read_only) {
 3205             SETWORD(&(state->eax), ACCESS_DENIED);
 3206             return (FALSE);
 3207         }
 3208         build_ufs_path(fpath, filename1);
 3209         if (find_file(fpath, &st)) {
 3210             Debug0((dbg_fd, "st.st_mode = 0x%02x, handles=%d\n", st.st_mode, sft_handle_cnt_r(sft)));
 3211             if ( /* !(st.st_mode & S_IFREG) || */ create_file) {
 3212                 SETWORD(&(state->eax), 0x50);
 3213                 Debug0((dbg_fd, "File exists '%s'\n",
 3214                         fpath));
 3215                 return (FALSE);
 3216             }
 3217         }
 3218         
 3219         for (i = 0, bs_pos = 0; fpath[i] != EOS; i++) {
 3220             if (fpath[i] == SLASH)
 3221                 bs_pos = i;
 3222         }
 3223         
 3224         if ((fd = open(fpath, (O_RDWR | O_CREAT | O_TRUNC),
 3225                        get_unix_attr(0664, attr))) < 0) {
 3226             strncpy(buf, fpath, bs_pos);
 3227             buf[bs_pos] = EOS;
 3228             find_file(buf, &st);
 3229             strncpy(fpath, buf, bs_pos);
 3230             Debug0((dbg_fd, "trying '%s'\n", fpath));
 3231             if ((fd = open(fpath, (O_RDWR | O_CREAT | O_TRUNC),
 3232                            get_unix_attr(0664, attr))) < 0) {
 3233                 Debug0((dbg_fd, "can't open %s: %s (%d)\n",
 3234                         fpath, strerror(errno), errno));
 3235                 SETWORD(&(state->eax), ACCESS_DENIED);
 3236                 return (FALSE);
 3237             }
 3238         }
 3239         
 3240         auspr(fpath + bs_pos + 1, sft_name(sft), sft_ext(sft));
 3241         sft_dev_drive_ptr(sft,0);
 3242         
 3243         /* This caused a bug with temporary files so they couldn't be read,
 3244            they were made write-only */
 3245 #if 0
 3246         sft_open_mode_w(sft, 0x01);
 3247 #else
 3248         if (FCBcall)
 3249             /* ### Added by DH ### */
 3250         {
 3251             u_short tmp = sft_open_mode_r(sft) | 0xf0;
 3252             
 3253             sft_open_mode_w(sft, tmp);
 3254         }
 3255         /* ### End of addition ### */
 3256         else
 3257             /* ### Added by DH ### */
 3258         {
 3259             u_short tmp = sft_open_mode_r(sft) & 0x3;
 3260             
 3261             sft_open_mode_w(sft, tmp);
 3262         }
 3263         /* ### end of addition ### */
 3264         
 3265 #endif
 3266         sft_directory_entry(sft) = 0;
 3267         sft_directory_sector(sft,0);
 3268         sft_attribute_byte(sft) = attr;
 3269         sft_device_info_w(sft, current_drive + 0x8040);
 3270         time_to_dos(&st.st_mtime, &sft_date(sft),
 3271                     &sft_time(sft));
 3272         
 3273         /* file size starts at 0 bytes */
 3274         sft_size_w(sft, 0);
 3275         sft_position_w(sft,0);
 3276         sft_fd_w(sft ,fd);
 3277         Debug0((dbg_fd, "create succeeds: '%s' fd = 0x%x\n", fpath, fd));
 3278         Debug0((dbg_fd, "size = 0x%lx\n", sft_size_r(sft)));
 3279         
 3280         /* If FCB open requested, we need to call int2f 0x120c */
 3281         if (FCBcall) {
 3282             u_short *ssp;
 3283             
 3284             Debug0((dbg_fd, "FCB Open calling int2f 0x120c\n"));
 3285             if (!LWORD(esp))
 3286                 ssp = (SEG_ADR((us *), ss, sp)) + 0x8000;
 3287             else
 3288                 ssp = SEG_ADR((us *), ss, sp);
 3289             /* ### Commented out by DH ###
 3290              *      *--ssp = REG(eflags);
 3291              *      *--ssp = REG(cs);
 3292              *      *--ssp = REG(eip);
 3293              */
 3294             /* ### Added by DH ### */
 3295             Write2Bytes(ssp-1, REG(eflags));
 3296             Write2Bytes(ssp-2, REG(cs));
 3297             Write2Bytes(ssp-3, REG(eip));
 3298             /* ### End of addition ### */
 3299             REG(esp) -= 6;
 3300             REG(cs) = (us) INTE7_SEG;
 3301             REG(eip) = (us) INTE7_OFF;
 3302             
 3303             /* clear TF (trap flag, singlestep), IF (interrupt flag), and
 3304              * NT (nested task) bits of EFLAGS
 3305              */
 3306             REG(eflags) &= ~(TF | IF | NT);
 3307             
 3308         }
 3309         return (TRUE);
 3310         
 3311     case FIND_FIRST_NO_CDS: /* 0x19 */
 3312     case FIND_FIRST:        /* 0x1b */
 3313         
 3314         attr = sda_search_attribute(sda);
 3315         
 3316         Debug0((dbg_fd, "findfirst %s attr=%x\n", filename1, attr));
 3317         
 3318         if (!strncmp(&filename1[strlen(filename1) - 3], "NUL", 3)) {
 3319             Debug0((dng_fd, "Found a NUL, translating\n"));
 3320             filename1[strlen(filename1) - 4] = 0;
 3321             attr = attr | DIRECTORY;
 3322         }
 3323         
 3324         if (find_in_progress) {
 3325             if (!hlist_push(hlist))
 3326                 free_list(hlist);
 3327         }
 3328         else {
 3329             free_list(hlist);
 3330         }
 3331         hlist = NULL;
 3332         
 3333         Debug0((dbg_fd, "attr = 0x%x\n", attr));
 3334         
 3335         build_ufs_path(fpath, filename1);
 3336         
 3337         for (i = 0, bs_pos = 0; fpath[i] != EOS; i++) {
 3338             if (fpath[i] == SLASH)
 3339                 bs_pos = i;
 3340         }
 3341         fpath[bs_pos] = EOS;
 3342         
 3343         auspr(fpath + bs_pos + 1, fname, fext);
 3344         strncpy(sdb_template_name(sdb), fname, 8);
 3345         strncpy(sdb_template_ext(sdb), fext, 3);
 3346         sdb_attribute(sdb) = attr;
 3347         sdb_drive_letter(sdb) = 0x80 + current_drive;
 3348         sdb_dir_entry_w(sdb, hlist_stack_indx);
 3349         
 3350         Debug0((dbg_fd, "Find first %8.8s.%3.3s\n",
 3351                 sdb_template_name(sdb),
 3352                 sdb_template_ext(sdb)));
 3353         
 3354         strncpy(last_find_name, sdb_template_name(sdb), 8);
 3355         strncpy(last_find_ext, sdb_template_ext(sdb), 3);
 3356         last_find_dir = sdb_dir_entry_r(sdb);
 3357         last_find_drive = sdb_drive_letter(sdb);
 3358         
 3359 #ifndef NO_VOLUME_LABELS
 3360         if (attr & VOLUME_LABEL &&
 3361             strncmp(sdb_template_name(sdb), "????????", 8) == 0 &&
 3362             strncmp(sdb_template_ext(sdb), "???", 3) == 0) {
 3363             Debug0((dbg_fd, "DO LABEL!!\n"));
 3364 #if 0
 3365             auspr(VOLUMELABEL, fname, fext);
 3366             sprintf(fext, "%d", current_drive);
 3367 #else
 3368         {
 3369             char *label, *root, *p;
 3370             
 3371             p = dos_roots[current_drive];
 3372             label = (char *) malloc(8 + 3 + 1);
 3373             root = (char *) malloc(strlen(p) + 1);
 3374             strcpy(root, p);
 3375             if (root[strlen(root) - 1] == '/' && strlen(root) > 1)
 3376                 root[strlen(root) - 1] = '\0';
 3377 #if 0
 3378             sprintf(label, "%d:", current_drive);
 3379 #else
 3380             label[0] = '\0';
 3381 #endif
 3382             if (strlen(label) + strlen(root) <= 8 + 3) {
 3383                 strcat(label, root);
 3384             }
 3385             else {
 3386 #if 0
 3387                 strcat(label, "...");
 3388 #endif
 3389                 strcat(label, root + strlen(root) - (8 + 3 - strlen(label)));
 3390             }
 3391             for (p = label + strlen(label); p < label + 8 + 3; p++)
 3392                 *p = ' ';
 3393             
 3394             strncpy(fname, label, 8);
 3395             strncpy(fext, label + 8, 3);
 3396             free(label);
 3397             free(root);
 3398         }
 3399 #endif
 3400             strncpy(sdb_file_name(sdb), fname, 8);
 3401             strncpy(sdb_file_ext(sdb), fext, 3);
 3402             sdb_file_attr(sdb) = VOLUME_LABEL;
 3403             sdb_dir_entry_w(sdb, 0);
 3404             if (attr != VOLUME_LABEL)
 3405                 find_in_progress = TRUE;
 3406             auspr(fpath + bs_pos + 1, fname, fext);
 3407             if (bs_pos == 0)
 3408                 strcpy(fpath, "/");
 3409             hlist = match_filename_prune_list(
 3410                                               get_dir(fpath, fname, fext), fname, fext);
 3411             return (TRUE);
 3412         }
 3413 #else
 3414         if (attr == VOLUME_LABEL)
 3415             return (FALSE);
 3416 #endif
 3417         if (bs_pos == 0)
 3418             strcpy(fpath, "/");
 3419         hlist = match_filename_prune_list(
 3420                                           get_dir(fpath, fname, fext), fname, fext);
 3421         
 3422     find_again:
 3423         
 3424         if (hlist == NULL) {
 3425             /* no matches or empty directory */
 3426             Debug0((dbg_fd, "No more matches\n"));
 3427             SETWORD(&(state->eax), NO_MORE_FILES);
 3428             hlist = hlist_pop();
 3429             last_find_drive = 0;
 3430             if (hlist == NULL && !hlist_stack_indx)
 3431                 find_in_progress = FALSE;
 3432             return (FALSE);
 3433         }
 3434         else {
 3435             Debug0((dbg_fd, "find_again entered with %.8s.%.3s\n", hlist->name, hlist->ext));
 3436             sdb_file_attr(sdb) = get_dos_attr(hlist->mode);
 3437             
 3438             if (hlist->mode & S_IFDIR) {
 3439                 Debug0((dbg_fd, "Directory ---> YES\n"));
 3440                 if (!(attr & DIRECTORY)) {
 3441                     tmp = hlist->next;
 3442                     free(hlist);
 3443                     hlist = tmp;
 3444                     goto find_again;
 3445                 }
 3446             }
 3447             time_to_dos(&hlist->time,
 3448                         &sdb_file_date(sdb),
 3449                         &sdb_file_time(sdb));
 3450             sdb_file_size(sdb, hlist->size);
 3451             strncpy(sdb_file_name(sdb), hlist->name, 8);
 3452             strncpy(sdb_file_ext(sdb), hlist->ext, 3);
 3453 
 3454 #if 0
 3455             /* ### Added by DH ## */
 3456         {
 3457             u_short tmp = sdb_dir_entry_r(sdb) +1;
 3458             
 3459             sdb_dir_entry_w(sdb, tmp);
 3460         }
 3461             /* ### End of addition ### */
 3462             
 3463 #endif
 3464             
 3465             Debug0((dbg_fd, "'%.8s'.'%.3s'\n",
 3466                     sdb_file_name(sdb),
 3467                     sdb_file_ext(sdb)));
 3468             
 3469             tmp = hlist->next;
 3470             free(hlist);
 3471             hlist = tmp;
 3472         }
 3473         find_in_progress = TRUE;
 3474         return (TRUE);
 3475     case FIND_NEXT:     /* 0x1c */
 3476         Debug0((dbg_fd, "Find next %8.8s.%3.3s, hlist=%d\n",
 3477                 sdb_template_name(sdb),
 3478                 sdb_template_ext(sdb), hlist));
 3479         if (last_find_drive && ((strncmp(last_find_name, sdb_template_name(sdb), 8) != 0 ||
 3480                                  strncmp(last_find_ext, sdb_template_ext(sdb), 3) != 0) ||
 3481                                 (last_find_dir != sdb_dir_entry_r(sdb)) ||
 3482                                 (last_find_drive != sdb_drive_letter(sdb)))) {
 3483             Debug0((dbg_fd, "last_template!=this_template. popping. %.8s,%.3s\n", last_find_name, last_find_ext));
 3484             Debug0((dbg_fd, "last_dir=%x,last_drive=%d sdb_dir=%d,sdb_drive=%d\n", last_find_dir, last_find_drive, sdb_dir_entry_r(sdb), sdb_drive_letter(sdb)));
 3485             hlist = hlist_pop();
 3486             
 3487             strncpy(last_find_name, sdb_template_name(sdb), 8);
 3488             strncpy(last_find_ext, sdb_template_ext(sdb), 3);
 3489             last_find_dir = sdb_dir_entry_r(sdb);
 3490             last_find_drive = sdb_drive_letter(sdb);
 3491             /*
 3492                if (hlist == NULL)
 3493                {
 3494                Debug0((dbg_fd,"double popping!!\n"));
 3495                hlist = hlist_pop ();
 3496                }
 3497                */
 3498         }
 3499         
 3500         attr = sdb_attribute(sdb);
 3501         goto find_again;
 3502     case CLOSE_ALL:     /* 0x1d */
 3503         Debug0((dbg_fd, "Close All\n"));
 3504         break;
 3505     case FLUSH_ALL_DISK_BUFFERS:    /* 0x20 */
 3506         Debug0((dbg_fd, "Flush Disk Buffers\n"));
 3507         break;
 3508     case SEEK_FROM_EOF:     /* 0x21 */
 3509     {
 3510         int offset = (state->ecx << 16) + (state->edx);
 3511         
 3512         fd = sft_fd_r(sft);
 3513         Debug0((dbg_fd, "Seek From EOF fd=%x ofs=%d\n",
 3514                 fd, offset));
 3515         if (offset > 0)
 3516             offset = -offset;
 3517         offset = lseek(fd, offset, SEEK_END);
 3518         Debug0((dbg_fd, "Seek returns fs=%d ofs=%d\n",
 3519                 fd, offset));
 3520         if (offset != -1) {
 3521             sft_position_w(sft, offset);
 3522             state->edx = offset >> 16;
 3523             state->eax = WORD(offset);
 3524             return (TRUE);
 3525         }
 3526         else {
 3527             SETWORD(&(state->eax), SEEK_ERROR);
 3528             return (FALSE);
 3529         }
 3530     }
 3531         break;
 3532     case QUALIFY_FILENAME:  /* 0x23 */
 3533     {
 3534         char *fn = (char *) Addr(state, ds, esi);
 3535         char *qfn = (char *) Addr(state, es, edi);
 3536         char *cpath = cds_current_path(cds);
 3537         
 3538 #if DOQUALIFY
 3539         if (fn[1] == ':') {
 3540             if (fn[2] == '\\')
 3541                 strcpy(qfn, fn);
 3542             else {
 3543                 strcpy(qfn, cpath);
 3544                 if (cpath[strlen(cpath) - 1] != '\\')
 3545                     strcat(qfn, "\\");
 3546                 strcat(qfn, fn + 2);
 3547             }
 3548         }
 3549         else {
 3550             strcpy(qfn, cpath);
 3551             strcat(qfn, fn);
 3552         }
 3553         Debug0((dbg_fd, "Qualify filename %s->%s\n", fn, qfn));
 3554         return (TRUE);
 3555 #else
 3556         Debug0((dbg_fd, "Qualify filename %s\n", fn));
 3557 #endif
 3558     }
 3559         break;
 3560     case LOCK_FILE_REGION:  /* 0x0a */
 3561         Debug0((dbg_fd, "Lock file region\n"));
 3562         return (TRUE);
 3563         break;
 3564     case UNLOCK_FILE_REGION:    /* 0x0b */
 3565         Debug0((dbg_fd, "Unlock file region\n"));
 3566         break;
 3567     case PROCESS_TERMINATED:    /* 0x22*/
 3568         Debug0((dbg_fd, "Process terminated\n"));
 3569         if (find_in_progress) {
 3570             while ((int) hlist_stack_indx != (int) NULL) {
 3571                 free_list(hlist);
 3572                 hlist = hlist_pop();
 3573             }
 3574             find_in_progress = FALSE;
 3575         }
 3576         return (REDIRECT);
 3577     case CONTROL_REDIRECT:  /* 0x1e */
 3578         /* get low word of parameter, should be one of 2, 3, 4, 5 */
 3579         /* ### Changed next line from *(u_short *)... to Read2Bytes(u_short,...) ### */
 3580         subfunc = LOW(Read2Bytes(u_short,Addr(state, ss, uesp)));
 3581         Debug0((dbg_fd, "Control redirect, subfunction %d\n",
 3582                 subfunc));
 3583         switch (subfunc) {
 3584             /* XXXTRB - need to support redirection index pass-thru */
 3585         case GET_REDIRECTION:
 3586         case EXTENDED_GET_REDIRECTION:
 3587             return (GetRedirection(state, WORD(state->ebx)));
 3588             break;
 3589         case REDIRECT_DEVICE:
 3590             return (RedirectDevice(state));
 3591             break;
 3592         case CANCEL_REDIRECTION:
 3593             return (CancelRedirection(state));
 3594             break;
 3595         default:
 3596             SETWORD(&(state->eax), FUNC_NUM_IVALID);
 3597             return (FALSE);
 3598             break;
 3599         }
 3600         break;
 3601     case COMMIT_FILE:       /* 0x07 */
 3602         Debug0((dbg_fd, "Commit\n"));
 3603         break;
 3604     case MULTIPURPOSE_OPEN:
 3605     {
 3606         boolean_t file_exists;
 3607         u_short action = sda_ext_act(sda);
 3608         
 3609         mode = sda_ext_mode(sda) & 0x7f;
 3610         /* ### Changed next line from *(u_short *)... to Read2Bytes(u_short,...) ### */
 3611         attr = Read2Bytes(u_short,Addr(state, ss, uesp));
 3612         Debug0((dbg_fd, "Multipurpose open file: %s\n", filename1));
 3613         Debug0((dbg_fd, "Mode, action, attr = %x, %x, %x\n",
 3614                 mode, action, attr));
 3615         
 3616         build_ufs_path(fpath, filename1);
 3617         file_exists = find_file(fpath, &st);
 3618         
 3619         if (((action & 0x10) == 0) && !file_exists) {
 3620             /* Fail if file does not exist */
 3621             SETWORD(&(state->eax), FILE_NOT_FOUND);
 3622             return (FALSE);
 3623         }
 3624         
 3625         if (((action & 0xf) == 0) && file_exists) {
 3626             /* Fail if file does exist */
 3627             SETWORD(&(state->eax), FILE_ALREADY_EXISTS);
 3628             return (FALSE);
 3629         }
 3630         
 3631         if (((action & 0xf) == 1) && file_exists) {
 3632             /* Open if does exist */
 3633             SETWORD(&(state->ecx), 0x1);
 3634             goto do_open_existing;
 3635         }
 3636         
 3637         if (((action & 0xf) == 2) && file_exists) {
 3638             /* Replace if file exists */
 3639             SETWORD(&(state->ecx), 0x3);
 3640             goto do_create_truncate;
 3641         }
 3642         
 3643         if (((action & 0x10) != 0) && !file_exists) {
 3644             /* Replace if file exists */
 3645             SETWORD(&(state->ecx), 0x2);
 3646             goto do_create_truncate;
 3647         }
 3648         
 3649         Debug0((dbg_fd, "Multiopen failed: 0x%02x\n",
 3650                 (int) LOW(state->eax)));
 3651         /* Fail if file does exist */
 3652         SETWORD(&(state->eax), FILE_NOT_FOUND);
 3653         return (FALSE);
 3654     }
 3655     case EXTENDED_ATTRIBUTES:{
 3656         switch (LOW(state->ebx)) {
 3657         case 2:         /* get extended attributes */
 3658         case 3:         /* get extended attribute properties */
 3659             if (WORD(state->ecx) >= 2) {
 3660                 *(short *) (Addr(state, es, edi)) = 0;
 3661                 SETWORD(&(state->ecx), 0x2);
 3662             }
 3663         case 4:         /* set extended attributes */
 3664             return (TRUE);
 3665         }
 3666         return (FALSE);
 3667     }
 3668     case PRINTER_MODE:{
 3669         SETLOW(&(state->edx), 1);
 3670         return (TRUE);
 3671     }
 3672 #ifdef UNDOCUMENTED_FUNCTION_2
 3673     case UNDOCUMENTED_FUNCTION_2:
 3674         Debug0((dbg_fd, "Undocumented function: %02x\n",
 3675                 (int) LOW(state->eax)));
 3676         return (TRUE);
 3677 #endif
 3678     case PRINTER_SETUP:
 3679         SETWORD(&(state->ebx), WORD(state->ebx) - redirected_drives);
 3680         Debug0((dbg_fd, "Passing %d to PRINTER SETUP CALL\n",
 3681                 (int) WORD(state->ebx)));
 3682         return (REDIRECT);
 3683     default:
 3684         Debug0((dbg_fd, "Default for undocumented function: %02x\n",
 3685                 (int) LOW(state->eax)));
 3686         return (REDIRECT);
 3687     }
 3688     return (ret);
 3689 }
 3690 
 3691 #endif