FATFS.C
上传用户:dcs7469208
上传日期:2010-01-02
资源大小:443k
文件大小:53k
源码类别:

操作系统开发

开发平台:

DOS

  1. /****************************************************************/
  2. /*                                                              */
  3. /*                          fatfs.c                             */
  4. /*                           DOS-C                              */
  5. /*                                                              */
  6. /*                 FAT File System I/O Functions                */
  7. /*                                                              */
  8. /*                      Copyright (c) 1995                      */
  9. /*                      Pasquale J. Villani                     */
  10. /*                      All Rights Reserved                     */
  11. /*                                                              */
  12. /* This file is part of DOS-C.                                  */
  13. /*                                                              */
  14. /* DOS-C is free software; you can redistribute it and/or       */
  15. /* modify it under the terms of the GNU General Public License  */
  16. /* as published by the Free Software Foundation; either version */
  17. /* 2, or (at your option) any later version.                    */
  18. /*                                                              */
  19. /* DOS-C is distributed in the hope that it will be useful, but */
  20. /* WITHOUT ANY WARRANTY; without even the implied warranty of   */
  21. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See    */
  22. /* the GNU General Public License for more details.             */
  23. /*                                                              */
  24. /* You should have received a copy of the GNU General Public    */
  25. /* License along with DOS-C; see the file COPYING.  If not,     */
  26. /* write to the Free Software Foundation, 675 Mass Ave,         */
  27. /* Cambridge, MA 02139, USA.                                    */
  28. /****************************************************************/
  29. #include "../../hdr/portab.h"
  30. #include "globals.h"
  31. #ifdef VERSION_STRINGS
  32. BYTE *RcsId = "$Header:   C:/dos-c/src/fs/fatfs.c_v   1.12   03 Feb 1998 11:28:04   patv  $";
  33. #endif
  34. /* $Log:   C:/dos-c/src/fs/fatfs.c_v  $
  35.  * 
  36.  *    Rev 1.12   03 Feb 1998 11:28:04   patv
  37.  * Fixed lseek bug.
  38.  * 
  39.  *    Rev 1.11   22 Jan 1998  5:38:08   patv
  40.  * Corrected remaining file name and extension copies that did not
  41.  * account for far file nodes due to allocated FILES= spec.
  42.  * 
  43.  *    Rev 1.10   22 Jan 1998  4:09:00   patv
  44.  * Fixed pointer problems affecting SDA
  45.  * 
  46.  *    Rev 1.9   04 Jan 1998 23:14:40   patv
  47.  * Changed Log for strip utility
  48.  * 
  49.  *    Rev 1.8   04 Jan 1998 17:24:14   patv
  50.  * Corrected subdirectory bug
  51.  * 
  52.  *    Rev 1.7   03 Jan 1998  8:36:04   patv
  53.  * Converted data area to SDA format
  54.  * 
  55.  *    Rev 1.6   22 Jan 1997 13:00:30   patv
  56.  * pre-0.92 bug fixes
  57.  * 
  58.  *    Rev 1.5   16 Jan 1997 12:46:24   patv
  59.  * pre-Release 0.92 feature additions
  60.  * 
  61.  *    Rev 1.4   29 May 1996 21:15:16   patv
  62.  * bug fixes for v0.91a
  63.  * 
  64.  *    Rev 1.3   19 Feb 1996  3:20:10   patv
  65.  * Added NLS, int2f and config.sys processing
  66.  * 
  67.  *    Rev 1.2   01 Sep 1995 17:48:40   patv
  68.  * First GPL release.
  69.  * 
  70.  *    Rev 1.1   30 Jul 1995 20:50:24   patv
  71.  * Eliminated version strings in ipl
  72.  * 
  73.  *    Rev 1.0   02 Jul 1995  8:04:46   patv
  74.  * Initial revision.
  75.  */
  76. /* $EndLog$ */
  77. /*                                                                      */
  78. /*      function prototypes                                             */
  79. /*                                                                      */
  80. struct f_node FAR *xlt_fd(COUNT);
  81. COUNT xlt_fnp(struct f_node FAR *);
  82. struct f_node FAR *split_path(BYTE FAR *, BYTE *, BYTE *, BYTE *);
  83. BOOL find_fname(struct f_node FAR *, BYTE *, BYTE *);
  84. date dos_getdate(VOID);
  85. time dos_gettime(VOID);
  86. BOOL find_free(struct f_node FAR *);
  87. UWORD find_fat_free(struct f_node FAR *);
  88. VOID wipe_out(struct f_node FAR *);
  89. BOOL last_link(struct f_node FAR *);
  90. BOOL extend(struct f_node FAR *);
  91. COUNT extend_dir(struct f_node FAR *);
  92. BOOL first_fat(struct f_node FAR *);
  93. COUNT map_cluster(struct f_node FAR *, COUNT);
  94. /************************************************************************/
  95. /*                                                                      */
  96. /*      Internal file handlers - open, create, read, write, close, etc. */
  97. /*                                                                      */
  98. /************************************************************************/
  99. /* Open a file given the path. Flags is 0 for read, 1 for write and 2   */
  100. /* for update.                                                          */
  101. /* Returns an integer file desriptor or a negative error code           */
  102. COUNT 
  103. dos_open (BYTE FAR *path, COUNT flag)
  104. {
  105. REG struct f_node FAR *fnp;
  106. COUNT i;
  107. BYTE FAR *fnamep;
  108. /* First test the flag to see if the user has passed a valid    */
  109. /* file mode...                                                 */
  110. if(flag < 0 || flag > 2)
  111. return DE_INVLDACC;
  112. /* first split the passed dir into comopnents (i.e. - path to   */
  113. /* new directory and name of new directory.                     */
  114. if((fnp = split_path(path, szDirName, szFileName, szFileExt)) == NULL)
  115. {
  116. dir_close(fnp);
  117. return DE_PATHNOTFND;
  118. }
  119. /* Look for the file. If we can't find it, just return a not    */
  120. /* found error.                                                 */
  121. if(!find_fname(fnp, szFileName, szFileExt))
  122. {
  123. dir_close(fnp);
  124. return DE_FILENOTFND;
  125. }
  126. /* Set the fnode to the desired mode                            */
  127. fnp -> f_mode = flag;
  128. /* Initialize the rest of the fnode.                            */
  129. fnp -> f_offset = 0l;
  130. fnp -> f_highwater = fnp -> f_dir.dir_size;
  131. fnp -> f_back = LONG_LAST_CLUSTER;
  132. fnp -> f_cluster = fnp -> f_dir.dir_start;
  133. fnp -> f_flags.f_dmod = FALSE;
  134. fnp -> f_flags.f_dnew = FALSE;
  135. fnp -> f_flags.f_ddir = FALSE;
  136. return xlt_fnp(fnp);
  137. }
  138. #ifndef IPL
  139. BOOL fcmp(s1, s2, n)
  140. BYTE FAR *s1, FAR *s2;
  141. COUNT n;
  142. {
  143. while(n--)
  144. if(*s1++ != *s2++)
  145. return FALSE;
  146. return TRUE;
  147. }
  148. BOOL fcmp_wild(s1, s2, n)
  149. BYTE FAR *s1, FAR *s2;
  150. COUNT n;
  151. {
  152. while(n--)
  153. {
  154. if(*s1 == '?')
  155. {
  156. ++s1, ++s2;
  157. continue;
  158. }
  159. if(*s1++ != *s2++)
  160. return FALSE;
  161. }
  162. return TRUE;
  163. }
  164. #endif
  165. COUNT 
  166. dos_close (COUNT fd)
  167. {
  168. struct f_node FAR *fnp;
  169. /* Translate the fd into a useful pointer                       */
  170. fnp = xlt_fd(fd);
  171. /* If the fd was invalid because it was out of range or the     */
  172. /* requested file was not open, tell the caller and exit        */
  173. /* note: an invalid fd is indicated by a 0 return               */
  174. if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
  175. return DE_INVLDHNDL;
  176. if(fnp -> f_mode != RDONLY)
  177. {
  178. fnp -> f_dir.dir_size = fnp -> f_highwater;
  179. fnp -> f_flags.f_dmod = TRUE;
  180. }
  181. fnp -> f_flags.f_ddir = TRUE;
  182. dir_close(fnp);
  183. return SUCCESS;
  184. }
  185. /*                                                                      */
  186. /* split a path into it's component directory and file name             */
  187. /*                                                                      */
  188. static struct f_node FAR *
  189. split_path (BYTE FAR *path, BYTE *dname, BYTE *fname, BYTE *fext)
  190. {
  191. REG struct f_node FAR *fnp;
  192. COUNT nDrive;
  193. struct dpb *dpbp;
  194. /* Start off by parsing out the components. */
  195. ParseDosName(adjust_far(path), &nDrive, &dname[2], fname, fext);
  196. if(nDrive < 0)
  197. nDrive = default_drive;
  198. dname[0] = 'A' + nDrive;
  199. dname[1] = ':';
  200. /* Add trailing spaces to the file name and extension */
  201. SpacePad(fname, FNAME_SIZE);
  202. SpacePad(fext, FEXT_SIZE);
  203. /* If the path is null, we to default to the current            */
  204. /* directory...                                                 */
  205. if(!dname[2])
  206. {
  207. dpbp = &blk_devices[nDrive];
  208. fsncopy((BYTE FAR *)dpbp -> dpb_path,
  209.         (BYTE FAR *)&dname[2],
  210.         PARSE_MAX);
  211. }
  212. /* Translate the path into a useful pointer                     */
  213. fnp = dir_open((BYTE FAR *)dname);
  214. /* If the fd was invalid because it was out of range or the     */
  215. /* requested file was not open, tell the caller and exit...     */
  216. /* note: an invalid fd is indicated by a 0 return               */
  217. if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
  218. {
  219. dir_close(fnp);
  220. return (struct f_node FAR *)0;
  221. }
  222. /* Convert the name into an absolute name for comparison...     */
  223. upMem((BYTE FAR *)dname, strlen(dname));
  224. upMem((BYTE FAR *)fname, FNAME_SIZE);
  225. upMem((BYTE FAR *)fext, FEXT_SIZE);
  226. return fnp;
  227. }
  228. static BOOL 
  229. find_fname (struct f_node FAR *fnp, BYTE *fname, BYTE *fext)
  230. {
  231. BOOL found = FALSE;
  232. while(dir_read(fnp) == DIRENT_SIZE)
  233. {
  234. if(fnp -> f_dir.dir_name[0] != '')
  235. {
  236. if(fnp -> f_dir.dir_name[0] == DELETED)
  237. continue;
  238. if(fcmp((BYTE FAR *)fname, (BYTE FAR *)fnp -> f_dir.dir_name, FNAME_SIZE)
  239. && fcmp((BYTE FAR *)fext, (BYTE FAR *)fnp -> f_dir.dir_ext, FEXT_SIZE))
  240. {
  241. found = TRUE;
  242. break;
  243. }
  244. }
  245. }
  246. return found;
  247. }
  248. #ifndef IPL
  249. COUNT 
  250. dos_creat (BYTE FAR *path, COUNT attrib)
  251. {
  252. REG struct f_node FAR *fnp;
  253. /* first split the passed dir into comopnents (i.e. -   */
  254. /* path to new directory and name of new directory      */
  255. if((fnp = split_path(path, szDirName, szFileName, szFileExt)) == NULL)
  256. {
  257. dir_close(fnp);
  258. return DE_PATHNOTFND;
  259. }
  260. /* Check that we don't have a duplicate name, so if we  */
  261. /* find one, truncate it.                               */
  262. if(find_fname(fnp, szFileName, szFileExt))
  263. {
  264. /* The only permissable attribute is archive,   */
  265. /* check for any other bit set. If it is, give  */
  266. /* an access error.                             */
  267. if((fnp -> f_dir.dir_attrib & (D_RDONLY | D_DIR | D_VOLID))
  268.    || (fnp -> f_dir.dir_attrib & ~D_ARCHIVE & ~attrib))
  269. {
  270. dir_close(fnp);
  271. return DE_ACCESS;
  272. }
  273. /* Release the existing files FAT and set the   */
  274. /* length to zero, effectively truncating the   */
  275. /* file to zero.                                */
  276. wipe_out(fnp);
  277. }
  278. else
  279. {
  280. BOOL is_free;
  281. REG COUNT idx;
  282. struct buffer FAR *bp;
  283. BYTE FAR *p;
  284. /* Reset the directory by a close followed by   */
  285. /* an open                                      */
  286. fnp -> f_flags.f_dmod = FALSE;
  287. dir_close(fnp);
  288. fnp = dir_open((BYTE FAR *)szDirName);
  289. /* Get a free f_node pointer so that we can use */
  290. /* it in building the new file.                 */
  291. /* Note that if we're in the root and we don't  */
  292. /* find an empty slot, we need to abort.        */
  293. if(!(is_free = find_free(fnp)) && (fnp -> f_flags.f_droot))
  294. {
  295. fnp -> f_flags.f_dmod = FALSE;
  296. dir_close(fnp);
  297. return DE_TOOMANY;
  298. }
  299. /* Otherwise just expand the directory          */
  300. else if(!is_free && !(fnp -> f_flags.f_droot))
  301. {
  302. COUNT ret;
  303. if((ret = extend_dir(fnp)) != SUCCESS)
  304. return ret;
  305. }
  306. /* put the fnode's name into the directory.             */
  307. fbcopy((BYTE FAR *)szFileName,
  308.  (BYTE FAR *)fnp -> f_dir.dir_name, FNAME_SIZE);
  309. fbcopy((BYTE FAR *)szFileExt,
  310.  (BYTE FAR *)fnp -> f_dir.dir_ext, FEXT_SIZE);
  311. }
  312. /* Set the fnode to the desired mode                    */
  313. /* Updating the directory entry first.                  */
  314. fnp -> f_mode = RDWR;
  315. fnp -> f_dir.dir_size = 0l;
  316. fnp -> f_dir.dir_start = FREE;
  317. fnp -> f_dir.dir_attrib = attrib | D_ARCHIVE;
  318. fnp -> f_dir.dir_time = dos_gettime();
  319. fnp -> f_dir.dir_date = dos_getdate();
  320. fnp -> f_flags.f_dmod = TRUE;
  321. fnp -> f_flags.f_dnew = FALSE;
  322. fnp -> f_flags.f_ddir = TRUE;
  323. if(dir_write(fnp) != DIRENT_SIZE)
  324. {
  325. release_f_node(fnp);
  326. return DE_ACCESS;
  327. }
  328. /* Now change to file                                   */
  329. fnp -> f_offset = 0l;
  330. fnp -> f_highwater = 0l;
  331. fnp -> f_back = LONG_LAST_CLUSTER;
  332. fnp -> f_cluster = fnp -> f_dir.dir_start = FREE;
  333. fnp -> f_flags.f_dmod = TRUE;
  334. fnp -> f_flags.f_dnew = FALSE;
  335. fnp -> f_flags.f_ddir = FALSE;
  336. return xlt_fnp(fnp);
  337. }
  338. COUNT 
  339. dos_delete (BYTE FAR *path)
  340. {
  341. REG struct f_node FAR *fnp;
  342. /* first split the passed dir into components (i.e. - */
  343. /* path to new directory and name of new directory */
  344. if((fnp = split_path(path, szDirName, szFileName, szFileExt)) == NULL)
  345. {
  346. dir_close(fnp);
  347. return DE_PATHNOTFND;
  348. }
  349. /* Check that we don't have a duplicate name, so if we  */
  350. /* find one, it's an error.                             */
  351. if(find_fname(fnp, szFileName, szFileExt))
  352. {
  353. /* The only permissable attribute is archive,   */
  354. /* check for any other bit set. If it is, give  */
  355. /* an access error.                             */
  356. if(fnp -> f_dir.dir_attrib & ~D_ARCHIVE)
  357. {
  358. dir_close(fnp);
  359. return DE_ACCESS;
  360. }
  361. /* Ok, so we can delete. Start out by           */
  362. /* clobbering all FAT entries for this file     */
  363. /* (or, in English, truncate the FAT).          */
  364. wipe_out(fnp);
  365. fnp -> f_dir.dir_size = 0l;
  366. *(fnp -> f_dir.dir_name) = DELETED;
  367. /* The directory has been modified, so set the  */
  368. /* bit before closing it, allowing it to be     */
  369. /* updated                                      */
  370. fnp -> f_flags.f_dmod = TRUE;
  371. dir_close(fnp);
  372. /* SUCCESSful completion, return it             */
  373. return SUCCESS;
  374. }
  375. else
  376. {
  377. /* No such file, return the error               */ 
  378. dir_close(fnp);
  379. return DE_FILENOTFND;
  380. }
  381. }
  382. COUNT 
  383. dos_rmdir (BYTE FAR *path)
  384. {
  385. REG struct f_node FAR *fnp;
  386. REG struct f_node FAR *fnp1;
  387. BOOL found;
  388. /* first split the passed dir into comopnents (i.e. -   */
  389. /* path to new directory and name of new directory      */
  390. if((fnp = split_path(path, szDirName, szFileName, szFileExt)) == NULL)
  391. {
  392. dir_close(fnp);
  393. return DE_PATHNOTFND;
  394. }
  395. /* Check that we're not trying to remove the root!      */
  396. if((path[0] == '\') && (path[1] == NULL))
  397. {
  398. dir_close(fnp);
  399. return DE_ACCESS;
  400. }
  401. /* Check that we don't have a duplicate name, so if we  */
  402. /* find one, it's an error.                             */
  403. if(find_fname(fnp, szFileName, szFileExt))
  404. {
  405. /* The only permissable attribute is directory, */
  406. /* check for any other bit set. If it is, give  */
  407. /* an access error.                             */
  408. if(fnp -> f_dir.dir_attrib & ~D_DIR)
  409. {
  410. dir_close(fnp);
  411. return DE_ACCESS;
  412. }
  413. /* Check that the directory is empty. Only the  */
  414. /* "." and ".." are permissable.                */
  415. fnp -> f_flags.f_dmod = FALSE;
  416. fnp1 = dir_open((BYTE FAR *)path);
  417. dir_read(fnp1);
  418. if(fnp1 -> f_dir.dir_name[0] != '.')
  419. {
  420. dir_close(fnp);
  421. return DE_ACCESS;
  422. }
  423. dir_read(fnp1);
  424. if(fnp1 -> f_dir.dir_name[0] != '.')
  425. {
  426. dir_close(fnp);
  427. return DE_ACCESS;
  428. }
  429. /* Now search through the directory and make certain    */
  430. /* that there are no entries.                           */
  431. found = FALSE;
  432. while(dir_read(fnp1) == DIRENT_SIZE)
  433. {
  434. if(fnp1 -> f_dir.dir_name[0] == '')
  435. break;
  436. if(fnp1 -> f_dir.dir_name[0] == DELETED)
  437. continue;
  438. else
  439. {
  440. found = TRUE;
  441. break;
  442. }
  443. }
  444. dir_close(fnp1);
  445. /* If anything was found, exit with an error.   */
  446. if(found)
  447. {
  448. dir_close(fnp);
  449. return DE_ACCESS;
  450. }
  451. /* Ok, so we can delete. Start out by           */
  452. /* clobbering all FAT entries for this file     */
  453. /* (or, in English, truncate the FAT).          */
  454. wipe_out(fnp);
  455. fnp -> f_dir.dir_size = 0l;
  456. *(fnp -> f_dir.dir_name) = DELETED;
  457. /* The directory has been modified, so set the  */
  458. /* bit before closing it, allowing it to be     */
  459. /* updated                                      */
  460. fnp -> f_flags.f_dmod = TRUE;
  461. dir_close(fnp);
  462. /* SUCCESSful completion, return it             */
  463. return SUCCESS;
  464. }
  465. else
  466. {
  467. /* No such file, return the error               */
  468. dir_close(fnp);
  469. return DE_FILENOTFND;
  470. }
  471. }
  472. COUNT dos_rename(path1, path2)
  473. BYTE FAR *path1, FAR *path2;
  474. {
  475. REG struct f_node FAR *fnp1;
  476. REG struct f_node FAR *fnp2;
  477. BOOL is_free;
  478. /* first split the passed target into compnents (i.e. - path to */
  479. /* new file name and name of new file name                      */
  480. if((fnp2 = split_path(path2, szSecDirName, szSecFileName, szSecFileExt)) == NULL)
  481. {
  482. dir_close(fnp2);
  483. return DE_PATHNOTFND;
  484. }
  485. /* Check that we don't have a duplicate name, so if we find     */
  486. /* one, it's an error.                                          */
  487. if(find_fname(fnp2, szSecFileName, szSecFileExt))
  488. {
  489. dir_close(fnp2);
  490. return DE_ACCESS;
  491. }
  492. /* next split the passed source into compnents (i.e. - path to  */
  493. /* old file name and name of old file name                      */
  494. if((fnp1 = split_path(path1, szPriDirName, szPriFileName, szPriFileExt)) == NULL)
  495. {
  496. dir_close(fnp1);
  497. dir_close(fnp2);
  498. return DE_PATHNOTFND;
  499. }
  500. /* Reset the directory by a close followed by an open           */
  501. fnp2 -> f_flags.f_dmod = FALSE;
  502. dir_close(fnp2);
  503. fnp2 = dir_open((BYTE FAR *)szSecDirName);
  504. /* Now find a free slot to put the file into.                   */
  505. /* If it's the root and we don't have room, return an error.    */
  506. if(!(is_free = find_free(fnp2)) && (fnp2 -> f_flags.f_droot))
  507. {
  508. fnp2 -> f_flags.f_dmod = FALSE;
  509. dir_close(fnp1);
  510. dir_close(fnp2);
  511. return DE_TOOMANY;
  512. }
  513. /* Otherwise just expand the directory                          */
  514. else if(!is_free && !(fnp2 -> f_flags.f_droot))
  515. {
  516. COUNT ret;
  517. if(extend_dir(fnp2) != SUCCESS)
  518. return ret;
  519. }
  520. if(!find_fname(fnp1, szPriFileName, szPriFileExt))
  521. {
  522. /* No such file, return the error                       */
  523. dir_close(fnp1);
  524. dir_close(fnp2);
  525. return DE_FILENOTFND;
  526. }
  527. /* put the fnode's name into the directory.                     */
  528. fbcopy((BYTE FAR *)szSecFileName,
  529.  (BYTE FAR *)fnp2 -> f_dir.dir_name, FNAME_SIZE);
  530. fbcopy((BYTE FAR *)szSecFileExt,
  531.  (BYTE FAR *)fnp2 -> f_dir.dir_ext, FEXT_SIZE);
  532. /* Set the fnode to the desired mode                            */
  533. fnp2 -> f_dir.dir_size = fnp1 -> f_dir.dir_size;
  534. fnp2 -> f_dir.dir_start = fnp1 -> f_dir.dir_start;
  535. fnp2 -> f_dir.dir_attrib = fnp1 -> f_dir.dir_attrib;
  536. fnp2 -> f_dir.dir_time = fnp1 -> f_dir.dir_time;
  537. fnp2 -> f_dir.dir_date = fnp1 -> f_dir.dir_date;
  538. /* The directory has been modified, so set the bit before       */
  539. /* closing it, allowing it to be updated.                       */
  540. fnp1 -> f_flags.f_dmod = fnp2 -> f_flags.f_dmod = TRUE;
  541. fnp1 -> f_flags.f_dnew = fnp2 -> f_flags.f_dnew = FALSE;
  542. fnp1 -> f_flags.f_ddir = fnp2 -> f_flags.f_ddir = TRUE;
  543. fnp2 -> f_highwater = fnp2 -> f_offset = fnp1 -> f_dir.dir_size;
  544. /* Ok, so we can delete this one. Save the file info.           */
  545. fnp1 -> f_dir.dir_size = 0l;
  546. *(fnp1 -> f_dir.dir_name) = DELETED;
  547. dir_close(fnp1);
  548. dir_close(fnp2);
  549. /* SUCCESSful completion, return it                             */
  550. return SUCCESS;
  551. }
  552. /*                                                              */
  553. /* wipe out all FAT entries for create, delete, etc.            */
  554. /*                                                              */
  555. static VOID 
  556. wipe_out (struct f_node FAR *fnp)
  557. {
  558. REG UWORD st, next;
  559. struct dpb *dpbp = fnp -> f_dpb;
  560. /* if already free or not valid file, just exit         */
  561. if((fnp == NULL) || (fnp -> f_dir.dir_start == FREE))
  562. return;
  563. /* if there are no FAT entries, just exit               */
  564. if(fnp -> f_dir.dir_start == FREE)
  565. return;
  566. /* Loop from start until either a FREE entry is         */
  567. /* encountered (due to a fractured file system) of the  */
  568. /* last cluster is encountered.                         */
  569. for(st = fnp -> f_dir.dir_start ;
  570.   st != LONG_LAST_CLUSTER && st != LAST_CLUSTER;)
  571. {
  572. /* get the next cluster pointed to              */
  573. next = next_cluster(dpbp, st);
  574. /* just exit if a damaged file system exists    */
  575. if(next == FREE)
  576. return;
  577. /* zap the FAT pointed to                       */
  578. link_fat(dpbp, st, FREE);
  579. /* and the start of free space pointer          */
  580. if((dpbp -> dpb_cluster == UNKNCLUSTER)
  581.  || (dpbp -> dpb_cluster > st))
  582. dpbp -> dpb_cluster = st;
  583. /* and just follow the linked list              */
  584. st = next;
  585. }
  586. }
  587. static BOOL 
  588. find_free (struct f_node FAR *fnp)
  589. {
  590. while(dir_read(fnp) == DIRENT_SIZE)
  591. {
  592. if(fnp -> f_dir.dir_name[0] == ''
  593.  || fnp -> f_dir.dir_name[0] == DELETED)
  594. {
  595. return TRUE;
  596. }
  597. }
  598. return !fnp -> f_flags.f_dfull;
  599. }
  600. /*                                                              */
  601. /* dos_getdate for the file date                                */
  602. /*                                                              */
  603. date dos_getdate()
  604. {
  605. #ifndef NOTIME
  606. # ifndef IPL
  607. BYTE WeekDay, Month, MonthDay;
  608. COUNT Year;
  609. date Date;
  610. /* First - get the system date set by either the user   */
  611. /* on start-up or the CMOS clock                        */
  612. DosGetDate((BYTE FAR *)&WeekDay,
  613.  (BYTE FAR *)&Month,
  614.  (BYTE FAR *)&MonthDay,
  615.  (COUNT FAR *)& Year);
  616. Date = DT_ENCODE(Month, MonthDay, Year - EPOCH_YEAR);
  617. return Date;
  618. # else
  619. return 0;
  620. # endif
  621. #else
  622. return 0;
  623. #endif
  624. }
  625. /*                                                              */
  626. /* dos_gettime for the file time                                */
  627. /*                                                              */
  628. time dos_gettime()
  629. {
  630. #ifndef NOTIME
  631. # ifndef IPL
  632. BYTE Hour, Minute, Second, Hundredth;
  633. time Time;
  634. BYTE h;
  635. /* First - get the system time set by either the user   */
  636. /* on start-up or the CMOS clock                        */
  637. DosGetTime((BYTE FAR *)&Hour,
  638.  (BYTE FAR *)&Minute,
  639.  (BYTE FAR *)&Second,
  640.  (BYTE FAR *)&Hundredth);
  641. h = Second * 10 + ((Hundredth + 5) / 10);
  642. Time = TM_ENCODE(Hour, Minute, h);
  643. return Time;
  644. # else
  645. return 0;
  646. # endif
  647. #else
  648. return 0;
  649. #endif
  650. }
  651. #ifndef IPL
  652. /*                                                              */
  653. /* dos_getftime for the file time                               */
  654. /*                                                              */
  655. BOOL dos_getftime(fd, dp, tp)
  656. COUNT fd;
  657. date FAR *dp;
  658. time FAR *tp;
  659. {
  660. struct f_node FAR *fnp;
  661. /* Translate the fd into an fnode pointer, since all internal   */
  662. /* operations are achieved through fnodes.                      */
  663. fnp = xlt_fd(fd);
  664. /* If the fd was invalid because it was out of range or the     */
  665. /* requested file was not open, tell the caller and exit        */
  666. /* note: an invalid fd is indicated by a 0 return               */
  667. if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
  668. return FALSE;
  669. /* Get the date and time from the fnode and return              */
  670. *dp = fnp -> f_dir.dir_date;
  671. *tp = fnp -> f_dir.dir_time;
  672. return TRUE;
  673. }
  674. /*                                                              */
  675. /* dos_setftime for the file time                               */
  676. /*                                                              */
  677. BOOL dos_setftime(fd, dp, tp)
  678. COUNT fd;
  679. date FAR *dp;
  680. time FAR *tp;
  681. {
  682. struct f_node FAR *fnp;
  683. /* Translate the fd into an fnode pointer, since all internal   */
  684. /* operations are achieved through fnodes.                      */
  685. fnp = xlt_fd(fd);
  686. /* If the fd was invalid because it was out of range or the     */
  687. /* requested file was not open, tell the caller and exit        */
  688. /* note: an invalid fd is indicated by a 0 return               */
  689. if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
  690. return FALSE;
  691. /* Set the date and time from the fnode and return              */
  692. fnp -> f_dir.dir_date = *dp;
  693. fnp -> f_dir.dir_time = *tp;
  694. return TRUE;
  695. }
  696. /*                                                              */
  697. /* dos_getfsize for the file time                               */
  698. /*                                                              */
  699. LONG 
  700. dos_getcufsize (COUNT fd)
  701. {
  702. struct f_node FAR *fnp;
  703. /* Translate the fd into an fnode pointer, since all internal   */
  704. /* operations are achieved through fnodes.                      */
  705. fnp = xlt_fd(fd);
  706. /* If the fd was invalid because it was out of range or the     */
  707. /* requested file was not open, tell the caller and exit        */
  708. /* note: an invalid fd is indicated by a 0 return               */
  709. if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
  710. return -1l;
  711. /* Return the file size                                         */
  712. return fnp -> f_highwater;
  713. }
  714. /*                                                              */
  715. /* dos_getfsize for the file time                               */
  716. /*                                                              */
  717. LONG 
  718. dos_getfsize (COUNT fd)
  719. {
  720. struct f_node FAR *fnp;
  721. /* Translate the fd into an fnode pointer, since all internal   */
  722. /* operations are achieved through fnodes.                      */
  723. fnp = xlt_fd(fd);
  724. /* If the fd was invalid because it was out of range or the     */
  725. /* requested file was not open, tell the caller and exit        */
  726. /* note: an invalid fd is indicated by a 0 return               */
  727. if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
  728. return -1l;
  729. /* Return the file size                                         */
  730. return fnp -> f_dir.dir_size;
  731. }
  732. /*                                                              */
  733. /* dos_setfsize for the file time                               */
  734. /*                                                              */
  735. BOOL 
  736. dos_setfsize (COUNT fd, LONG size)
  737. {
  738. struct f_node FAR *fnp;
  739. /* Translate the fd into an fnode pointer, since all internal   */
  740. /* operations are achieved through fnodes.                      */
  741. fnp = xlt_fd(fd);
  742. /* If the fd was invalid because it was out of range or the     */
  743. /* requested file was not open, tell the caller and exit        */
  744. /* note: an invalid fd is indicated by a 0 return               */
  745. if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
  746. return FALSE;
  747. /* Change the file size                                         */
  748. fnp -> f_dir.dir_size = size;
  749. fnp -> f_highwater = size;
  750. return TRUE;
  751. }
  752. #endif
  753. /*                                                              */
  754. /* Find free cluster in disk FAT table                          */
  755. /*                                                              */
  756. static UWORD 
  757. find_fat_free (struct f_node FAR *fnp)
  758. {
  759. REG UWORD idx;
  760. /* Start from optimized lookup point for start of FAT   */
  761. if(fnp -> f_dpb -> dpb_cluster != UNKNCLUSTER)
  762. idx =  fnp -> f_dpb -> dpb_cluster;
  763. else
  764. idx = 2;
  765. /* Search the FAT table looking for the first free      */
  766. /* entry.                                               */
  767. for( ; idx < fnp -> f_dpb -> dpb_size; idx++)
  768. {
  769. if(next_cluster(fnp -> f_dpb, idx) == FREE)
  770. break;
  771. }
  772. /* No empty clusters, disk is FULL!                     */
  773. if(idx >= fnp -> f_dpb -> dpb_size)
  774. {
  775. fnp -> f_dpb -> dpb_cluster = UNKNCLUSTER;
  776. dir_close(fnp);
  777. return LONG_LAST_CLUSTER;
  778. }
  779. /* return the free entry                                */
  780. fnp -> f_dpb -> dpb_cluster = idx;
  781. return idx;
  782. }
  783. /*                                                              */
  784. /* crate a directory - returns success or a negative error      */
  785. /* number                                                       */
  786. /*                                                              */
  787. COUNT 
  788. dos_mkdir (BYTE FAR *dir)
  789. {
  790. REG struct f_node FAR *fnp;
  791. REG COUNT idx;
  792. struct buffer FAR *bp;
  793. BYTE FAR *p;
  794. UWORD free_fat;
  795. UWORD parent;
  796. /* first split the passed dir into comopnents (i.e. -   */
  797. /* path to new directory and name of new directory      */
  798. if((fnp = split_path(dir, szDirName, szFileName, szFileExt)) == NULL)
  799. {
  800. dir_close(fnp);
  801. return DE_PATHNOTFND;
  802. }
  803. /* Check that we don't have a duplicate name, so if we  */
  804. /* find one, it's an error.                             */
  805. if(find_fname(fnp, szFileName, szFileExt))
  806. {
  807. dir_close(fnp);
  808. return DE_ACCESS;
  809. }
  810. else
  811. {
  812. BOOL is_free;
  813. /* Reset the directory by a close followed by   */
  814. /* an open                                      */
  815. fnp -> f_flags.f_dmod = FALSE;
  816. parent = fnp -> f_dirstart;
  817. dir_close(fnp);
  818. fnp = dir_open((BYTE FAR *)szDirName);
  819. /* Get a free f_node pointer so that we can use */
  820. /* it in building the new file.                 */
  821. /* Note that if we're in the root and we don't  */
  822. /* find an empty slot, we need to abort.        */
  823. if(!(is_free = find_free(fnp)) && (fnp -> f_flags.f_droot))
  824. {
  825. fnp -> f_flags.f_dmod = FALSE;
  826. dir_close(fnp);
  827. return DE_TOOMANY;
  828. }
  829. /* Otherwise just expand the directory          */
  830. else if(!is_free && !(fnp -> f_flags.f_droot))
  831. {
  832. COUNT ret;
  833. if(extend_dir(fnp) != SUCCESS)
  834. return ret;
  835. }
  836. /* put the fnode's name into the directory.             */
  837. fbcopy((BYTE FAR *)szFileName,
  838.  (BYTE FAR *)fnp -> f_dir.dir_name, FNAME_SIZE);
  839. fbcopy((BYTE FAR *)szFileExt,
  840.  (BYTE FAR *)fnp -> f_dir.dir_ext, FEXT_SIZE);
  841. /* Set the fnode to the desired mode                            */
  842. fnp -> f_mode = WRONLY;
  843. fnp -> f_back = LONG_LAST_CLUSTER;
  844. fnp -> f_dir.dir_size = 0l;
  845. fnp -> f_dir.dir_start = FREE;
  846. fnp -> f_dir.dir_attrib = D_DIR;
  847. fnp -> f_dir.dir_time = dos_gettime();
  848. fnp -> f_dir.dir_date = dos_getdate();
  849. fnp -> f_flags.f_dmod = TRUE;
  850. fnp -> f_flags.f_dnew = FALSE;
  851. fnp -> f_flags.f_ddir = TRUE;
  852. fnp -> f_highwater = 0l;
  853. fnp -> f_offset = 0l;
  854. }
  855. /* get an empty cluster, so that we make it into a      */
  856. /* directory.                                           */
  857. free_fat = find_fat_free(fnp);
  858. /* No empty clusters, disk is FULL! Translate into a    */
  859. /* useful error message.                                */
  860. if(free_fat == LONG_LAST_CLUSTER)
  861. {
  862. dir_close(fnp);
  863. return DE_HNDLDSKFULL;
  864. }
  865. /* Mark the cluster in the FAT as used                  */
  866. fnp -> f_dir.dir_start = fnp -> f_cluster = free_fat;
  867. link_fat(fnp -> f_dpb, (UCOUNT)free_fat, LONG_LAST_CLUSTER);
  868. /* Craft the new directory. Note that if we're in a new */
  869. /* directory just under the root, ".." pointer is 0.    */
  870. bp = getblock((LONG)clus2phys(free_fat,
  871. fnp -> f_dpb -> dpb_clssize,
  872. fnp -> f_dpb -> dpb_data),
  873. fnp -> f_dpb -> dpb_unit);
  874. if(bp == NULL)
  875. {
  876. dir_close(fnp);
  877. return DE_BLKINVLD;
  878. }
  879. /* Create the "." entry                                 */
  880. bcopy(".       ", (BYTE *)DirEntBuffer.dir_name, FNAME_SIZE);
  881. bcopy("   ", (BYTE *)DirEntBuffer.dir_ext, FEXT_SIZE);
  882. DirEntBuffer.dir_attrib = D_DIR;
  883. DirEntBuffer.dir_time = dos_gettime();
  884. DirEntBuffer.dir_date = dos_getdate();
  885. DirEntBuffer.dir_start = free_fat;
  886. DirEntBuffer.dir_size = 0l;
  887. /* And put it out                                       */
  888. putdirent((struct dirent FAR *)&DirEntBuffer, (BYTE FAR *)bp ->b_buffer);
  889. /* create the ".." entry                                */
  890. bcopy("..      ", (BYTE *)DirEntBuffer.dir_name, FNAME_SIZE);
  891. DirEntBuffer.dir_start = parent;
  892. /* and put it out                                       */
  893. putdirent((struct dirent FAR *)&DirEntBuffer, (BYTE FAR *)&bp -> b_buffer[DIRENT_SIZE]);
  894. /* fill the rest of the block with zeros                */
  895. for(p = (BYTE FAR *)&bp -> b_buffer[2 *DIRENT_SIZE];
  896.  p < &bp -> b_buffer[BUFFERSIZE]; )
  897. *p++ = NULL;
  898. /* Mark the block to be written out                     */
  899. bp -> b_flag |= BFR_DIRTY;
  900. /* clear out the rest of the blocks in the cluster      */
  901. for(idx = 1; idx < fnp -> f_dpb -> dpb_clssize; idx++)
  902. {
  903. REG COUNT i;
  904. bp = getblock(
  905. (LONG)clus2phys(fnp -> f_dir.dir_start,
  906. fnp -> f_dpb -> dpb_clssize,
  907. fnp -> f_dpb -> dpb_data) + idx,
  908. fnp -> f_dpb -> dpb_unit);
  909. if(bp == NULL)
  910. {
  911. dir_close(fnp);
  912. return DE_BLKINVLD;
  913. }
  914. for(i = 0, p = (BYTE FAR *)bp -> b_buffer; i < BUFFERSIZE; i++)
  915. *p++ = NULL;
  916. bp -> b_flag |= BFR_DIRTY;
  917. }
  918. /* flush the drive buffers so that all info is written  */
  919. flush_buffers((COUNT)(fnp -> f_dpb -> dpb_unit));
  920. /* Close the directory so that the entry is updated     */
  921. fnp -> f_flags.f_dmod = TRUE;
  922. dir_close(fnp);
  923. return SUCCESS;
  924. }
  925. #endif
  926. BOOL 
  927. last_link (struct f_node FAR *fnp)
  928. {
  929. return (((UWORD)fnp -> f_cluster == (UWORD)LONG_LAST_CLUSTER)
  930.  || ((UWORD)fnp -> f_cluster == (UWORD)LAST_CLUSTER));
  931. }
  932. #ifndef IPL
  933. static BOOL 
  934. extend (struct f_node FAR *fnp)
  935. {
  936. UWORD free_fat;
  937. /* get an empty cluster, so that we use it to extend the file.  */
  938. free_fat = find_fat_free(fnp);
  939. /* No empty clusters, disk is FULL! Translate into a useful     */
  940. /* error message.                                               */
  941. if(free_fat == LONG_LAST_CLUSTER)
  942. return FALSE;
  943. /* Now that we've found a free FAT entry, mark it as the last   */
  944. /* entry and save.                                              */
  945. link_fat(fnp -> f_dpb, (UCOUNT)fnp -> f_back, free_fat);
  946. fnp -> f_cluster = free_fat;
  947. link_fat(fnp -> f_dpb, (UCOUNT)free_fat, LONG_LAST_CLUSTER);
  948. /* Mark the directory so that the entry is updated              */
  949. fnp -> f_flags.f_dmod = TRUE;
  950. return TRUE;
  951. }
  952. static COUNT 
  953. extend_dir (struct f_node FAR *fnp)
  954. {
  955. REG COUNT idx;
  956. if(!extend(fnp))
  957. {
  958. dir_close(fnp);
  959. return DE_HNDLDSKFULL;
  960. }
  961. /* clear out the rest of the blocks in the cluster              */
  962. for(idx = 0; idx < fnp -> f_dpb -> dpb_clssize; idx++)
  963. {
  964. REG COUNT i;
  965. REG BYTE FAR *p;
  966. REG struct buffer FAR *bp;
  967. bp = getblock(
  968. (LONG)clus2phys(fnp -> f_cluster,
  969. fnp -> f_dpb -> dpb_clssize,
  970. fnp -> f_dpb -> dpb_data) + idx,
  971. fnp -> f_dpb -> dpb_unit);
  972. if(bp == NULL)
  973. {
  974. dir_close(fnp);
  975. return DE_BLKINVLD;
  976. }
  977. for(i = 0, p = (BYTE FAR *)bp -> b_buffer; i < BUFFERSIZE; i++)
  978. *p++ = NULL;
  979. bp -> b_flag |= BFR_DIRTY;
  980. }
  981. if(!find_free(fnp))
  982. {
  983. dir_close(fnp);
  984. return DE_HNDLDSKFULL;
  985. }
  986. /* flush the drive buffers so that all info is written          */
  987. flush_buffers((COUNT)(fnp -> f_dpb -> dpb_unit));
  988. return SUCCESS;
  989. }
  990. static BOOL 
  991. first_fat (struct f_node FAR *fnp)
  992. {
  993. UWORD free_fat;
  994. /* get an empty cluster, so that we make it into a file.        */
  995. free_fat = find_fat_free(fnp);
  996. /* No empty clusters, disk is FULL! Translate into a useful     */
  997. /* error message.                                               */
  998. if(free_fat == LONG_LAST_CLUSTER)
  999. return FALSE;
  1000. /* Now that we've found a free FAT entry, mark it as the last   */
  1001. /* entry and save it.                                           */
  1002. fnp -> f_dir.dir_start = free_fat;
  1003. link_fat(fnp -> f_dpb, (UCOUNT)free_fat, LONG_LAST_CLUSTER);
  1004. /* Mark the directory so that the entry is updated              */
  1005. fnp -> f_flags.f_dmod = TRUE;
  1006. return TRUE;
  1007. }
  1008. #endif
  1009. COUNT 
  1010. map_cluster (REG struct f_node FAR *fnp, COUNT mode)
  1011. {
  1012. ULONG idx;
  1013. WORD clssize, secsize;
  1014. /* Set internal index and cluster size.                 */
  1015. idx = fnp -> f_offset;
  1016. /* The variable clssize will be used later.             */
  1017. secsize = fnp -> f_dpb -> dpb_secsize;
  1018. clssize = secsize * fnp -> f_dpb -> dpb_clssize;
  1019. #ifndef IPL
  1020. /* If someone did a seek, but no writes have occured, we will   */
  1021. /* need to initialize the fnode.                                */
  1022. if((mode == XFR_WRITE) && (fnp -> f_dir.dir_start == FREE))
  1023. {        
  1024. if(!first_fat(fnp))
  1025. return DE_HNDLDSKFULL;
  1026. }
  1027. #endif
  1028. /* Now begin the linear search. The relative cluster is         */
  1029. /* maintained as part of the set of physical indices. It is     */
  1030. /* also the highest order index and is mapped directly into     */
  1031. /* physical cluster. Our search is performed by pacing an index */
  1032. /* up to the relative cluster position where the index falls    */
  1033. /* within the cluster.                                          */
  1034. /*                                                              */
  1035. /* NOTE: make sure your compiler does not optimize for loop     */
  1036. /* tests to the loop exit. We need to fall out immediately for  */
  1037. /* files whose length < cluster size.                           */
  1038. for(fnp -> f_cluster = fnp -> f_flags.f_ddir ?
  1039. fnp -> f_dirstart :
  1040. fnp -> f_dir.dir_start;
  1041.   idx >= clssize;
  1042.    idx -= clssize)
  1043. {
  1044. /* If this is a read and the next is a LAST_CLUSTER,    */
  1045. /* then we are going to read past EOF, return zero read */
  1046. if((mode == XFR_READ) && last_link(fnp))
  1047. return DE_SEEK;
  1048. #ifndef IPL
  1049. /* expand the list if we're going to write and have run into    */
  1050. /* the last cluster marker.                                     */
  1051. else if((mode == XFR_WRITE) && last_link(fnp))
  1052. {
  1053. if(!extend(fnp))
  1054. {
  1055. dir_close(fnp);
  1056. return DE_HNDLDSKFULL;
  1057. }
  1058. }
  1059. #endif
  1060. fnp -> f_back = fnp -> f_cluster;
  1061. fnp -> f_cluster = next_cluster(fnp -> f_dpb,fnp -> f_cluster);
  1062. }
  1063. return SUCCESS;
  1064. }
  1065. UCOUNT 
  1066. rdwrblock (COUNT fd, VOID FAR *buffer, UCOUNT count, COUNT mode, COUNT *err)
  1067. {
  1068. REG struct f_node FAR *fnp;
  1069. REG struct buffer FAR *bp;
  1070. UCOUNT xfr_cnt = 0, ret_cnt = 0;
  1071. LONG idx;
  1072. WORD secsize;
  1073. UCOUNT to_xfer = count;
  1074. #ifdef DEBUG
  1075. if(bDumpRdWrParms)
  1076. {
  1077. printf("rdwrblock: mode = %sn",
  1078.  mode == XFR_WRITE ? "WRITE" : "READ");
  1079. printf(" fd   buffer     countn --   ------     -----n");
  1080. printf(" %02d   %04x:%04x   %dn",
  1081.  fd, (COUNT)FP_SEG(buffer), (COUNT)FP_OFF(buffer), count);
  1082. }
  1083. #endif
  1084. /* Translate the fd into an fnode pointer, since all internal   */
  1085. /* operations are achieved through fnodes.                      */
  1086. fnp = xlt_fd(fd);
  1087. /* If the fd was invalid because it was out of range or the     */
  1088. /* requested file was not open, tell the caller and exit        */
  1089. /* note: an invalid fd is indicated by a 0 return               */
  1090. if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
  1091. {
  1092. *err = DE_INVLDHNDL;
  1093. return 0;
  1094. }
  1095. /* Test that we are really about to do a data transfer. If the  */
  1096. /* count is zero and the mode is XFR_READ, just exit. (Any */
  1097. /* read with a count of zero is a nop).                         */
  1098. /*                                                              */
  1099. /* A write (mode is XFR_WRITE) is a special case.  It sets the */
  1100. /* file length to the current length (truncates it).            */
  1101. /*                                                              */
  1102. /* NOTE: doing this up front saves a lot of headaches later.    */
  1103. if(count == 0)
  1104. {
  1105. if(mode == XFR_WRITE)
  1106. {
  1107. fnp -> f_highwater = fnp -> f_offset;
  1108. }
  1109. *err = SUCCESS;
  1110. return 0;
  1111. }
  1112. /* Another test is to check for a seek past EOF on an XFR_READ  */
  1113. /* operation.                                                   */
  1114. if(mode == XFR_READ
  1115.  && !fnp -> f_flags.f_ddir
  1116.  && (fnp -> f_offset >= fnp -> f_dir.dir_size))
  1117. {
  1118. *err = SUCCESS;
  1119. return 0;
  1120. }
  1121. /* test that we have a valid mode for this fnode                */
  1122. switch(mode)
  1123. {
  1124. case XFR_READ:
  1125. if(fnp -> f_mode != RDONLY && fnp -> f_mode != RDWR)
  1126. {
  1127. *err = DE_INVLDACC;
  1128. return 0;
  1129. }
  1130. break;
  1131. #ifndef IPL
  1132. case XFR_WRITE:
  1133. if(fnp -> f_mode != WRONLY && fnp -> f_mode != RDWR)
  1134. {
  1135. *err = DE_INVLDACC;
  1136. return 0;
  1137. }
  1138. break;
  1139. #endif
  1140. default:
  1141. *err = DE_INVLDACC;
  1142. return 0;
  1143. }
  1144. /* The variable secsize will be used later.                     */
  1145. secsize = fnp -> f_dpb -> dpb_secsize;
  1146. /* Adjust the far pointer from user space to supervisor space   */
  1147. buffer = adjust_far((VOID FAR *)buffer);
  1148. /* Do the data transfer. Use block transfer methods so that we  */
  1149. /* can utilize memory management in future DOS-C versions. */
  1150. while(ret_cnt < count)
  1151. {
  1152. /* Position the file to the fnode's pointer position. This is   */
  1153. /* done by updating the fnode's cluster, block (sector) and     */
  1154. /* byte offset so that read or write becomes a simple data move */
  1155. /* into or out of the block data buffer.                        */
  1156. if(fnp -> f_offset == 0l)
  1157. {
  1158. #ifndef IPL
  1159. /* For the write case, a newly created file     */
  1160. /* will have a start cluster of FREE. If we're  */
  1161. /* doing a write and this is the first time     */
  1162. /* through, allocate a new cluster to the file. */
  1163. if((mode == XFR_WRITE)
  1164.  && (fnp -> f_dir.dir_start == FREE))
  1165. if(!first_fat(fnp))
  1166. {
  1167. dir_close(fnp);
  1168. *err = DE_HNDLDSKFULL;
  1169. return ret_cnt;
  1170. }
  1171. #endif
  1172. /* complete the common operations of            */
  1173. /* initializing to the starting cluster and     */
  1174. /* setting all offsets to zero.                 */
  1175. fnp -> f_cluster = fnp -> f_dir.dir_start;
  1176. fnp -> f_back = LONG_LAST_CLUSTER;
  1177. fnp -> f_sector = 0;
  1178. fnp -> f_boff = 0;
  1179. }
  1180. /* The more difficult scenario is the (more common)     */
  1181. /* file offset case. Here, we need to take the fnode's  */
  1182. /* offset pointer (f_offset) and translate it into a    */
  1183. /* relative cluster position, cluster block (sector)    */
  1184. /* offset (f_sector) and byte offset (f_boff). Once we  */
  1185. /* have this information, we need to translate the      */
  1186. /* relative cluster position into an absolute cluster   */
  1187. /* position (f_cluster). This is unfortunate because it */
  1188. /* requires a linear search through the file's FAT      */
  1189. /* entries. It made sense when DOS was originally       */
  1190. /* designed as a simple floppy disk operating system    */
  1191. /* where the FAT was contained in core, but now         */
  1192. /* requires a search through the FAT blocks.            */
  1193. /*                                                      */
  1194. /* The algorithm in this function takes advantage of    */
  1195. /* the blockio block buffering scheme to simplify the   */
  1196. /* task.                                                */
  1197. else
  1198. switch(map_cluster(fnp, mode))
  1199. {
  1200. case DE_SEEK:
  1201. *err = DE_SEEK;
  1202. dir_close(fnp);
  1203. return ret_cnt;
  1204. default:
  1205. dir_close(fnp);
  1206. *err = DE_HNDLDSKFULL;
  1207. return ret_cnt;
  1208. case SUCCESS:
  1209. break;
  1210. }
  1211. #ifndef IPL
  1212. /* XFR_WRITE case only - if we're at the end, the next  */
  1213. /* FAT is an EOF marker, so just extend the file length */
  1214. if(mode == XFR_WRITE && last_link(fnp))
  1215. if(!extend(fnp))
  1216. {
  1217. dir_close(fnp);
  1218. *err = DE_HNDLDSKFULL;
  1219. return ret_cnt;
  1220. }
  1221. #endif
  1222. /* Compute the block within the cluster and the offset  */
  1223. /* within the block.                                    */
  1224. fnp -> f_sector =
  1225.  (fnp -> f_offset / secsize) & fnp -> f_dpb -> dpb_clsmask;
  1226. fnp -> f_boff = fnp -> f_offset % secsize;
  1227. #ifdef DSK_DEBUG
  1228. printf("%d links; dir offset %ld, starting at cluster %dn",
  1229. fnp -> f_count,
  1230. fnp -> f_diroff,
  1231. fnp -> f_cluster);
  1232. #endif
  1233. /* Do an EOF test and return whatever was transferred   */
  1234. /* but only for regular files in XFR_READ mode          */
  1235. if((mode == XFR_READ) && !(fnp -> f_flags.f_ddir)
  1236.   && (fnp -> f_offset >= fnp -> f_dir.dir_size))
  1237. {
  1238. *err = SUCCESS;
  1239. return ret_cnt;
  1240. }
  1241. /* Get the block we need from cache                     */
  1242. bp = getblock(
  1243. (LONG)clus2phys(fnp -> f_cluster,
  1244. fnp -> f_dpb -> dpb_clssize,
  1245. fnp -> f_dpb -> dpb_data) + fnp -> f_sector,
  1246. fnp -> f_dpb -> dpb_unit);
  1247. if(bp == (struct buffer *)0)
  1248. {
  1249. *err = DE_BLKINVLD;
  1250. return ret_cnt;
  1251. }
  1252. /* transfer a block                                     */
  1253. /* Transfer size as either a full block size, or the    */
  1254. /* requested transfer size, whichever is smaller.       */
  1255. /* Then compare to what is left, since we can transfer  */
  1256. /* a maximum of what is left.                           */
  1257. switch(mode)
  1258. {
  1259. case XFR_READ:
  1260. if(fnp -> f_flags.f_ddir)
  1261. xfr_cnt = min(to_xfer,
  1262.  secsize - fnp -> f_boff);
  1263. else
  1264. xfr_cnt = min(min(to_xfer,
  1265.  secsize - fnp -> f_boff),
  1266.   fnp -> f_dir.dir_size - fnp -> f_offset);
  1267. fbcopy((BYTE FAR *)&bp -> b_buffer[fnp -> f_boff],
  1268.  buffer,
  1269.   xfr_cnt);
  1270. break;
  1271. #ifndef IPL
  1272. case XFR_WRITE:
  1273. xfr_cnt = min(to_xfer, secsize - fnp -> f_boff);
  1274. fbcopy(buffer,
  1275.  (BYTE FAR *)&bp -> b_buffer[fnp -> f_boff],
  1276.   xfr_cnt);
  1277. bp -> b_flag |= BFR_DIRTY;
  1278. break;
  1279. #endif
  1280. default:
  1281. *err =  DE_INVLDACC;
  1282. return ret_cnt;
  1283. }
  1284. /* update pointers and counters                         */
  1285. ret_cnt += xfr_cnt;
  1286. to_xfer -= xfr_cnt;
  1287. fnp -> f_offset += xfr_cnt;
  1288. buffer = add_far((VOID FAR *)buffer, (ULONG)xfr_cnt);
  1289. if(mode == XFR_WRITE && (fnp -> f_offset > fnp -> f_highwater))
  1290. fnp -> f_highwater = fnp -> f_offset;
  1291. }
  1292. *err = SUCCESS;
  1293. return ret_cnt;
  1294. }
  1295. COUNT 
  1296. dos_read (COUNT fd, VOID FAR *buffer, UCOUNT count)
  1297. {
  1298. COUNT err, xfr;
  1299. xfr = rdwrblock(fd, buffer, count, XFR_READ, &err);
  1300. return err != SUCCESS ? err : xfr;
  1301. }
  1302. #ifndef IPL
  1303. COUNT 
  1304. dos_write (COUNT fd, VOID FAR *buffer, UCOUNT count)
  1305. {
  1306. REG struct f_node FAR *fnp;
  1307. COUNT err, xfr;
  1308. /* First test if we need to fill to new EOF. */
  1309. /* Translate the fd into an fnode pointer, since all internal   */
  1310. /* operations are achieved through fnodes.                      */
  1311. fnp = xlt_fd(fd);
  1312. /* If the fd was invalid because it was out of range or the     */
  1313. /* requested file was not open, tell the caller and exit        */
  1314. /* note: an invalid fd is indicated by a 0 return               */
  1315. if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
  1316. {
  1317. return DE_INVLDHNDL;
  1318. }
  1319. /* Future note: for security purposes, this should be set to */
  1320. /* blocks of 0.  This satisfies spec and guarantees no secure */
  1321. /* info is written to disk. */
  1322. /* Also, with real memory management, this may cause a page */
  1323. /* fault. */
  1324. if(fnp -> f_offset > fnp -> f_highwater)
  1325. {
  1326. ULONG lCount = fnp -> f_offset - fnp -> f_highwater;
  1327. while(lCount > 0)
  1328. {
  1329. rdwrblock(fd, buffer,
  1330. lCount > 512l ? 512 : (UCOUNT)lCount,
  1331. XFR_WRITE, &err);
  1332. lCount -= 512;
  1333. }
  1334. }
  1335. xfr = rdwrblock(fd, buffer, count, XFR_WRITE, &err);
  1336. return err != SUCCESS ? err : xfr;
  1337. }
  1338. #endif
  1339. /* Position the file pointer to the desired offset                      */
  1340. /* Returns a long current offset or a negative error code               */
  1341. LONG 
  1342. dos_lseek (COUNT fd, LONG foffset, COUNT origin)
  1343. {
  1344. REG struct f_node FAR *fnp;
  1345. /* Translate the fd into a useful pointer                       */
  1346. fnp = xlt_fd(fd);
  1347. /* If the fd was invalid because it was out of range or the     */
  1348. /* requested file was not open, tell the caller and exit                */
  1349. /* note: an invalid fd is indicated by a 0 return               */
  1350. if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
  1351. return (LONG)DE_INVLDHNDL;
  1352. /* now do the actual lseek adjustment to the file poitner       */
  1353. switch(origin)
  1354. {
  1355. /* offset from beginning of file                                */
  1356. case 0:
  1357. return fnp -> f_offset = (ULONG)foffset;
  1358. /* offset from current location                                 */
  1359. case 1:
  1360. return fnp -> f_offset += foffset;
  1361. /* offset from eof */
  1362. case 2:
  1363. return fnp -> f_offset = fnp -> f_highwater + foffset;
  1364. /* default to an invalid function                               */
  1365. default:
  1366. return (LONG)DE_INVLDFUNC;
  1367. }
  1368. }
  1369. UWORD 
  1370. dos_free (struct dpb *dpbp)
  1371. {
  1372. /* There's an unwritten rule here. All fs       */
  1373. /* cluster start at 2 and run to max_cluster+2  */
  1374. REG UWORD i, cnt = 0;
  1375. UWORD max_cluster = ((ULONG)dpbp -> dpb_size
  1376.     * (ULONG)dpbp -> dpb_clssize - dpbp -> dpb_data + 1)
  1377.     / dpbp -> dpb_clssize + 2; 
  1378. if(dpbp -> dpb_nfreeclst != UNKNCLUSTER)
  1379. return dpbp -> dpb_nfreeclst;
  1380. else
  1381. {
  1382. for(i = 2; i < max_cluster; i++)
  1383. {
  1384. if(next_cluster(dpbp, i) == 0)
  1385. ++cnt;
  1386. }
  1387. dpbp -> dpb_nfreeclst = cnt;
  1388. return cnt;
  1389. }
  1390. }
  1391. VOID 
  1392. dos_pwd (struct dpb *dpbp, BYTE FAR *s)
  1393. {
  1394. fsncopy((BYTE FAR *)&dpbp -> dpb_path[1], s, 64);
  1395. }
  1396. #ifndef IPL
  1397. COUNT 
  1398. dos_cd (struct dpb *dpbp, BYTE FAR *s)
  1399. {
  1400. BYTE FAR *p;
  1401. struct f_node FAR *fnp;
  1402. /* Get the current directory so that we initialize all access   */
  1403. /* relative to root.                                            */
  1404. truename(s, PriPathName);
  1405. /* now test for its existance. If it doesn't, return an error.  */
  1406. /* If it does, copy the path to the current directory           */
  1407. /* structure.                                                   */
  1408. if((fnp = dir_open((BYTE FAR *)PriPathName)) == NULL)
  1409. return DE_PATHNOTFND;
  1410. else
  1411. {
  1412. dir_close(fnp);
  1413. scopy(&PriPathName[2], dpbp -> dpb_path);
  1414. return SUCCESS;
  1415. }
  1416. }
  1417. #endif
  1418. struct f_node FAR *
  1419. get_f_node (void)
  1420. {
  1421. REG i;
  1422. for(i = 0; i < NFILES; i++)
  1423. {
  1424. if(f_nodes[i].f_count == 0)
  1425. {
  1426. ++f_nodes[i].f_count;
  1427. return &f_nodes[i];
  1428. }
  1429. }
  1430. return (struct f_node FAR *)0;
  1431. }
  1432. VOID 
  1433. release_f_node (struct f_node FAR *fnp)
  1434. {
  1435. if(fnp -> f_count > 0)
  1436. --fnp -> f_count;
  1437. else
  1438. fnp -> f_count = 0;
  1439. }
  1440. #ifndef IPL
  1441. VOID 
  1442. dos_setdta (BYTE FAR *newdta)
  1443. {
  1444. dta = newdta;
  1445. }
  1446. COUNT 
  1447. dos_getfattr (BYTE FAR *name, UWORD FAR *attrp)
  1448. {
  1449. struct f_node FAR *fnp;
  1450. COUNT fd;
  1451. /* Translate the fd into an fnode pointer, since all internal   */
  1452. /* operations are achieved through fnodes.                      */
  1453. if((fd = dos_open(name, O_RDONLY)) < SUCCESS)
  1454. return DE_FILENOTFND;
  1455. /* note: an invalid fd is indicated by a 0 return               */
  1456. if((fnp = xlt_fd(fd)) == (struct f_node FAR *)0)
  1457. return DE_TOOMANY;
  1458. /* If the fd was invalid because it was out of range or the     */
  1459. /* requested file was not open, tell the caller and exit        */
  1460. if(fnp -> f_count <= 0)
  1461. return DE_FILENOTFND;
  1462. /* Get the attribute from the fnode and return          */
  1463. *attrp = fnp -> f_dir.dir_attrib;
  1464. dos_close(fd);
  1465. return SUCCESS;
  1466. }
  1467. COUNT 
  1468. dos_setfattr (BYTE FAR *name, UWORD FAR *attrp)
  1469. {
  1470. struct f_node FAR *fnp;
  1471. COUNT fd;
  1472. /* Translate the fd into an fnode pointer, since all internal   */
  1473. /* operations are achieved through fnodes.                      */
  1474. if((fd = dos_open(name, O_RDONLY)) < SUCCESS)
  1475. return DE_FILENOTFND;
  1476. /* note: an invalid fd is indicated by a 0 return               */
  1477. if((fnp = xlt_fd(fd)) == (struct f_node FAR *)0)
  1478. return DE_TOOMANY;
  1479. /* If the fd was invalid because it was out of range or the     */
  1480. /* requested file was not open, tell the caller and exit        */
  1481. if(fnp -> f_count <= 0)
  1482. return DE_FILENOTFND;
  1483. /* Set the attribute from the fnode and return          */
  1484. fnp -> f_dir.dir_attrib = *attrp;
  1485. fnp -> f_flags.f_dmod = TRUE;
  1486. dos_close(fd);
  1487. return SUCCESS;
  1488. }
  1489. #endif
  1490. COUNT 
  1491. media_check (REG struct dpb *dpbp)
  1492. {
  1493. bpb FAR *bpbp;
  1494. ULONG   size;
  1495. REG     COUNT i;
  1496. /* First test if anyone has changed the removable media         */
  1497. FOREVER
  1498. {
  1499. MediaReqHdr.r_length = sizeof(request);
  1500. MediaReqHdr.r_unit = dpbp -> dpb_subunit;
  1501. MediaReqHdr.r_command = C_MEDIACHK;
  1502. MediaReqHdr.r_mcmdesc = dpbp -> dpb_mdb;
  1503. MediaReqHdr.r_status = 0;
  1504. execrh((request FAR *)&MediaReqHdr, dpbp -> dpb_device);
  1505. if(!(MediaReqHdr.r_status & S_ERROR) && (MediaReqHdr.r_status & S_DONE))
  1506. break;
  1507. else
  1508. {
  1509. loop1:
  1510. switch(block_error(&MediaReqHdr, dpbp -> dpb_unit))
  1511. {
  1512. case ABORT:
  1513. case FAIL:
  1514. return DE_INVLDDRV;
  1515. case RETRY:
  1516. continue;
  1517. case CONTINUE:
  1518. break;
  1519. default:
  1520. goto loop1;
  1521. }
  1522. }
  1523. }
  1524. switch(MediaReqHdr.r_mcretcode | dpbp -> dpb_flags)
  1525. {
  1526. case M_NOT_CHANGED:
  1527. /* It was definitely not changed, so ignore it          */
  1528. return SUCCESS;
  1529. /* If it is forced or the media may have changed,       */
  1530. /* rebuild the bpb                                      */
  1531. case M_DONT_KNOW:
  1532. flush_buffers(dpbp -> dpb_unit);
  1533. /* If it definitely changed, don't know (falls through) */
  1534. /* or has been changed, rebuild the bpb.                */
  1535. case M_CHANGED:
  1536. default:
  1537. setinvld(dpbp -> dpb_unit);
  1538. FOREVER
  1539. {
  1540. MediaReqHdr.r_length = sizeof(request);
  1541. MediaReqHdr.r_unit = dpbp -> dpb_subunit;
  1542. MediaReqHdr.r_command = C_BLDBPB;
  1543. MediaReqHdr.r_mcmdesc = dpbp -> dpb_mdb;
  1544. MediaReqHdr.r_status = 0;
  1545. execrh((request FAR *)&MediaReqHdr, dpbp -> dpb_device);
  1546. if(!(MediaReqHdr.r_status & S_ERROR) && (MediaReqHdr.r_status & S_DONE))
  1547. break;
  1548. else
  1549. {
  1550. loop2:
  1551. switch(block_error(&MediaReqHdr, dpbp -> dpb_unit))
  1552. {
  1553. case ABORT:
  1554. case FAIL:
  1555. return DE_INVLDDRV;
  1556. case RETRY:
  1557. continue;
  1558. case CONTINUE:
  1559. break;
  1560. default:
  1561. goto loop2;
  1562. }
  1563. }
  1564. }
  1565. bpbp = MediaReqHdr.r_bpptr;
  1566. dpbp -> dpb_mdb = bpbp -> bpb_mdesc;
  1567. dpbp -> dpb_secsize = bpbp -> bpb_nbyte;
  1568. dpbp -> dpb_clssize = bpbp -> bpb_nsector;
  1569. dpbp -> dpb_clsmask = bpbp -> bpb_nsector - 1;
  1570. dpbp -> dpb_fatstrt = bpbp -> bpb_nreserved;
  1571. dpbp -> dpb_fats = bpbp -> bpb_nfat;
  1572. dpbp -> dpb_dirents = bpbp -> bpb_ndirent;
  1573. size =  bpbp -> bpb_nsize == 0 ?
  1574.  bpbp -> bpb_huge :
  1575.  (ULONG)bpbp -> bpb_nsize;
  1576. dpbp -> dpb_size = size / ((ULONG)bpbp -> bpb_nsector);
  1577. dpbp -> dpb_fatsize = bpbp -> bpb_nfsect;
  1578. dpbp -> dpb_dirstrt = dpbp -> dpb_fatstrt
  1579. + dpbp -> dpb_fats * dpbp -> dpb_fatsize + 1;
  1580. dpbp -> dpb_data = dpbp -> dpb_dirstrt
  1581. + ((DIRENT_SIZE * dpbp -> dpb_dirents
  1582. + (dpbp -> dpb_secsize - 1))
  1583. / dpbp -> dpb_secsize);
  1584. dpbp -> dpb_flags = 0;
  1585. dpbp -> dpb_next = (struct dpb FAR *)-1;
  1586. dpbp -> dpb_cluster = UNKNCLUSTER;
  1587. dpbp -> dpb_nfreeclst = UNKNCLUSTER;
  1588. for(i = 1, dpbp -> dpb_shftcnt = 0;
  1589.  i < (sizeof(dpbp -> dpb_shftcnt) * 8); /* 8 bit bytes in C */
  1590.  dpbp -> dpb_shftcnt++, i <<= 1)
  1591. {
  1592. if(i >= bpbp -> bpb_nsector)
  1593. break;
  1594. }
  1595. return SUCCESS;
  1596. }
  1597. }
  1598. /* translate the fd into an f_node pointer                              */
  1599. struct f_node FAR *
  1600. xlt_fd (COUNT fd)
  1601. {
  1602. return fd > NFILES ? (struct f_node FAR *)0 : &f_nodes[fd];
  1603. }
  1604. COUNT 
  1605. xlt_fnp (struct f_node FAR *fnp)
  1606. {
  1607. return fnp - f_nodes;
  1608. }
  1609. struct dhdr FAR *
  1610. select_unit (COUNT drive)
  1611. {
  1612. /* Just get the header from the dhdr array                      */
  1613. return blk_devices[drive].dpb_device;
  1614. }