1File: FILEIO.C Page 1 1 2 /**************************************************************** 3 * * 4 * CP/M-68K BDOS File I/O Module * 5 * * 6 * This module contains all file handling BDOS functions * 7 * except for read and write for CP/M-68K. Included are: * 8 * * 9 * seldsk() - select disk * 10 * openfile() - open file * 11 * close_fi() - close file * 12 * search() - search for first/next file match * 13 * create() - create file * 14 * delete() - delete file * 15 * rename() - rename file * 16 * set_attr() - set file attributes * 17 * getsize() - get file size * 18 * setran() - set random record field * 19 * free_sp() - get disk free space * 20 * move() - general purpose byte mover * 21 * * 22 * * 23 * Compiled with Alcyon C on the VAX * 24 * * 25 ****************************************************************/ 26 27 #include "bdosinc.h" /* Standard I/O declarations */ 28 29 #include "bdosdef.h" /* Type and structure declarations for BDOS */ 30 31 #include "pktio.h" /* Packet I/O definitions */ 32 33 /* declare external fucntions */ 34 EXTERN UWORD dirscan(); /* directory scanning routine */ 35 EXTERN UWORD error(); /* disk error routine */ 36 EXTERN UWORD ro_err(); /* read-only file error routine */ 37 EXTERN UWORD do_phio(); /* packet disk i/o handler */ 38 EXTERN clraloc(); /* clear bit in allocation vector */ 39 EXTERN setaloc(); /* set bit in allocation vector */ 40 EXTERN UWORD swap(); /* assembly language byte swapper */ 41 EXTERN UWORD dir_wr(); /* directory write routine */ 42 EXTERN tmp_sel(); /* temporary select disk routine */ 43 EXTERN UWORD calcext(); /* calc max extent allocated for fcb */ 44 EXTERN UWORD udiv(); /* unsigned divide routine */ 45 46 47 /* declare external variables */ 48 EXTERN UWORD log_dsk; /* logged-on disk vector */ 49 EXTERN UWORD ro_dsk; /* read-only disk vector */ 50 EXTERN UWORD crit_dsk; /* vector of disks in critical state */ 51 52 53 /************************************ 54 * This function passed to dirscan * 55 * from seldsk (below) * 56 ************************************/ 57 58 BOOLEAN alloc(fcbp, dirp, dirindx) 59 /* Set up allocation vector for directory entry pointed to by dirp */ 1File: FILEIO.C Page 2 60 61 struct fcb *fcbp; /* not used in this function */ 62 REG struct dirent *dirp; /* pointer to directory entry */ 63 WORD dirindx; /* index into directory for *dirp */ 64 { 65 REG WORD i; /* loop counter */ 66 BSETUP 67 68 if ( UBWORD(dirp->entry) < 0x10 ) /* skip MP/M 2.x and CP/M 3.x XFCBs */ 69 { 70 (GBL.dphp)->hiwater = dirindx; /* set up high water mark for disk */ 71 i = 0; 72 if ((GBL.parmp)->dsm < 256) 73 { 74 do setaloc( UBWORD(dirp->dskmap.small[i++]) ); 75 while (i <= 15); 76 } 77 else 78 { 79 do setaloc(swap(dirp->dskmap.big[i++])); 80 while (i <= 7); 81 } 82 } 83 } 84 85 86 /************************ 87 * seldsk entry point * 88 ************************/ 89 90 seldsk(dsknum) 91 92 REG UBYTE dsknum; /* disk number to select */ 93 94 { 95 struct iopb selpkt; 96 REG WORD i; 97 UWORD j; 98 REG UBYTE logflag; 99 BSETUP 100 101 logflag = ~(log_dsk >> dsknum) & 1; 102 if ((GBL.curdsk != dsknum) || logflag) 103 { /* if not last used disk or not logged on */ 104 selpkt.iofcn = sel_info; 105 GBL.curdsk = (selpkt.devnum = dsknum); 106 if (UBWORD(dsknum) > 15) error(2); 107 selpkt.ioflags = logflag ^ 1; 108 do 109 { 110 do_phio(&selpkt); /* actually do the disk select */ 111 if ( (GBL.dphp = selpkt.infop) != NULL ) break; 112 } while ( ! error(3) ); 113 114 GBL.dirbufp = (GBL.dphp)->dbufp; 115 /* set up GBL copies of dir_buf and dpb ptrs */ 116 GBL.parmp = (GBL.dphp)->dpbp; 117 } 118 if (logflag) 1File: FILEIO.C Page 3 119 { /* if disk not previously logged on, do it now */ 120 LOCK /* must lock the file system while messing with alloc vec */ 121 i = (GBL.parmp)->dsm; 122 do clraloc(i); while (i--); /* clear the allocation vector */ 123 i = udiv( (LONG)(((GBL.parmp)->drm) + 1), 124 4 * (((GBL.parmp)->blm) + 1), &j); 125 /* calculate nmbr of directory blks */ 126 if (j) i++; /* round up */ 127 do setaloc(--i); while (i); /* alloc directory blocks */ 128 dirscan(alloc, NULL, 0x0e); /* do directory scan & alloc blocks */ 129 log_dsk |= 1 << dsknum; /* mark disk as logged in */ 130 } 131 } 132 133 134 /******************************* 135 * General purpose byte mover * 136 *******************************/ 137 138 move(p1, p2, i) 139 140 REG BYTE *p1; 141 REG BYTE *p2; 142 REG WORD i; 143 { 144 while (i--) 145 *p2++ = *p1++; 146 } 147 148 149 /************************************* 150 * General purpose filename matcher * 151 *************************************/ 152 153 BOOLEAN match(p1, p2, chk_ext) 154 155 REG UBYTE *p1; 156 REG UBYTE *p2; 157 BOOLEAN chk_ext; 158 { 159 REG WORD i; 160 REG UBYTE temp; 161 BSETUP 162 163 i = 12; 164 do 165 { 166 temp = (*p1 ^ '?'); 167 if ( ((*p1++ ^ *p2++) & 0x7f) && temp ) 168 return(FALSE); 169 i -= 1; 170 } while (i); 171 if (chk_ext) 172 { 173 if ( (*p1 != '?') && ((*p1 ^ *p2) & ~((GBL.parmp)->exm)) ) 174 return(FALSE); 175 p1 += 2; 176 p2 += 2; 177 if ((*p1 ^ *p2) & 0x3f) return(FALSE); 1File: FILEIO.C Page 4 178 } 179 return(TRUE); 180 } 181 182 183 /************************ 184 * openfile entry point * 185 ************************/ 186 187 BOOLEAN openfile(fcbp, dirp, dirindx) 188 189 REG struct fcb *fcbp; /* pointer to fcb for file to open */ 190 struct dirent *dirp; /* pointer to directory entry */ 191 WORD dirindx; 192 193 { 194 REG UBYTE fcb_ext; /* extent field from fcb */ 195 REG BOOLEAN rtn; 196 BSETUP 197 198 if ( rtn = match(fcbp, dirp, TRUE) ) 199 { 200 fcb_ext = fcbp->extent; /* save extent number from user's fcb */ 201 move(dirp, fcbp, sizeof *dirp); 202 /* copy dir entry into user's fcb */ 203 fcbp->extent = fcb_ext; 204 fcbp->s2 |= 0x80; /* set hi bit of S2 (write flag) */ 205 crit_dsk |= 1 << (GBL.curdsk); 206 } 207 return(rtn); 208 } 209 210 211 /*************************/ 212 /* flush buffers routine */ 213 /*************************/ 214 215 UWORD flushit() 216 { 217 REG UWORD rtn; /* return code from flush buffers call */ 218 struct iopb flushpkt; /* I/O packet for flush buffers call */ 219 220 flushpkt.iofcn = flush; 221 while ( rtn = do_phio(&flushpkt) ) 222 if ( error(1) ) break; 223 return(rtn); 224 } 225 226 227 /********************************* 228 * file close routine for dirscan * 229 *********************************/ 230 231 BOOLEAN close(fcbp, dirp, dirindx) 232 233 REG struct fcb *fcbp; /* pointer to fcb */ 234 REG struct dirent *dirp; /* pointer to directory entry */ 235 WORD dirindx; /* index into directory */ 236 1File: FILEIO.C Page 5 237 { 238 REG WORD i; 239 REG UBYTE *fp; 240 REG UBYTE *dp; 241 REG UWORD fcb_ext; 242 REG UWORD dir_ext; 243 BSETUP 244 245 if ( match(fcbp, dirp, TRUE) ) 246 { /* Note that FCB merging is done here as a final 247 confirmation that disks haven't been swapped */ 248 LOCK 249 fp = &(fcbp->dskmap.small[0]); 250 dp = &(dirp->dskmap.small[0]); 251 if ((GBL.parmp)->dsm < 256) 252 { /* Small disk map merge routine */ 253 i = 16; 254 do 255 { 256 if (*dp) 257 { 258 if (*fp) 259 { 260 if (*dp != *fp) goto badmerge; 261 } 262 else *fp = *dp; 263 } 264 else *dp = *fp; 265 fp += 1; 266 dp += 1; 267 i -= 1; 268 } while (i); 269 } 270 else 271 { /* Large disk map merge routine */ 272 i = 8; 273 do 274 { 275 if (*(UWORD *)dp) 276 { 277 if (*(UWORD *)fp) 278 { 279 if (*(UWORD *)dp != *(UWORD *)fp) goto badmerge; 280 } 281 else *(UWORD *)fp = *(UWORD *)dp; 282 } 283 else *(UWORD *)dp = *(UWORD *)fp; 284 (UWORD *)fp += 1; 285 (UWORD *)dp += 1; 286 i -= 1; 287 } while (i); 288 } 289 /* Disk map merging complete */ 290 fcb_ext = calcext(fcbp); /* calc max extent for fcb */ 291 dir_ext = (UWORD)(dirp->extent) & 0x1f; 292 if ( (fcb_ext > dir_ext) || 293 ((fcb_ext == dir_ext) && 294 (UBWORD(fcbp->rcdcnt) > UBWORD(dirp->rcdcnt))) ) 295 /* if fcb points to larger file than dirp */ 1File: FILEIO.C Page 6 296 { 297 dirp->rcdcnt = fcbp->rcdcnt; /* set up rc, ext from fcb */ 298 dirp->extent = (BYTE)fcb_ext; 299 } 300 dirp->s1 = fcbp->s1; 301 if ( (dirp->ftype[robit]) & 0x80) ro_err(fcbp,dirindx); 302 /* read-only file error */ 303 dirp->ftype[arbit] &= 0x7f; /* clear archive bit */ 304 dir_wr(dirindx >> 2); 305 UNLOCK 306 return(TRUE); 307 308 badmerge: 309 UNLOCK 310 ro_dsk |= (1 << GBL.curdsk); 311 return(FALSE); 312 } 313 else return(FALSE); 314 } 315 316 317 /************************ 318 * close_fi entry point * 319 ************************/ 320 321 UWORD close_fi(fcbp) 322 323 struct fcb *fcbp; /* pointer to fcb for file to close */ 324 { 325 flushit(); /* first, flush the buffers */ 326 if ((fcbp->s2) & 0x80) return(0); /* if file write flag not on, 327 don't need to do physical close */ 328 return( dirscan(close, fcbp, 0)); /* call dirscan with close function */ 329 } 330 331 332 /************************ 333 * search entry point * 334 ************************/ 335 336 /* First two functions for dirscan */ 337 338 BOOLEAN alltrue(p1, p2, i) 339 UBYTE *p1; 340 UBYTE *p2; 341 WORD i; 342 { 343 return(TRUE); 344 } 345 346 BOOLEAN matchit(p1, p2, i) 347 UBYTE *p1; 348 UBYTE *p2; 349 WORD i; 350 { 351 return(match(p1, p2, TRUE)); 352 } 353 354 1File: FILEIO.C Page 7 355 /* search entry point */ 356 UWORD search(fcbp, dsparm, p) 357 358 REG struct fcb *fcbp; /* pointer to fcb for file to search */ 359 REG UWORD dsparm; /* parameter to pass through to dirscan */ 360 UBYTE *p; /* pointer to pass through to tmp_sel */ 361 362 { 363 REG UWORD rtn; /* return value */ 364 BSETUP 365 366 if (fcbp->drvcode == '?') 367 { 368 seldsk(GBL.dfltdsk); 369 rtn = dirscan(alltrue, fcbp, dsparm); 370 } 371 else 372 { 373 tmp_sel(p); /* temporarily select disk */ 374 if (fcbp->extent != '?') fcbp->extent = 0; 375 fcbp->s2 = 0; 376 rtn = dirscan(matchit, fcbp, dsparm); 377 } 378 move( GBL.dirbufp, GBL.dmaadr, SECLEN); 379 return(rtn); 380 } 381 382 383 /************************ 384 * create entry point * 385 ************************/ 386 387 BOOLEAN create(fcbp, dirp, dirindx) 388 389 REG struct fcb *fcbp; /* pointer to fcb for file to create */ 390 REG struct dirent *dirp; /* pointer to directory entry */ 391 REG WORD dirindx; /* index into directory */ 392 393 { 394 REG BYTE *p; 395 REG WORD i; 396 REG BOOLEAN rtn; 397 BSETUP 398 399 if ( rtn = ((dirp->entry) == 0xe5) ) 400 { 401 p = &(fcbp->rcdcnt); 402 i = 17; 403 do 404 { /* clear fcb rcdcnt and disk map */ 405 *p++ = 0; 406 i -= 1; 407 } while (i); 408 move(fcbp, dirp, sizeof *dirp); /* move the fcb to the directory */ 409 dir_wr(dirindx >> 2); /* write the directory sector */ 410 if ( dirindx > (GBL.dphp)->hiwater ) 411 (GBL.dphp)->hiwater = dirindx; 412 crit_dsk |= 1 << (GBL.curdsk); 413 } 1File: FILEIO.C Page 8 414 return(rtn); 415 } 416 417 418 /************************ 419 * delete entry point * 420 ************************/ 421 422 BOOLEAN delete(fcbp, dirp, dirindx) 423 424 REG struct fcb *fcbp; /* pointer to fcb for file to delete */ 425 REG struct dirent *dirp; /* pointer to directory entry */ 426 REG WORD dirindx; /* index into directory */ 427 428 { 429 REG WORD i; 430 REG BOOLEAN rtn; 431 BSETUP 432 433 if ( rtn = match(fcbp, dirp, FALSE) ) 434 { 435 if ( (dirp->ftype[robit]) & 0x80 ) ro_err(fcbp,dirindx); 436 /* check for read-only file */ 437 dirp->entry = 0xe5; 438 LOCK 439 dir_wr(dirindx >> 2); 440 /* Now free up the space in the allocation vector */ 441 if ((GBL.parmp)->dsm < 256) 442 { 443 i = 16; 444 do clraloc(UBWORD(dirp->dskmap.small[--i])); 445 while (i); 446 } 447 else 448 { 449 i = 8; 450 do clraloc(swap(dirp->dskmap.big[--i])); 451 while (i); 452 } 453 UNLOCK 454 } 455 return(rtn); 456 } 457 458 459 /************************ 460 * rename entry point * 461 ************************/ 462 463 BOOLEAN rename(fcbp, dirp, dirindx) 464 465 REG struct fcb *fcbp; /* pointer to fcb for file to delete */ 466 REG struct dirent *dirp; /* pointer to directory entry */ 467 REG WORD dirindx; /* index into directory */ 468 469 { 470 REG UWORD i; 471 REG BYTE *p; /* general purpose pointers */ 472 REG BYTE *q; 1File: FILEIO.C Page 9 473 REG BOOLEAN rtn; 474 BSETUP 475 476 if ( rtn = match(fcbp, dirp, FALSE) ) 477 { 478 if ( (dirp->ftype[robit]) & 0x80 ) ro_err(fcbp,dirindx); 479 /* check for read-only file */ 480 p = &(fcbp->dskmap.small[1]); 481 q = &(dirp->fname[0]); 482 i = 11; 483 do 484 { 485 *q++ = *p++ & 0x7f; 486 i -= 1; 487 } while (i); 488 dir_wr(dirindx >> 2); 489 } 490 return(rtn); 491 } 492 493 494 /************************ 495 * set_attr entry point * 496 ************************/ 497 498 BOOLEAN set_attr(fcbp, dirp, dirindx) 499 500 REG struct fcb *fcbp; /* pointer to fcb for file to delete */ 501 REG struct dirent *dirp; /* pointer to directory entry */ 502 REG WORD dirindx; /* index into directory */ 503 504 { 505 REG BOOLEAN rtn; 506 BSETUP 507 508 if ( rtn = match(fcbp, dirp, FALSE) ) 509 { 510 move(&fcbp->fname[0], &dirp->fname[0], 11); 511 dir_wr(dirindx >> 2); 512 } 513 return(rtn); 514 } 515 516 517 /**************************** 518 * utility routine used by * 519 * setran and getsize * 520 ****************************/ 521 522 LONG extsize(fcbp) 523 /* Return size of extent pointed to by fcbp */ 524 REG struct fcb *fcbp; 525 526 { 527 return( ((LONG)(fcbp->extent & 0x1f) << 7) 528 | ((LONG)(fcbp->s2 & 0x3f) << 12) ); 529 } 530 531 1File: FILEIO.C Page 10 532 /************************ 533 * setran entry point * 534 ************************/ 535 536 setran(fcbp) 537 538 REG struct fcb *fcbp; /* pointer to fcb for file to set ran rec */ 539 540 { 541 struct 542 { 543 BYTE b3; 544 BYTE b2; 545 BYTE b1; 546 BYTE b0; 547 }; 548 LONG random; 549 550 random = (LONG)UBWORD(fcbp->cur_rec) + extsize(fcbp); 551 /* compute random record field */ 552 fcbp->ran0 = random.b2; 553 fcbp->ran1 = random.b1; 554 fcbp->ran2 = random.b0; 555 } 556 557 558 /**********************************/ 559 /* fsize is a funtion for dirscan */ 560 /* passed from getsize */ 561 /**********************************/ 562 563 BOOLEAN fsize(fcbp, dirp, dirindx) 564 565 REG struct fcb *fcbp; /* pointer to fcb for file to delete */ 566 REG struct dirent *dirp; /* pointer to directory entry */ 567 WORD dirindx; /* index into directory */ 568 569 { 570 REG BOOLEAN rtn; 571 struct 572 { 573 BYTE b3; 574 BYTE b2; 575 BYTE b1; 576 BYTE b0; 577 }; 578 LONG temp; 579 580 if ( rtn = match(fcbp, dirp, FALSE) ) 581 { 582 temp = (LONG)UBWORD(dirp->rcdcnt) + extsize(dirp); 583 /* compute file size */ 584 fcbp->ran0 = temp.b2; 585 fcbp->ran1 = temp.b1; 586 fcbp->ran2 = temp.b0; 587 } 588 return(rtn); 589 } 590 1File: FILEIO.C Page 11 591 /************************ 592 * getsize entry point * 593 ************************/ 594 595 getsize(fcbp) 596 /* get file size */ 597 REG struct fcb *fcbp; /* pointer to fcb to get file size for */ 598 599 { 600 LONG maxrcd; 601 LONG temp; 602 REG WORD dsparm; 603 struct 604 { 605 BYTE b3; 606 BYTE b2; 607 BYTE b1; 608 BYTE b0; 609 }; 610 611 maxrcd = 0; 612 dsparm = 0; 613 temp = 0; 614 while ( dirscan(fsize, fcbp, dsparm) < 255 ) 615 { /* loop until no more matches */ 616 temp.b2 = fcbp->ran0; 617 temp.b1 = fcbp->ran1; 618 temp.b0 = fcbp->ran2; 619 if (temp > maxrcd) maxrcd = temp; 620 dsparm = 1; 621 } 622 fcbp->ran0 = maxrcd.b2; 623 fcbp->ran1 = maxrcd.b1; 624 fcbp->ran2 = maxrcd.b0; 625 } 626 627 628 /************************ 629 * free_sp entry point * 630 ************************/ 631 632 free_sp(dsknum) 633 634 UBYTE dsknum; /* disk number to get free space of */ 635 { 636 REG LONG records; 637 REG UWORD *alvec; 638 REG UWORD bitmask; 639 REG UWORD alvword; 640 REG WORD i; 641 BSETUP 642 643 seldsk(dsknum); /* select the disk */ 644 records = (LONG)0; /* initialize the variables */ 645 alvec = (GBL.dphp)->alv; 646 bitmask = 0; 647 for (i = 0; i <= (GBL.parmp)->dsm; i++) /* for loop to compute */ 648 { 649 if ( ! bitmask) 1File: FILEIO.C Page 12 650 { 651 bitmask = 0x8000; 652 alvword = ~(*alvec++); 653 } 654 if ( alvword & bitmask) 655 records += (LONG)( ((GBL.parmp)->blm) + 1 ); 656 bitmask >>= 1; 657 } 658 *(LONG *)GBL.dmaadr = records; /* move # records to DMA address */ 659 }