home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / mtools2 / part03 < prev    next >
Encoding:
Text File  |  1992-01-10  |  40.8 KB  |  1,615 lines

  1. Newsgroups: comp.sources.unix
  2. From: fthood!egray@uxc.cso.uiuc.edu (Emmet P. Gray)
  3. Subject: v25i099: mtools2 - tools to manipulate MSDOS filesystems, V2.0, Part03/03
  4. Sender: sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: fthood!egray@uxc.cso.uiuc.edu (Emmet P. Gray)
  8. Posting-Number: Volume 25, Issue 99
  9. Archive-Name: mtools2/part03
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 3 (of 3)."
  18. # Contents:  mtools/Makefile mtools/init.c mtools/mdir.c mtools/mread.c
  19. #   mtools/mwrite.c
  20. # Wrapped by lai@risotto on Sat Jan 11 12:03:35 1992
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'mtools/Makefile' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'mtools/Makefile'\"
  24. else
  25. echo shar: Extracting \"'mtools/Makefile'\" \(6713 characters\)
  26. sed "s/^X//" >'mtools/Makefile' <<'END_OF_FILE'
  27. X#
  28. X#       Makefile for Mtools
  29. X#
  30. X# check the Configure file for some examples of device-specific setups
  31. X# Berkeley flavors of Unix should include -DBSD in the CFLAGS
  32. X
  33. XCFLAGS    = -O
  34. XLDFLAGS    = -s
  35. XLD    = cc
  36. XLINT    = lint
  37. XSHLIB    = 
  38. XSHAR    = shar -a
  39. XBINDIR    = /usr/local/bin
  40. XMANSECT    = 1
  41. XMANDIR    = /usr/man/man$(MANSECT)
  42. X#
  43. X# for AT&T Unix PC 7300/3b1 style shared libraries.
  44. X#SHOBJ    = /lib/crt0s.o /lib/shlib.ifile
  45. X#LD    = ld
  46. X
  47. XPROGS    = mattrib mcd mcopy mdel mdir mformat mlabel mmd mrd mread mren \
  48. X    mtype mwrite mkmanifest
  49. X
  50. XMATTRIB    = mattrib.o buf_read.o buf_write.o devices.o dir_read.o \
  51. X    dir_write.o expand.o fat_read.o init.o match.o parse.o subdir.o
  52. XMCD    = mcd.o buf_read.o devices.o dir_read.o expand.o fat_read.o \
  53. X    init.o is_dir.o match.o parse.o subdir.o
  54. XMCOPY    = mcopy.o
  55. XMDEL    = mdel.o buf_read.o buf_write.o devices.o dir_read.o dir_write.o \
  56. X    expand.o fat_free.o fat_read.o fat_write.o init.o match.o parse.o \
  57. X    subdir.o 
  58. XMDIR    = mdir.o buf_read.o devices.o dir_read.o expand.o fat_read.o \
  59. X    init.o is_dir.o match.o parse.o subdir.o
  60. XMFORMAT    = mformat.o devices.o dir_write.o expand.o
  61. XMLABEL    = mlabel.o buf_read.o buf_write.o devices.o dir_read.o \
  62. X    dir_write.o expand.o fat_read.o init.o 
  63. XMMD    = mmd.o buf_read.o buf_write.o devices.o dir_make.o dir_read.o \
  64. X    dir_write.o expand.o fat_read.o fat_write.o init.o match.o parse.o \
  65. X    subdir.o
  66. XMRD    = mrd.o buf_read.o buf_write.o devices.o dir_read.o dir_write.o \
  67. X    expand.o fat_free.o fat_read.o fat_write.o init.o match.o parse.o \
  68. X    subdir.o
  69. XMREAD    = mread.o buf_read.o devices.o dir_read.o expand.o fat_read.o \
  70. X    file_read.o init.o match.o parse.o subdir.o
  71. XMREN    = mren.o buf_read.o buf_write.o devices.o dir_read.o dir_write.o \
  72. X    expand.o fat_read.o init.o match.o parse.o subdir.o
  73. XMTYPE    = mtype.o buf_read.o devices.o dir_read.o expand.o fat_read.o \
  74. X    file_read.o init.o match.o parse.o subdir.o
  75. XMWRITE    = mwrite.o buf_read.o buf_write.o devices.o dir_make.o \
  76. X    dir_read.o dir_write.o expand.o fat_free.o fat_read.o fat_write.o \
  77. X    file_write.o init.o is_dir.o match.o parse.o subdir.o
  78. XMKMANIFEST = mkmanifest.o
  79. X
  80. Xall:    $(PROGS)
  81. X
  82. Xmattrib: $(MATTRIB)
  83. X    $(LD) $(LDFLAGS) $(MATTRIB) $(SHOBJ) -o mattrib $(SHLIB)
  84. X
  85. Xmcd:    $(MCD)
  86. X    $(LD) $(LDFLAGS) $(MCD) $(SHOBJ) -o mcd $(SHLIB)
  87. X
  88. Xmcopy:    $(MCOPY)
  89. X    $(LD) $(LDFLAGS) $(MCOPY) $(SHOBJ) -o mcopy $(SHLIB)
  90. X
  91. Xmdel:    $(MDEL)
  92. X    $(LD) $(LDFLAGS) $(MDEL) $(SHOBJ) -o mdel $(SHLIB)
  93. X
  94. Xmdir:    $(MDIR)
  95. X    $(LD) $(LDFLAGS) $(MDIR) $(SHOBJ) -o mdir $(SHLIB)
  96. X
  97. Xmformat: $(MFORMAT)
  98. X    $(LD) $(LDFLAGS) $(MFORMAT) $(SHOBJ) -o mformat $(SHLIB)
  99. X
  100. Xmlabel:    $(MLABEL)
  101. X    $(LD) $(LDFLAGS) $(MLABEL) $(SHOBJ) -o mlabel $(SHLIB)
  102. X
  103. Xmmd:    $(MMD)
  104. X    $(LD) $(LDFLAGS) $(MMD) $(SHOBJ) -o mmd $(SHLIB)
  105. X
  106. Xmrd:    $(MRD)
  107. X    $(LD) $(LDFLAGS) $(MRD) $(SHOBJ) -o mrd $(SHLIB)
  108. X
  109. Xmread:    $(MREAD)
  110. X    $(LD) $(LDFLAGS) $(MREAD) $(SHOBJ) -o mread $(SHLIB)
  111. X
  112. Xmren:    $(MREN)
  113. X    $(LD) $(LDFLAGS) $(MREN) $(SHOBJ) -o mren $(SHLIB)
  114. X
  115. Xmtype:    $(MTYPE)
  116. X    $(LD) $(LDFLAGS) $(MTYPE) $(SHOBJ) -o mtype $(SHLIB)
  117. X
  118. Xmwrite:    $(MWRITE)
  119. X    $(LD) $(LDFLAGS) $(MWRITE) $(SHOBJ) -o mwrite $(SHLIB)
  120. X
  121. Xmkmanifest:    $(MKMANIFEST)
  122. X    $(LD) $(LDFLAGS) $(MKMANIFEST) $(SHOBJ) -o mkmanifest $(SHLIB)
  123. X
  124. Xinstall:
  125. X    cp $(PROGS) $(BINDIR)
  126. X
  127. Xinstall_man:
  128. X    cp Mattrib.1 $(MANDIR)/mattrib.$(MANSECT)
  129. X    cp Mcd.1 $(MANDIR)/mcd.$(MANSECT)
  130. X    cp Mcopy.1 $(MANDIR)/mcopy.$(MANSECT)
  131. X    cp Mdel.1 $(MANDIR)/mdel.$(MANSECT)
  132. X    cp Mdir.1 $(MANDIR)/mdir.$(MANSECT)
  133. X    cp Mformat.1 $(MANDIR)/mformat.$(MANSECT)
  134. X    cp Mlabel.1 $(MANDIR)/mlabel.$(MANSECT)
  135. X    cp Mmd.1 $(MANDIR)/mmd.$(MANSECT)
  136. X    cp Mrd.1 $(MANDIR)/mrd.$(MANSECT)
  137. X    cp Mread.1 $(MANDIR)/mread.$(MANSECT)
  138. X    cp Mren.1 $(MANDIR)/mren.$(MANSECT)
  139. X    cp Mtools.1 $(MANDIR)/mtools.$(MANSECT)
  140. X    cp Mtype.1 $(MANDIR)/mtype.$(MANSECT)
  141. X    cp Mwrite.1 $(MANDIR)/mwrite.$(MANSECT)
  142. X    cp Mkmanifest.1 $(MANDIR)/mkmanifest.$(MANSECT)
  143. X
  144. Xclean:
  145. X    rm $(PROGS)
  146. X
  147. Xlint:
  148. X    $(LINT) mattrib.c buf_read.c buf_write.c devices.c dir_read.c \
  149. X    dir_write.c expand.c fat_read.c init.c match.c parse.c subdir.c
  150. X    $(LINT) mcd.c buf_read.c devices.c dir_read.c expand.c fat_read.c \
  151. X    init.c is_dir.c match.c parse.c subdir.c
  152. X    $(LINT) mcopy.c
  153. X    $(LINT) mdel.c buf_read.c buf_write.c devices.c dir_read.c dir_write.c \
  154. X    expand.c fat_free.c fat_read.c fat_write.c init.c match.c parse.c \
  155. X    subdir.c 
  156. X    $(LINT) mdir.c buf_read.c devices.c dir_read.c expand.c fat_read.c \
  157. X    init.c is_dir.c match.c parse.c subdir.c
  158. X    $(LINT) mformat.c devices.c dir_write.c expand.c
  159. X    $(LINT) mlabel.c buf_read.c buf_write.c devices.c dir_read.c \
  160. X    dir_write.c expand.c fat_read.c init.c 
  161. X    $(LINT) mmd.c buf_read.c buf_write.c devices.c dir_make.c dir_read.c \
  162. X    dir_write.c expand.c fat_read.c fat_write.c init.c match.c parse.c \
  163. X    subdir.c
  164. X    $(LINT) mrd.c buf_read.c buf_write.c devices.c dir_read.c dir_write.c \
  165. X    expand.c fat_free.c fat_read.c fat_write.c init.c match.c parse.c \
  166. X    subdir.c
  167. X    $(LINT) mread.c buf_read.c devices.c dir_read.c expand.c fat_read.c \
  168. X    file_read.c init.c match.c parse.c subdir.c
  169. X    $(LINT) mren.c buf_read.c buf_write.c devices.c dir_read.c dir_write.c \
  170. X    expand.c fat_read.c init.c match.c parse.c subdir.c
  171. X    $(LINT) mtype.c buf_read.c devices.c dir_read.c expand.c fat_read.c \
  172. X    file_read.c init.c match.c parse.c subdir.c
  173. X    $(LINT) mwrite.c buf_read.c buf_write.c devices.c dir_make.c \
  174. X    dir_read.c dir_write.c expand.c fat_free.c fat_read.c fat_write.c \
  175. X    file_write.c init.c is_dir.c match.c parse.c subdir.c
  176. X    $(LINT) mkmanifest.c
  177. X
  178. Xshar:
  179. X    $(SHAR) Configure Makefile Mattrib.1 Mcd.1 Mcopy.1 Mdel.1 Mdir.1 \
  180. X    Mformat.1 Mkmanifest.1 Mlabel.1 Mmd.1 Mrd.1 Mread.1 Mren.1 \
  181. X    Mtools.1 Mtype.1 Mwrite.1 Readme Release.notes buf_read.c \
  182. X    buf_write.c devices.c dir_make.c dir_read.c dir_write.c expand.c \
  183. X    fat_free.c > mtools_sh.1
  184. X    $(SHAR) fat_read.c fat_write.c file_read.c file_write.c init.c \
  185. X    is_dir.c match.c mattrib.c mcd.c mcopy.c mdel.c mdir.c mformat.c \
  186. X    mkmanifest.c mlabel.c mmd.c > mtools_sh.2
  187. X    $(SHAR) mrd.c mread.c mren.c msdos.h mtype.c mwrite.c parse.c \
  188. X    patchlevel.h subdir.c > mtools_sh.3
  189. X    $(SHAR) Mattrib.out Mcd.out Mcopy.out Mdel.out Mdir.out Mformat.out \
  190. X    Mkmanifest.out Mlabel.out Mmd.out Mrd.out Mread.out Mren.out \
  191. X    Mtools.out Mtype.out Mwrite.out > mtools_sh.4
  192. X
  193. Xbuf_read.o:    msdos.h
  194. Xbuf_write.o:    msdos.h
  195. Xdevices.o:    msdos.h
  196. Xdir_make.o:    msdos.h
  197. Xdir_read.o:    msdos.h
  198. Xdir_write.o:    msdos.h
  199. Xfat_free.o:    msdos.h
  200. Xfat_read.o:    msdos.h
  201. Xfat_write.o:    msdos.h
  202. Xfile_read.o:    msdos.h
  203. Xfile_write.o:    msdos.h
  204. Xinit.o:        msdos.h
  205. Xis_dir.o:    msdos.h
  206. Xmattrib.o:    msdos.h patchlevel.h
  207. Xmcd.o:        msdos.h patchlevel.h
  208. Xmcopy.o:    patchlevel.h
  209. Xmdel.o:        msdos.h patchlevel.h
  210. Xmdir.o:        msdos.h patchlevel.h
  211. Xmformat.o:    msdos.h patchlevel.h
  212. Xmlabel.o:    msdos.h patchlevel.h
  213. Xmmd.o:        msdos.h patchlevel.h
  214. Xmrd.o:        msdos.h patchlevel.h
  215. Xmread.o:    msdos.h patchlevel.h
  216. Xmren.o:        msdos.h patchlevel.h
  217. Xmtype.o:    msdos.h patchlevel.h
  218. Xmwrite.o:    msdos.h patchlevel.h
  219. Xparse.o:    msdos.h
  220. Xsubdir.o:    msdos.h
  221. END_OF_FILE
  222. if test 6713 -ne `wc -c <'mtools/Makefile'`; then
  223.     echo shar: \"'mtools/Makefile'\" unpacked with wrong size!
  224. fi
  225. # end of 'mtools/Makefile'
  226. fi
  227. if test -f 'mtools/init.c' -a "${1}" != "-c" ; then 
  228.   echo shar: Will not clobber existing file \"'mtools/init.c'\"
  229. else
  230. echo shar: Extracting \"'mtools/init.c'\" \(7669 characters\)
  231. sed "s/^X//" >'mtools/init.c' <<'END_OF_FILE'
  232. X/*
  233. X * Initialize an MSDOS diskette.  Read the boot sector, and switch to the
  234. X * proper floppy disk device to match the format on the disk.  Sets a bunch
  235. X * of global variables.  Returns 0 on success, or 1 on failure.
  236. X */
  237. X
  238. X#include <stdio.h>
  239. X#include <ctype.h>
  240. X#include <sys/types.h>
  241. X#include <sys/stat.h>
  242. X#include "msdos.h"
  243. X
  244. X#define FULL_CYL
  245. X#define WORD(x) ((boot->x)[0] + ((boot->x)[1] << 8))
  246. X#define DWORD(x) ((boot->x)[0] + ((boot->x)[1] << 8) + ((boot->x)[2] << 16) + ((boot->x)[3] << 24))
  247. X
  248. Xunsigned int num_clus;            /* total number of cluster */
  249. Xint num_fat;                /* the number of FAT tables */
  250. Xlong disk_offset;            /* skip this many bytes */
  251. Xint fat_bits;                /* the FAT encoding scheme */
  252. X
  253. Xextern int fd, fat_len, dir_len, dir_start, clus_size, dir_dirty, disk_dirty;
  254. Xextern int fat_error, disk_size;
  255. Xextern long disk_current;
  256. Xextern char *mcwd;
  257. Xextern unsigned char *fat_buf, *disk_buf, *dir_buf;
  258. Xextern struct device devices[];
  259. Xstatic struct bootsector *read_boot();
  260. X
  261. Xint
  262. Xinit(drive, mode)
  263. Xchar drive;
  264. Xint mode;
  265. X{
  266. X    int fat_start, tracks, heads, sectors, old_dos;
  267. X    char *malloc(), *name, *expand();
  268. X    void perror(), exit(), reset_chain(), free(), fat_read();
  269. X    struct bootsector *boot;
  270. X    struct device *dev;
  271. X
  272. X    if (fd != -1) {
  273. X        close(fd);
  274. X        free((char *) fat_buf);
  275. X        free((char *) disk_buf);
  276. X        free((char *) dir_buf);
  277. X    }
  278. X                    /* check out the drive letter */
  279. X    dev = devices;
  280. X    while (dev->drive) {
  281. X        if (dev->drive == drive)
  282. X            break;
  283. X        dev++;
  284. X    }
  285. X    if (!dev->drive) {
  286. X        fprintf(stderr, "Drive '%c:' not supported\n", drive);
  287. X        return(1);
  288. X    }
  289. X                    /* open the device */
  290. X    while (dev->name) {
  291. X        if (dev->drive != drive)
  292. X            break;
  293. X
  294. X        name = expand(dev->name);
  295. X        if ((fd = open(name, mode | dev->mode)) < 0) {
  296. X            perror("init: open");
  297. X            exit(1);
  298. X        }
  299. X                    /* set default parameters, if needed */
  300. X        if (dev->gioctl) {
  301. X            if ((*(dev->gioctl)) (fd, dev->tracks, dev->heads, dev->sectors))
  302. X                goto try_again;
  303. X        }
  304. X                    /* read the boot sector */
  305. X        disk_offset = dev->offset;
  306. X        if ((boot = read_boot()) == NULL)
  307. X            goto try_again;
  308. X
  309. X        heads = WORD(nheads);
  310. X        sectors = WORD(nsect);
  311. X        if (heads && sectors)
  312. X            tracks = WORD(psect) / (unsigned) (heads * sectors);
  313. X
  314. X                    /* sanity checking */
  315. X        old_dos = 0;
  316. X        if (!heads || heads > 100 || !sectors || sectors > 500 || tracks > 5000 || !boot->clsiz) {
  317. X            /*
  318. X             * The above technique will fail on diskettes that
  319. X             * have been formatted with very old MSDOS, so we
  320. X             * resort to the old table-driven method using the
  321. X             * media signature (first byte in FAT).
  322. X             */
  323. X            unsigned char temp[MSECTOR_SIZE];
  324. X            if (read(fd, (char *) temp, MSECTOR_SIZE) != MSECTOR_SIZE)
  325. X                temp[0] = '0';
  326. X
  327. X            switch (temp[0]) {
  328. X                case 0xfe:    /* 160k */
  329. X                    tracks = 40;
  330. X                    sectors = 8;
  331. X                    heads = 1;
  332. X                    dir_start = 3;
  333. X                    dir_len = 4;
  334. X                    clus_size = 1;
  335. X                    fat_len = 1;
  336. X                    num_clus = 313;
  337. X                    break;
  338. X                case 0xfc:    /* 180k */
  339. X                    tracks = 40;
  340. X                    sectors = 9;
  341. X                    heads = 1;
  342. X                    dir_start = 5;
  343. X                    dir_len = 4;
  344. X                    clus_size = 1;
  345. X                    fat_len = 2;
  346. X                    num_clus = 351;
  347. X                    break;
  348. X                case 0xff:    /* 320k */
  349. X                    tracks = 40;
  350. X                    sectors = 8;
  351. X                    heads = 2;
  352. X                    dir_start = 3;
  353. X                    dir_len = 7;
  354. X                    clus_size = 2;
  355. X                    fat_len = 1;
  356. X                    num_clus = 315;
  357. X                    break;
  358. X                case 0xfd:    /* 360k */
  359. X                    tracks = 40;
  360. X                    sectors = 9;
  361. X                    heads = 2;
  362. X                    dir_start = 5;
  363. X                    dir_len = 7;
  364. X                    clus_size = 2;
  365. X                    fat_len = 2;
  366. X                    num_clus = 354;
  367. X                    break;
  368. X                default:
  369. X                    fprintf(stderr, "Probable non-MSDOS disk\n");
  370. X                    close(fd);
  371. X                    fd = -1;
  372. X                    return(1);
  373. X            }
  374. X            fat_start = 1;
  375. X            num_fat = 2;
  376. X            old_dos = 1;
  377. X        }
  378. X                    /* check the parameters */
  379. X        if (dev->tracks && !dev->gioctl) {
  380. X            if (dev->tracks == tracks && dev->heads == heads && dev->sectors == sectors)
  381. X                break;
  382. X        }
  383. X        else
  384. X            break;
  385. X
  386. Xtry_again:    close(fd);
  387. X        fd = -1;
  388. X        dev++;
  389. X    }
  390. X    if (fd == -1) {
  391. X        if (boot != NULL && dev->tracks)
  392. X            fprintf(stderr, "No support for %d tracks, %d heads, %d sector diskettes\n", tracks, heads, sectors);
  393. X        return(1);
  394. X    }
  395. X                    /* set new parameters, if needed */
  396. X    if (dev->gioctl) {
  397. X        if ((*(dev->gioctl)) (fd, tracks, heads, sectors)) {
  398. X            fprintf(stderr, "Can't set disk parameters\n");
  399. X            close(fd);
  400. X            fd = -1;
  401. X            return(1);
  402. X        }
  403. X    }
  404. X
  405. X    /*
  406. X     * all numbers are in sectors, except num_clus (which is in clusters)
  407. X     */
  408. X    if (!old_dos) {
  409. X        clus_size = boot->clsiz;
  410. X        fat_start = WORD(nrsvsect);
  411. X        fat_len = WORD(fatlen);
  412. X        dir_start = fat_start + (boot->nfat * fat_len);
  413. X        dir_len = WORD(dirents) * MDIR_SIZE / (unsigned) MSECTOR_SIZE;
  414. X        /*
  415. X         * For DOS partitions > 32M
  416. X         */
  417. X        if (WORD(psect) == 0)
  418. X            num_clus = (unsigned int) (DWORD(bigsect) - dir_start - dir_len) / clus_size;
  419. X        else
  420. X            num_clus = (unsigned int) (WORD(psect) - dir_start - dir_len) / clus_size;
  421. X        num_fat = boot->nfat;
  422. X    }
  423. X                    /* more sanity checking */
  424. X    if (clus_size * MSECTOR_SIZE > MAX_CLUSTER) {
  425. X        fprintf(stderr, "Cluster size of %d is larger than max of %d\n", clus_size * MSECTOR_SIZE, MAX_CLUSTER);
  426. X        close(fd);
  427. X        fd = -1;
  428. X        return(1);
  429. X    }
  430. X    if (!old_dos && WORD(secsiz) != MSECTOR_SIZE) {
  431. X        fprintf(stderr, "Sector size of %d is not supported\n", WORD(secsiz));
  432. X        close(fd);
  433. X        fd = -1;
  434. X        return(1);
  435. X    }
  436. X                    /* full cylinder buffering */
  437. X#ifdef FULL_CYL
  438. X    disk_size = (dev->tracks) ? (sectors * heads) : 1;
  439. X#else /* FULL_CYL */
  440. X    disk_size = (dev->tracks) ? sectors : 1;
  441. X#endif /* FULL_CYL */
  442. X
  443. X/*
  444. X * The driver in Dell's SVR4 v2.01 is unreliable with large writes.
  445. X */
  446. X#ifdef DELL
  447. X    disk_size = 1;
  448. X#endif /* DELL */
  449. X
  450. X    disk_buf = (unsigned char *) malloc((unsigned int) disk_size * MSECTOR_SIZE);
  451. X    if (disk_buf == NULL) {
  452. X        perror("init: malloc");
  453. X        exit(1);
  454. X    }
  455. X                    /* read the FAT sectors */
  456. X    disk_current = -1000L;
  457. X    disk_dirty = 0;
  458. X    fat_error = 0;
  459. X    fat_bits = dev->fat_bits;
  460. X    fat_read(fat_start);
  461. X                    /* set dir_chain[] to root directory */
  462. X    dir_dirty = 0;
  463. X    reset_chain(NEW);
  464. X    return(0);
  465. X}
  466. X
  467. X/*
  468. X * Fix the info in the MCWD file to be a proper directory name.  Always
  469. X * has a leading separator.  Never has a trailing separator (unless it is
  470. X * the path itself).
  471. X */
  472. X
  473. Xchar *
  474. Xfix_mcwd()
  475. X{
  476. X    FILE *fp;
  477. X    struct stat sbuf;
  478. X    char *s, *strcpy(), *strcat(), *mcwd_path, *getenv(), *strncpy();
  479. X    char buf[BUFSIZ], *file, *expand();
  480. X    static char ans[MAX_PATH];
  481. X    long now, time();
  482. X
  483. X    mcwd_path = getenv("MCWD");
  484. X    if (mcwd_path == NULL || *mcwd_path == '\0')
  485. X        mcwd_path = "$HOME/.mcwd";
  486. X
  487. X    file = expand(mcwd_path);
  488. X    if (stat(file, &sbuf) < 0)
  489. X        return("A:/");
  490. X    /*
  491. X     * Ignore the info, if the file is more than 6 hours old
  492. X     */
  493. X    time(&now);
  494. X    if (now - sbuf.st_mtime > 6 * 60 * 60) {
  495. X        fprintf(stderr, "Warning: \"%s\" is out of date, contents ignored\n", file);
  496. X        return("A:/");
  497. X    }
  498. X    
  499. X    if (!(fp = fopen(file, "r")))
  500. X        return("A:/");
  501. X
  502. X    if (!fgets(buf, BUFSIZ, fp))
  503. X        return("A:/");
  504. X
  505. X    buf[strlen(buf) -1] = '\0';
  506. X    fclose(fp);
  507. X                    /* drive letter present? */
  508. X    s = buf;
  509. X    if (buf[0] && buf[1] == ':') {
  510. X        strncpy(ans, buf, 2);
  511. X        ans[2] = '\0';
  512. X        s = &buf[2];
  513. X    }
  514. X    else 
  515. X        strcpy(ans, "A:");
  516. X                    /* add a leading separator */
  517. X    if (*s != '/' && *s != '\\') {
  518. X        strcat(ans, "/");
  519. X        strcat(ans, s);
  520. X    }
  521. X    else
  522. X        strcat(ans, s);
  523. X                    /* translate to upper case */
  524. X    for (s = ans; *s; ++s) {
  525. X        if (islower(*s))
  526. X            *s = toupper(*s);
  527. X        if (*s == '\\')
  528. X            *s = '/';
  529. X    }
  530. X                    /* if only drive, colon, & separator */
  531. X    if (strlen(ans) == 3)
  532. X        return(ans);
  533. X                    /* zap the trailing separator */
  534. X    if (*--s == '/')
  535. X        *s = '\0';
  536. X    return(ans);
  537. X}
  538. X
  539. X/*
  540. X * Read the boot sector.  We glean the disk parameters from this sector.
  541. X */
  542. X
  543. Xstatic struct bootsector *
  544. Xread_boot()
  545. X{
  546. X    long lseek();
  547. X    static struct bootsector boot;
  548. X
  549. X    if (lseek(fd, disk_offset, 0) < 0)
  550. X        return(NULL);
  551. X                    /* read the first sector */
  552. X    if (read(fd, (char *) &boot, MSECTOR_SIZE) != MSECTOR_SIZE)
  553. X        return(NULL);
  554. X
  555. X    return(&boot);
  556. X}
  557. END_OF_FILE
  558. if test 7669 -ne `wc -c <'mtools/init.c'`; then
  559.     echo shar: \"'mtools/init.c'\" unpacked with wrong size!
  560. fi
  561. # end of 'mtools/init.c'
  562. fi
  563. if test -f 'mtools/mdir.c' -a "${1}" != "-c" ; then 
  564.   echo shar: Will not clobber existing file \"'mtools/mdir.c'\"
  565. else
  566. echo shar: Extracting \"'mtools/mdir.c'\" \(7059 characters\)
  567. sed "s/^X//" >'mtools/mdir.c' <<'END_OF_FILE'
  568. X/*
  569. X * Display an MSDOS directory
  570. X *
  571. X * Emmet P. Gray            US Army, HQ III Corps & Fort Hood
  572. X * ...!uunet!uiucuxc!fthood!egray    Attn: AFZF-DE-ENV
  573. X * fthood!egray@uxc.cso.uiuc.edu    Directorate of Engineering & Housing
  574. X *                     Environmental Management Office
  575. X *                     Fort Hood, TX 76544-5057
  576. X */
  577. X
  578. X#include <stdio.h>
  579. X#include "msdos.h"
  580. X#include "patchlevel.h"
  581. X
  582. Xint fd = -1;                /* the file descriptor for the device */
  583. Xint dir_start;                /* starting sector for directory */
  584. Xint dir_len;                /* length of directory (in sectors) */
  585. Xint dir_entries;            /* number of directory entries */
  586. Xint clus_size;                /* cluster size (in sectors) */
  587. Xchar *mcwd;                /* the Current Working Directory */
  588. Xint fat_error;                /* FAT error detected? */
  589. X
  590. Xstatic long getfree();
  591. Xstatic char *conv_date(), *conv_time();
  592. X
  593. Xmain(argc, argv)
  594. Xint argc;
  595. Xchar *argv[];
  596. X{
  597. X    int i, entry, files, fargn, wide, faked;
  598. X    long size, blocks;
  599. X    char *date, *time, last_drive, *fix_mcwd();
  600. X    char *strncpy(), newpath[MAX_PATH], *get_name(), *get_path(), *pathname;
  601. X    char *newfile, *filename, *unix_name(), volume[12], drive, *strpbrk();
  602. X    char *strcpy(), *strcat(), newname[13], *strncat(), get_drive();
  603. X    void exit();
  604. X    struct directory *dir, *dir_read();
  605. X
  606. X    fargn = 1;
  607. X    wide = 0;
  608. X    files = 0;
  609. X                    /* first argument */
  610. X    if (argc > 1) {
  611. X        if (!strcmp(argv[1], "-w")) {
  612. X            wide = 1;
  613. X            fargn = 2;
  614. X        }
  615. X        if (argv[1][0] == '-' && !wide) {
  616. X            fprintf(stderr, "%s: illegal option -- %c\n", argv[0], argv[1][1]);
  617. X            fprintf(stderr, "Mtools version %s, dated %s\n", VERSION, DATE);
  618. X            fprintf(stderr, "Usage: %s: [-w] msdosdirectory\n", argv[0]);
  619. X            fprintf(stderr, "       %s: [-w] msdosfile [msdosfiles...]\n", argv[0]);
  620. X            exit(1);
  621. X        }
  622. X    }
  623. X                    /* fake an argument */
  624. X    faked = 0;
  625. X    if (argc == fargn) {
  626. X        faked++;
  627. X        argc++;
  628. X    }
  629. X    last_drive = 'x';
  630. X    mcwd = fix_mcwd();
  631. X
  632. X    for (i = fargn; i < argc; i++) {
  633. X        if (faked) {
  634. X            drive = get_drive("");
  635. X            filename = get_name("");
  636. X            pathname = get_path("");
  637. X        }
  638. X        else {
  639. X            drive = get_drive(argv[i]);
  640. X            filename = get_name(argv[i]);
  641. X            pathname = get_path(argv[i]);
  642. X        }
  643. X                    /* is this a new device? */
  644. X        if (drive != last_drive) {
  645. X            if (last_drive != 'x') {
  646. X                blocks = getfree() * MSECTOR_SIZE;
  647. X                if (!files)
  648. X                    printf("File \"%s\" not found\n\n", newname);
  649. X                else
  650. X                    printf("     %3d File(s)     %6ld bytes free\n\n", files, blocks);
  651. X            }
  652. X            if (init(drive, 0)) {
  653. X                fprintf(stderr, "%s: Cannot initialize '%c:'\n", argv[0], drive);
  654. X                continue;
  655. X            }
  656. X            last_drive = drive;
  657. X            files = 0;
  658. X                    /* find the volume label */
  659. X            volume[0] = '\0';
  660. X            for (entry = 0; entry < dir_entries; entry++) {
  661. X                dir = dir_read(entry);
  662. X
  663. X                    /* if empty */
  664. X                if (dir->name[0] == 0x0)
  665. X                    break;
  666. X
  667. X                    /* if erased */
  668. X                if (dir->name[0] == 0xe5)
  669. X                    continue;
  670. X
  671. X                    /* if not volume label */
  672. X                if (!(dir->attr & 0x08))
  673. X                    continue;
  674. X
  675. X                strncpy(volume, (char *) dir->name, 8);
  676. X                volume[8] = '\0';
  677. X                strncat(volume, (char *) dir->ext, 3);
  678. X                volume[11] = '\0';
  679. X                break;
  680. X            }
  681. X            if (volume[0] == '\0')
  682. X                printf(" Volume in drive %c has no label\n", drive);
  683. X            else
  684. X                printf(" Volume in drive %c is %s\n", drive, volume);
  685. X        }
  686. X
  687. X        /*
  688. X         * Move to "first guess" subdirectory, so that is_dir() can
  689. X         * search to see if filename is also a directory.
  690. X         */
  691. X        if (subdir(drive, pathname))
  692. X            continue;
  693. X
  694. X        /*
  695. X         * Under MSDOS, wildcards that match directories don't
  696. X         * display the contents of that directory.  So I guess I'll
  697. X         * do that too.
  698. X         */
  699. X        if ((strpbrk(filename, "*[?") == NULL) && is_dir(filename)) {
  700. X            strcpy(newpath, pathname);
  701. X            if (newpath[strlen(newpath) -1] != '/')
  702. X                strcat(newpath, "/");
  703. X            strcat(newpath, filename);
  704. X
  705. X                    /* move to real subdirectory */
  706. X            if (subdir(drive, newpath))
  707. X                continue;
  708. X
  709. X            strcpy(newname, "*");
  710. X        }
  711. X        else {
  712. X            strcpy(newpath, pathname);
  713. X            strcpy(newname, filename);
  714. X        }
  715. X                    /* if no files, assume '*' */
  716. X        if (*filename == '\0')
  717. X            strcpy(newname, "*");
  718. X
  719. X        printf(" Directory for %c:%s\n\n", drive, newpath);
  720. X
  721. X        for (entry = 0; entry < dir_entries; entry++) {
  722. X            dir = dir_read(entry);
  723. X                    /* if empty */
  724. X            if (dir->name[0] == 0x0)
  725. X                break;
  726. X                    /* if erased */
  727. X            if (dir->name[0] == 0xe5)
  728. X                continue;
  729. X                    /* if a volume label */
  730. X            if (dir->attr & 0x08)
  731. X                continue;
  732. X
  733. X            newfile = unix_name(dir->name, dir->ext);
  734. X            if (!match(newfile, newname))
  735. X                continue;
  736. X
  737. X            files++;
  738. X            if (wide && files != 1) {
  739. X                if (!((files - 1) % 5))
  740. X                    putchar('\n');
  741. X            }
  742. X            date = conv_date(dir->date[1], dir->date[0]);
  743. X            time = conv_time(dir->time[1], dir->time[0]);
  744. X            size = dir->size[3] * 0x1000000L + dir->size[2] * 0x10000L + dir->size[1] * 0x100 + dir->size[0];
  745. X                    /* is a subdirectory */
  746. X            if (dir->attr & 0x10) {
  747. X                if (wide)
  748. X                    printf("%-8.8s %-3.3s   ", dir->name, dir->ext);
  749. X                else
  750. X                    printf("%-8.8s %-3.3s     <DIR>     %s  %s\n", dir->name, dir->ext, date, time);
  751. X                continue;
  752. X            }
  753. X            if (wide)
  754. X                printf("%-8.8s %-3.3s   ", dir->name, dir->ext);
  755. X            else
  756. X                printf("%-8.8s %-3.3s    %8ld   %s  %s\n", dir->name, dir->ext, size, date, time);
  757. X        }
  758. X        if (argc > 2)
  759. X            putchar('\n');
  760. X    }
  761. X    if (fd < 0)
  762. X        exit(1);
  763. X
  764. X    blocks = getfree() * MSECTOR_SIZE;
  765. X    if (!files)
  766. X        printf("File \"%s\" not found\n", newname);
  767. X    else
  768. X        printf("     %3d File(s)     %6ld bytes free\n", files, blocks);
  769. X    close(fd);
  770. X    exit(0);
  771. X}
  772. X
  773. X/*
  774. X * Get the amount of free space on the diskette
  775. X */
  776. X
  777. Xstatic long
  778. Xgetfree()
  779. X{
  780. X    register unsigned int i;
  781. X    long total;
  782. X    extern unsigned int num_clus;
  783. X    unsigned int fat_decode();
  784. X
  785. X    total = 0L;
  786. X    for (i = 2; i < num_clus + 2; i++) {
  787. X                    /* if fat_decode returns zero */
  788. X        if (!fat_decode(i))
  789. X            total += clus_size;
  790. X    }
  791. X    return(total);
  792. X}
  793. X
  794. X/*
  795. X * Convert an MSDOS directory date stamp to ASCII
  796. X */
  797. X
  798. Xstatic char *
  799. Xconv_date(date_high, date_low)
  800. Xunsigned date_high, date_low;
  801. X{
  802. X/*
  803. X *        hi byte     |    low byte
  804. X *    |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
  805. X *      | | | | | | | | | | | | | | | | |
  806. X *      \   7 bits    /\4 bits/\ 5 bits /
  807. X *         year +80      month     day
  808. X */
  809. X    static char ans[9];
  810. X    unsigned char year, month_hi, month_low, day;
  811. X
  812. X    year = (date_high >> 1) + 80;
  813. X    month_hi = (date_high & 0x1) << 3;
  814. X    month_low = date_low >> 5;
  815. X    day = date_low & 0x1f;
  816. X    sprintf(ans, "%2d-%02d-%02d", month_hi + month_low, day, year);
  817. X    return(ans);
  818. X}
  819. X
  820. X/*
  821. X * Convert an MSDOS directory time stamp to ASCII.
  822. X */
  823. X
  824. Xstatic char *
  825. Xconv_time(time_high, time_low)
  826. Xunsigned time_high, time_low;
  827. X{
  828. X/*
  829. X *        hi byte     |    low byte
  830. X *    |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
  831. X *      | | | | | | | | | | | | | | | | |
  832. X *      \  5 bits /\  6 bits  /\ 5 bits /
  833. X *         hour      minutes     sec*2
  834. X */
  835. X    static char ans[7];
  836. X    char am_pm;
  837. X    unsigned char hour, min_hi, min_low;
  838. X
  839. X    hour = time_high >> 3;
  840. X    am_pm = (hour >= 12) ? 'p' : 'a';
  841. X    if (hour > 12)
  842. X        hour = hour - 12;
  843. X    if (hour == 0)
  844. X        hour = 12;
  845. X    min_hi = (time_high & 0x7) << 3;
  846. X    min_low = time_low >> 5;
  847. X    sprintf(ans, "%2d:%02d%c", hour, min_hi + min_low, am_pm);
  848. X    return(ans);
  849. X}
  850. X
  851. X/*
  852. X * stubs for read-only programs
  853. X */
  854. X
  855. Xvoid
  856. Xdisk_flush()
  857. X{
  858. X    extern int disk_dirty;
  859. X
  860. X    disk_dirty = 0;
  861. X    return;
  862. X}
  863. X
  864. Xvoid
  865. Xdir_flush()
  866. X{
  867. X    extern int dir_dirty;
  868. X
  869. X    dir_dirty = 0;
  870. X    return;
  871. X}
  872. END_OF_FILE
  873. if test 7059 -ne `wc -c <'mtools/mdir.c'`; then
  874.     echo shar: \"'mtools/mdir.c'\" unpacked with wrong size!
  875. fi
  876. # end of 'mtools/mdir.c'
  877. fi
  878. if test -f 'mtools/mread.c' -a "${1}" != "-c" ; then 
  879.   echo shar: Will not clobber existing file \"'mtools/mread.c'\"
  880. else
  881. echo shar: Extracting \"'mtools/mread.c'\" \(7810 characters\)
  882. sed "s/^X//" >'mtools/mread.c' <<'END_OF_FILE'
  883. X/*
  884. X * Read (copy) an MSDOS file to Unix
  885. X *
  886. X * Emmet P. Gray            US Army, HQ III Corps & Fort Hood
  887. X * ...!uunet!uiucuxc!fthood!egray    Attn: AFZF-DE-ENV
  888. X * fthood!egray@uxc.cso.uiuc.edu    Directorate of Engineering & Housing
  889. X *                     Environmental Management Office
  890. X *                     Fort Hood, TX 76544-5057
  891. X */
  892. X
  893. X#define LOWERCASE
  894. X
  895. X#include <stdio.h>
  896. X#include <ctype.h>
  897. X#include <sys/types.h>
  898. X#include <sys/stat.h>
  899. X#ifdef BSD
  900. X#include <sys/time.h>
  901. X#else /* BSD */
  902. X#include <time.h>
  903. X#endif /* BSD */
  904. X#include "msdos.h"
  905. X#include "patchlevel.h"
  906. X
  907. Xint fd = -1;                /* the file descriptor for the device */
  908. Xint dir_start;                /* starting sector for directory */
  909. Xint dir_len;                /* length of directory (in sectors) */
  910. Xint dir_entries;            /* number of directory entries */
  911. Xint clus_size;                /* cluster size (in sectors) */
  912. Xchar *mcwd;                /* the Current Working Directory */
  913. Xint fat_error;                /* FAT error detected? */
  914. X
  915. Xstatic void set_mtime();
  916. Xstatic FILE *open_file();
  917. Xstatic long conv_stamp();
  918. X
  919. Xmain(argc, argv)
  920. Xint argc;
  921. Xchar *argv[];
  922. X{
  923. X    FILE *fp;
  924. X    extern int optind;
  925. X    extern char *optarg;
  926. X    int i, ismatch, entry, single, c, oops, preserve, nowarn, textmode;
  927. X    unsigned int fat;
  928. X    long size, mtime;
  929. X    char *filename, *newfile, *get_name(), *unix_name(), *pathname;
  930. X    char *get_path(), *target, tmp[MAX_PATH], *strcat(), *strcpy(), drive;
  931. X    char get_drive(), last_drive, *fix_mcwd(), *s;
  932. X    void exit();
  933. X    struct directory *dir, *dir_read();
  934. X    struct stat stbuf;
  935. X
  936. X                    /* get command line options */
  937. X    oops = 0;
  938. X    preserve = 0;
  939. X    nowarn = 0;
  940. X    textmode = 0;
  941. X    while ((c = getopt(argc, argv, "tnmv")) != EOF) {
  942. X        switch (c) {
  943. X            case 't':
  944. X                textmode = 1;
  945. X                break;
  946. X            case 'n':
  947. X                nowarn = 1;
  948. X                break;
  949. X            case 'm':
  950. X                preserve = 1;
  951. X                break;
  952. X            case 'v':    /* dummy option for mcopy */
  953. X                break;
  954. X            default:
  955. X                oops = 1;
  956. X                break;
  957. X        }
  958. X    }
  959. X
  960. X    if (oops || (argc - optind) < 2) {
  961. X        fprintf(stderr, "Mtools version %s, dated %s\n", VERSION, DATE);
  962. X        fprintf(stderr, "Usage: %s [-tnm] msdosfile unixfile\n", argv[0]);
  963. X        fprintf(stderr, "       %s [-tnm] msdosfile [msdosfiles...] unixdirectory\n", argv[0]);
  964. X        exit(1);
  965. X    }
  966. X    last_drive = 'x';
  967. X    mcwd = fix_mcwd();
  968. X                    /* only 1 file to copy... */
  969. X    single = 1;
  970. X    target = argv[argc - 1];
  971. X                    /* ...unless last arg is a directory */
  972. X    if (!stat(target, &stbuf)) {
  973. X        if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
  974. X            single = 0;
  975. X    }
  976. X                    /* too many arguments */
  977. X    if (single && (argc - optind) != 2) {
  978. X        fprintf(stderr, "%s: Too many arguments or destination directory omitted\n", argv[0]);
  979. X        exit(1);
  980. X    }
  981. X
  982. X    for (i = optind; i < argc - 1; i++) {
  983. X        drive = get_drive(argv[i]);
  984. X        if (drive != last_drive) {
  985. X            if (init(drive, 0)) {
  986. X                fprintf(stderr, "%s: Cannot initialize '%c:'\n", argv[0], drive);
  987. X                continue;
  988. X            }
  989. X            last_drive = drive;
  990. X        }
  991. X        filename = get_name(argv[i]);
  992. X        pathname = get_path(argv[i]);
  993. X        if (subdir(drive, pathname))
  994. X            continue;
  995. X
  996. X        ismatch = 0;
  997. X        for (entry = 0; entry < dir_entries; entry++) {
  998. X            dir = dir_read(entry);
  999. X                    /* if empty */
  1000. X            if (dir->name[0] == 0x0)
  1001. X                break;
  1002. X                    /* if erased */
  1003. X            if (dir->name[0] == 0xe5)
  1004. X                continue;
  1005. X                    /* if dir or volume label */
  1006. X            if ((dir->attr & 0x10) || (dir->attr & 0x08))
  1007. X                continue;
  1008. X
  1009. X            newfile = unix_name(dir->name, dir->ext);
  1010. X
  1011. X                    /* if single file */
  1012. X            if (single) {
  1013. X                if (!strcmp(newfile, filename)) {
  1014. X                    fat = dir->start[1] * 0x100 + dir->start[0];
  1015. X                    size = dir->size[3] * 0x1000000L + dir->size[2] * 0x10000L + dir->size[1] * 0x100 + dir->size[0];
  1016. X                    if (preserve)
  1017. X                        mtime = conv_stamp(dir->time, dir->date);
  1018. X                    else
  1019. X                        mtime = 0L;
  1020. X                    if ((fp = open_file(target, nowarn))) {
  1021. X                        if (file_read(fp, fat, textmode, 0, size)) {
  1022. X                            fclose(fp);
  1023. X                            break;
  1024. X                        }
  1025. X                        fclose(fp);
  1026. X                        set_mtime(target, mtime);
  1027. X                    }
  1028. X                    ismatch = 1;
  1029. X                    break;
  1030. X                }
  1031. X            }
  1032. X                    /* if multiple files */
  1033. X            else {
  1034. X                if (match(newfile, filename)) {
  1035. X                    fat = dir->start[1] * 0x100 + dir->start[0];
  1036. X                    size = dir->size[3] * 0x1000000L + dir->size[2] * 0x10000L + dir->size[1] * 0x100 + dir->size[0];
  1037. X                    if (preserve)
  1038. X                        mtime = conv_stamp(dir->time, dir->date);
  1039. X                    else
  1040. X                        mtime = 0L;
  1041. X                    printf("Copying %s\n", newfile);
  1042. X#ifdef LOWERCASE
  1043. X                    s = newfile;
  1044. X                    while (*s) {
  1045. X                        if (isupper(*s))
  1046. X                            *s = tolower(*s);
  1047. X                        s++;
  1048. X                    }
  1049. X#endif /* LOWERCASE */
  1050. X                    strcpy(tmp, target);
  1051. X                    strcat(tmp, "/");
  1052. X                    strcat(tmp, newfile);
  1053. X                    if ((fp = open_file(tmp, nowarn))) {
  1054. X                        if (file_read(fp, fat, textmode, 0, size)) {
  1055. X                            fclose(fp);
  1056. X                            break;
  1057. X                        }
  1058. X                        fclose(fp);
  1059. X                        set_mtime(tmp, mtime);
  1060. X                    }
  1061. X                    ismatch = 1;
  1062. X                }
  1063. X            }
  1064. X        }
  1065. X        if (fat_error)
  1066. X            break;
  1067. X
  1068. X        if (!ismatch)
  1069. X            fprintf(stderr, "%s: File \"%s\" not found\n", argv[0], filename);
  1070. X    }
  1071. X    close(fd);
  1072. X    exit(0);
  1073. X}
  1074. X
  1075. X/*
  1076. X * Open the named Unix file for write.
  1077. X */
  1078. X
  1079. Xstatic FILE *
  1080. Xopen_file(target, nowarn)
  1081. Xchar *target;
  1082. Xint nowarn;
  1083. X{
  1084. X    static FILE *fp;
  1085. X    char ans[10];
  1086. X    struct stat stbuf;
  1087. X
  1088. X    if (!nowarn) {
  1089. X        if (!access(target, 0)) {
  1090. X            /* CONSTCOND */
  1091. X            while (1) {
  1092. X                printf("File \"%s\" exists, overwrite (y/n) ? ", target);
  1093. X                gets(ans);
  1094. X                if (ans[0] == 'n' || ans[0] == 'N')
  1095. X                    return(NULL);
  1096. X                if (ans[0] == 'y' || ans[0] == 'Y')
  1097. X                    break;
  1098. X            }
  1099. X                    /* sanity checking */
  1100. X            if (!stat(target, &stbuf)) {
  1101. X                if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
  1102. X                    fprintf(stderr, "\"%s\" is not a regular file\n", target);
  1103. X                    return(NULL);
  1104. X                }
  1105. X            }
  1106. X        }
  1107. X    }
  1108. X
  1109. X    if (!(fp = fopen(target, "w"))) {
  1110. X        fprintf(stderr, "Can't open \"%s\" for write\n", target);
  1111. X        return(NULL);
  1112. X    }
  1113. X    return(fp);
  1114. X}
  1115. X
  1116. X/*
  1117. X * Convert an MSDOS time & date stamp to the Unix time() format
  1118. X */
  1119. X
  1120. Xstatic long
  1121. Xconv_stamp(time_field, date_field)
  1122. Xunsigned char *time_field, *date_field;
  1123. X{
  1124. X#ifdef BSD
  1125. X    struct timeval tv;
  1126. X    struct timezone tz;
  1127. X#else /* BSD */
  1128. X    extern long timezone;
  1129. X    void tzset();
  1130. X#endif /* BSD */
  1131. X    struct tm *tmbuf, *localtime();
  1132. X    int year, mon, mday, hour, min, sec, old_leaps;
  1133. X    long answer, sec_year, sec_mon, sec_mday, sec_hour, sec_min, sec_leap;
  1134. X    long tzone, dst;
  1135. X    static int month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304,
  1136. X    334};
  1137. X                    /* dissect the parts */
  1138. X    year = (date_field[1] >> 1) + 1980;
  1139. X    mon = (((date_field[1] & 0x1) << 3) + (date_field[0] >> 5));
  1140. X    mday = date_field[0] & 0x1f;
  1141. X    hour = time_field[1] >> 3;
  1142. X    min = (((time_field[1] & 0x7) << 3) + (time_field[0] >> 5));
  1143. X    sec = (time_field[0] & 0x1f) * 2;
  1144. X                    /* how many previous leap years */
  1145. X    old_leaps = (year - 1972) / 4L;
  1146. X    sec_leap = old_leaps * 24L * 60L * 60L;
  1147. X                    /* back off 1 day if before 29 Feb */
  1148. X    if (!(year % 4) && mon < 3)
  1149. X        sec_leap -= 24L * 60L * 60L;
  1150. X    sec_year = (year - 1970) * 365L * 24L * 60L * 60L;
  1151. X    sec_mon = month[mon - 1] * 24L * 60L * 60L;
  1152. X    sec_mday = mday * 24L * 60L * 60L;
  1153. X    sec_hour = hour * 60L * 60L;
  1154. X    sec_min = min * 60L;
  1155. X                    /* correct for Time Zone */
  1156. X#ifdef BSD
  1157. X    gettimeofday(&tv, &tz);
  1158. X    tzone = tz.tz_minuteswest * 60L;
  1159. X#else /* BSD */
  1160. X    tzset();
  1161. X    tzone = timezone;
  1162. X#endif /* BSD */
  1163. X
  1164. X    answer = sec_leap + sec_year + sec_mon + sec_mday + sec_hour + sec_min + sec + tzone;
  1165. X                    /* correct for Daylight Saving Time */
  1166. X    tmbuf = localtime(&answer);
  1167. X    dst = (tmbuf->tm_isdst) ? (-60L * 60L) : 0L;
  1168. X    answer += dst;
  1169. X    
  1170. X    return(answer);
  1171. X}
  1172. X
  1173. X/*
  1174. X * Preserve the file modification times after the fclose()
  1175. X */
  1176. X
  1177. Xstatic void
  1178. Xset_mtime(target, mtime)
  1179. Xchar *target;
  1180. Xlong mtime;
  1181. X{
  1182. X#ifdef BSD
  1183. X    struct timeval tv[2];
  1184. X
  1185. X    if (mtime != 0L) {
  1186. X        tv[0].tv_sec = mtime;
  1187. X        tv[0].tv_usec = 0;
  1188. X        tv[1].tv_sec = mtime;
  1189. X        tv[1].tv_usec = 0;
  1190. X        utimes(target, tv);
  1191. X    }
  1192. X#else /* BSD */
  1193. X    struct {
  1194. X        time_t actime;
  1195. X        time_t modtime;
  1196. X    } utbuf;
  1197. X
  1198. X    if (mtime != 0L) {
  1199. X        utbuf.actime = mtime;
  1200. X        utbuf.modtime = mtime;
  1201. X        utime(target, &utbuf);
  1202. X    }
  1203. X#endif /* BSD */
  1204. X    return;
  1205. X}
  1206. X
  1207. X/*
  1208. X * stubs for read-only programs
  1209. X */
  1210. X
  1211. Xvoid
  1212. Xdisk_flush()
  1213. X{
  1214. X    extern int disk_dirty;
  1215. X
  1216. X    disk_dirty = 0;
  1217. X    return;
  1218. X}
  1219. X
  1220. Xvoid
  1221. Xdir_flush()
  1222. X{
  1223. X    extern int dir_dirty;
  1224. X
  1225. X    dir_dirty = 0;
  1226. X    return;
  1227. X}
  1228. END_OF_FILE
  1229. if test 7810 -ne `wc -c <'mtools/mread.c'`; then
  1230.     echo shar: \"'mtools/mread.c'\" unpacked with wrong size!
  1231. fi
  1232. # end of 'mtools/mread.c'
  1233. fi
  1234. if test -f 'mtools/mwrite.c' -a "${1}" != "-c" ; then 
  1235.   echo shar: Will not clobber existing file \"'mtools/mwrite.c'\"
  1236. else
  1237. echo shar: Extracting \"'mtools/mwrite.c'\" \(7770 characters\)
  1238. sed "s/^X//" >'mtools/mwrite.c' <<'END_OF_FILE'
  1239. X/*
  1240. X * Write (copy) a Unix file to MSDOS
  1241. X *
  1242. X * Emmet P. Gray            US Army, HQ III Corps & Fort Hood
  1243. X * ...!uunet!uiucuxc!fthood!egray    Attn: AFZF-DE-ENV
  1244. X * fthood!egray@uxc.cso.uiuc.edu    Directorate of Engineering & Housing
  1245. X *                     Environmental Management Office
  1246. X *                     Fort Hood, TX 76544-5057
  1247. X */
  1248. X
  1249. X#include <stdio.h>
  1250. X#include <signal.h>
  1251. X#include <sys/types.h>
  1252. X#include <sys/stat.h>
  1253. X#include "msdos.h"
  1254. X#include "patchlevel.h"
  1255. X
  1256. Xint fd = -1;                /* the file descriptor for the device */
  1257. Xint dir_start;                /* starting sector for directory */
  1258. Xint dir_len;                /* length of directory (in sectors) */
  1259. Xint dir_entries;            /* number of directory entries */
  1260. Xint clus_size;                /* cluster size (in sectors) */
  1261. Xchar *mcwd;                /* the Current Working Directory */
  1262. Xint fat_error;                /* FAT error detected? */
  1263. X
  1264. Xint full = 0;
  1265. Xint textmode = 0;
  1266. Xint nowarn = 0;
  1267. Xstatic int got_signal();
  1268. Xstatic struct directory *writeit();
  1269. Xstatic long free_space();
  1270. X
  1271. Xmain(argc, argv)
  1272. Xint argc;
  1273. Xchar *argv[];
  1274. X{
  1275. X    extern int optind;
  1276. X    extern char *optarg;
  1277. X    int i, entry, ismatch, nogo, slot, single;
  1278. X    int c, oops, verbose, first, mod_time;
  1279. X    unsigned int dot, start;
  1280. X    char *filename, *newfile, *get_name(), get_drive();
  1281. X    char *unix_name(), ans[10], *pathname, *get_path(), *fix_mcwd();
  1282. X    char tmp[MAX_PATH], target[13], *strcat(), *strcpy(), drive;
  1283. X    unsigned char *fixed, *dos_name();
  1284. X    void exit(), fat_write(), dir_write(), disk_flush(), dir_flush();
  1285. X    struct directory *dir, *dir_read();
  1286. X                    /* catch signals */
  1287. X    signal(SIGINT, (SIG_TYPE(*) ()) got_signal);
  1288. X    signal(SIGTERM, (SIG_TYPE(*) ()) got_signal);
  1289. X    signal(SIGQUIT, (SIG_TYPE(*) ()) got_signal);
  1290. X                    /* get command line options */
  1291. X    oops = 0;
  1292. X    verbose = 0;
  1293. X    mod_time = 0;
  1294. X    while ((c = getopt(argc, argv, "tnvm")) != EOF) {
  1295. X        switch (c) {
  1296. X            case 't':
  1297. X                textmode = 1;
  1298. X                break;
  1299. X            case 'n':
  1300. X                nowarn = 1;
  1301. X                break;
  1302. X            case 'v':
  1303. X                verbose = 1;
  1304. X                break;
  1305. X            case 'm':
  1306. X                mod_time = 1;
  1307. X                break;
  1308. X            default:
  1309. X                oops = 1;
  1310. X                break;
  1311. X        }
  1312. X    }
  1313. X
  1314. X    if (oops || (argc - optind) < 2) {
  1315. X        fprintf(stderr, "Mtools version %s, dated %s\n", VERSION, DATE);
  1316. X        fprintf(stderr, "Usage: %s [-tnvm] unixfile msdosfile\n", argv[0]);
  1317. X        fprintf(stderr, "       %s [-tnvm] unixfile [unixfiles...] msdosdirectory\n", argv[0]);
  1318. X        exit(1);
  1319. X    }
  1320. X    mcwd = fix_mcwd();
  1321. X
  1322. X    drive = get_drive(argv[argc - 1]);
  1323. X    if (init(drive, 2)) {
  1324. X        fprintf(stderr, "%s: Cannot initialize '%c:'\n", argv[0], drive);
  1325. X        exit(1);
  1326. X    }
  1327. X
  1328. X    filename = get_name(argv[argc - 1]);
  1329. X    pathname = get_path(argv[argc - 1]);
  1330. X
  1331. X    /*
  1332. X     * Move to "first guess" directory so we can see if filename is also
  1333. X     * a directory.
  1334. X     */
  1335. X    if (subdir(drive, pathname))
  1336. X        exit(1);
  1337. X                    /* test if last argv is a dir */
  1338. X    if (is_dir(filename) || *filename == '\0') {
  1339. X        if (*filename) {
  1340. X            strcpy(tmp, pathname);
  1341. X            if (tmp[strlen(tmp) -1] != '/')
  1342. X                strcat(tmp, "/");
  1343. X            strcat(tmp, filename);
  1344. X
  1345. X            if (subdir(drive, tmp))
  1346. X                exit(1);
  1347. X        }
  1348. X        single = 0;
  1349. X    }
  1350. X    else {
  1351. X        single = 1;
  1352. X                    /* too many arguments */
  1353. X        if ((argc - optind) != 2) {
  1354. X            fprintf(stderr, "%s: Too many arguments or destination directory omitted\n", argv[0]);
  1355. X            exit(1);
  1356. X        }
  1357. X    }
  1358. X
  1359. X    for (i = optind; i < argc - 1; i++) {
  1360. X        if (single)
  1361. X            fixed = dos_name(argv[argc - 1], verbose);
  1362. X        else
  1363. X            fixed = dos_name(argv[i], verbose);
  1364. X
  1365. X        strcpy(target, unix_name(fixed, fixed + 8));
  1366. X                    /* see if exists and get slot */
  1367. X        ismatch = 0;
  1368. X        slot = -1;
  1369. X        dot = 0;
  1370. X        nogo = 0;
  1371. X        first = 1;
  1372. X        for (entry = 0; entry < dir_entries; entry++) {
  1373. X            dir = dir_read(entry);
  1374. X                    /* save the '.' entry info */
  1375. X            if (first) {
  1376. X                first = 0;
  1377. X                if ((dir->attr & 0x10) && dir->name[0] == '.') {
  1378. X                    dot = dir->start[1] * 0x100 + dir->start[0];
  1379. X                    continue;
  1380. X                }
  1381. X            }
  1382. X                    /* is empty */
  1383. X            if (dir->name[0] == 0x0) {
  1384. X                if (slot < 0)
  1385. X                    slot = entry;
  1386. X                break;
  1387. X            }
  1388. X                    /* is erased */
  1389. X            if (dir->name[0] == 0xe5) {
  1390. X                if (slot < 0)
  1391. X                    slot = entry;
  1392. X                continue;
  1393. X            }
  1394. X                    /* is dir or volume label */
  1395. X            if ((dir->attr & 0x10) || (dir->attr & 0x08))
  1396. X                continue;
  1397. X
  1398. X            newfile = unix_name(dir->name, dir->ext);
  1399. X
  1400. X                    /* if file exists, delete it first */
  1401. X            if (!strcmp(target, newfile)) {
  1402. X                ismatch = 1;
  1403. X                start = dir->start[1] * 0x100 + dir->start[0];
  1404. X                if (nowarn) {
  1405. X                    if (fat_free(start))
  1406. X                        break;
  1407. X                    dir->name[0] = 0xe5;
  1408. X                    dir_write(entry, dir);
  1409. X                    if (slot < 0)
  1410. X                        slot = entry;
  1411. X                }
  1412. X                else {
  1413. X                    /* CONSTCOND */
  1414. X                    while (1) {
  1415. X                        printf("File \"%s\" exists, overwrite (y/n) ? ", target);
  1416. X                        gets(ans);
  1417. X                        if (ans[0] == 'n' || ans[0] == 'N') {
  1418. X                            nogo = 1;
  1419. X                            break;
  1420. X                        }
  1421. X                        if (ans[0] == 'y' || ans[0] == 'Y') {
  1422. X                            if (fat_free(start))
  1423. X                                break;
  1424. X                            dir->name[0] = 0xe5;
  1425. X                            dir_write(entry, dir);
  1426. X                            if (slot < 0)
  1427. X                                slot = entry;
  1428. X                            break;
  1429. X                        }
  1430. X                    }
  1431. X                }
  1432. X            }
  1433. X            if (ismatch)
  1434. X                break;
  1435. X        }
  1436. X        if (fat_error)
  1437. X            break;
  1438. X
  1439. X        if (nogo)        /* chickened out... */
  1440. X            continue;
  1441. X                    /* no '.' entry means root directory */
  1442. X        if (dot == 0 && slot < 0) {
  1443. X            fprintf(stderr, "%s: No directory slots\n", argv[0]);
  1444. X            break;
  1445. X        }
  1446. X                    /* make the directory grow */
  1447. X        if (dot && slot < 0) {
  1448. X            if (dir_grow(dot)) {
  1449. X                fprintf(stderr, "%s: Disk full\n", argv[0]);
  1450. X                break;
  1451. X            }
  1452. X                    /* first entry in 'new' directory */
  1453. X            slot = entry;
  1454. X        }
  1455. X                    /* write the file */
  1456. X        if (dir = writeit(fixed, argv[i], verbose, mod_time, single, target))
  1457. X            dir_write(slot, dir);
  1458. X
  1459. X        if (full) {
  1460. X            fprintf(stderr, "%s: Disk full\n", argv[0]);
  1461. X            break;
  1462. X        }
  1463. X        if (single)
  1464. X            break;
  1465. X    }
  1466. X                    /* write the FAT, flush the buffers */
  1467. X    fat_write();
  1468. X    dir_flush();
  1469. X    disk_flush();
  1470. X    close(fd);
  1471. X    exit(0);
  1472. X}
  1473. X
  1474. X/*
  1475. X * Open the named file for read, create the cluster chain, return the
  1476. X * directory structure or NULL on error.
  1477. X */
  1478. X
  1479. Xstatic struct directory *
  1480. Xwriteit(fixed, path, verbose, mod_time, single, target)
  1481. Xunsigned char *fixed;
  1482. Xchar *path;
  1483. Xint verbose, mod_time, single;
  1484. Xchar *target;
  1485. X{
  1486. X    FILE *fp;
  1487. X    unsigned int fat, next_fat();
  1488. X    long filesize, file_write(), size, time(), now;
  1489. X    struct directory *dir, *mk_entry();
  1490. X    struct stat stbuf;
  1491. X
  1492. X    if (stat(path, &stbuf) < 0) {
  1493. X        fprintf(stderr, "Can't stat \"%s\"\n", path);
  1494. X        return(NULL);
  1495. X    }
  1496. X
  1497. X    if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
  1498. X        if (verbose)
  1499. X            fprintf(stderr, "\"%s\" is a directory\n", path);
  1500. X        return(NULL);
  1501. X    }
  1502. X
  1503. X    if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
  1504. X        if (verbose)
  1505. X            fprintf(stderr, "\"%s\" is not a regular file\n", path);
  1506. X        return(NULL);
  1507. X    }
  1508. X
  1509. X    if (!(fp = fopen(path, "r"))) {
  1510. X        fprintf(stderr, "Can't open \"%s\" for read\n", path);
  1511. X        return(NULL);
  1512. X    }
  1513. X
  1514. X    if (!single)
  1515. X        printf("Copying %s\n", target);
  1516. X
  1517. X                    /* will it fit? */
  1518. X    filesize = stbuf.st_size;
  1519. X    if (filesize > free_space()) {
  1520. X        full = 1;
  1521. X        return(NULL);
  1522. X    }
  1523. X                    /* preserve mod time? */
  1524. X    if (mod_time)
  1525. X        now = stbuf.st_mtime;
  1526. X    else
  1527. X        time(&now);
  1528. X
  1529. X                    /* if a zero length file */
  1530. X    if (filesize == 0L) {
  1531. X        dir = mk_entry(fixed, 0x20, 0, 0L, now);
  1532. X        return(dir);
  1533. X    }
  1534. X
  1535. X    if ((fat = next_fat(0)) == 1) {
  1536. X        full = 1;
  1537. X        fclose(fp);
  1538. X        return(NULL);
  1539. X    }
  1540. X    if ((size = file_write(fp, fat, filesize, textmode)) < 0) {
  1541. X        fclose(fp);
  1542. X        return(NULL);
  1543. X    }
  1544. X    fclose(fp);
  1545. X
  1546. X    dir = mk_entry(fixed, 0x20, fat, size, now);
  1547. X    return(dir);
  1548. X}
  1549. X
  1550. X/*
  1551. X * Do a graceful exit if the program is interrupted.  This will reduce
  1552. X * (but not eliminate) the risk of generating a corrupted disk on
  1553. X * a user abort.
  1554. X */
  1555. X
  1556. Xstatic int
  1557. Xgot_signal()
  1558. X{
  1559. X    void exit(), disk_flush(), fat_write(), dir_flush();
  1560. X
  1561. X    if (fd < 0)
  1562. X        exit(1);
  1563. X    fat_write();
  1564. X    dir_flush();
  1565. X    disk_flush();
  1566. X    close(fd);
  1567. X    exit(1);
  1568. X}
  1569. X
  1570. X
  1571. X/*
  1572. X * Get the amount of remaining free space
  1573. X */
  1574. X
  1575. Xstatic long
  1576. Xfree_space()
  1577. X{
  1578. X    register unsigned int i;
  1579. X    long total;
  1580. X    extern unsigned int num_clus;
  1581. X    unsigned int fat_decode();
  1582. X
  1583. X    total = 0L;
  1584. X    for (i = 2; i < num_clus + 2; i++) {
  1585. X                    /* if fat_decode returns zero */
  1586. X        if (!fat_decode(i))
  1587. X            total += clus_size;
  1588. X    }
  1589. X    total *= MSECTOR_SIZE;
  1590. X    return(total);
  1591. X}
  1592. END_OF_FILE
  1593. if test 7770 -ne `wc -c <'mtools/mwrite.c'`; then
  1594.     echo shar: \"'mtools/mwrite.c'\" unpacked with wrong size!
  1595. fi
  1596. # end of 'mtools/mwrite.c'
  1597. fi
  1598. echo shar: End of archive 3 \(of 3\).
  1599. cp /dev/null ark3isdone
  1600. MISSING=""
  1601. for I in 1 2 3 ; do
  1602.     if test ! -f ark${I}isdone ; then
  1603.     MISSING="${MISSING} ${I}"
  1604.     fi
  1605. done
  1606. if test "${MISSING}" = "" ; then
  1607.     echo You have unpacked all 3 archives.
  1608.     rm -f ark[1-9]isdone
  1609. else
  1610.     echo You still need to unpack the following archives:
  1611.     echo "        " ${MISSING}
  1612. fi
  1613. ##  End of shell archive.
  1614. exit 0
  1615.