home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / HDX_BACK / HDX302.TT / SECT.C < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-09  |  16.4 KB  |  694 lines

  1. /* sect.c */
  2.  
  3. /* 
  4.  * Aug-12-89 jye. Change and add codes so that can be used for MS-DOS
  5.  * Dec-22-89 jye. Fixed a bug that HDX return a error message in the
  6.  *                  partitioning dialog box when the CD-ROM is busy.
  7.  *                  The correction is in rescan().
  8.  */
  9.  
  10. #include "obdefs.h"
  11. #include "osbind.h"
  12. #include "defs.h"
  13. #include "part.h"
  14. #include "hdx.h"
  15. #include "addr.h"
  16. #include "error.h"
  17.  
  18. #define    ZBUFSIZ    0x4000        /* about 16k == 32 sectors */
  19. #define    ZCOUNT    (ZBUFSIZ/0x200)    /* ZCOUNT = 32 */
  20. #define MAXUNITS 16            /* max number of logical units */
  21.  
  22. #define PUNINFO struct _punifno
  23. PUNINFO {
  24.         WORD puns;    /* number of physical units */
  25.         BYTE pun[MAXUNITS];
  26.         LONG partition_start[MAXUNITS]; /* offset to partition on */
  27.                                         /* physical unit */
  28. };
  29. extern long ostack;        /* old stack pointer */
  30. extern UWORD errcode();        /* function to return error code */
  31. extern int yesscan;        /* the flag for the func. IBMGPART use */
  32. extern long sptrk;        /* the sector per track */
  33. extern int npart;        /* the number of partitions */
  34. extern int ext;            /* the index of extended partition */
  35. extern int extend;        /* the index of end extended partition */
  36. extern int showmany;    /* the flag for show the too many device alert box */
  37.  
  38.  
  39. /*
  40.  * Logical-to-dev+partition mapping table.
  41.  */
  42. int nlogdevs;            /* # logical devices */
  43. LOGMAP logmap[EXTRALOGD];    /* logical dev map */
  44. int livedevs[MAXPHYSDEVS];    /* live devs flags; 1: device is alive */
  45. char typedev = 0x00;        /* if the bit set, that bit is mean that */
  46.                             /* driver is a removable driver */
  47.  
  48.  
  49. /*
  50.  * Rebuild logical-to-physical mapping
  51.  * by reading and interpreting the root
  52.  * blocks for all physical devs.
  53.  *
  54.  */
  55.  
  56. rescan(flag, znm)
  57.  
  58. int flag;    /* 0: don't report medium change error; */
  59.             /* non-0: report medium change error; */
  60. int znm;    /* 1: do zero & markbad; 0: do partition & format */
  61.  
  62. {
  63.     int dev, scan=0;
  64.     char buf[512];
  65.     char sendata[16];
  66.     int partno, ret, inqret, i;
  67.     PART *partinfo;
  68.     char mask = 0x80;    /* 7th bit is set on */
  69.     char setmask;
  70.  
  71.     /* disable all logical and physical devs */
  72.     for (dev = 0; dev < EXTRALOGD; ++dev)
  73.     logmap[dev].lm_physdev = -1;
  74.  
  75.     for (dev = 0; dev < MAXPHYSDEVS; ++dev)
  76.     livedevs[dev] = 0;
  77.  
  78.     /*
  79.      * Scan all physical devs
  80.      * and pick up partition structures.
  81.      */
  82.     nlogdevs = 0;
  83.     showmany = 0;
  84.     for (dev = 0; dev < MAXPHYSDEVS; ++dev)
  85.     {
  86.         /* initialize the buffer */
  87.         for (i = 0; i < 16; i++)        {
  88.             sendata[i] = 0;
  89.         }
  90.  
  91.         /* check see the drive is a what kind of drive */
  92.            ostack = Super(NULL);
  93.         inqret = inquiry(dev, sendata);
  94.            delay();
  95.            Super(ostack);
  96.         if (inqret & 0x08)    {    /* the device is busy */
  97.             continue;
  98.         }
  99.         /* ret not = ok, it may be a regular hard drive */
  100.         if (inqret == OK)    { /* it is not a regular hard drive */
  101.             if (sendata[0])    {     /* it is not a hard drive */
  102.                 continue;
  103.             }
  104.         }
  105.         setmask = 0x01;
  106.         if ((ret = getroot(dev, buf, (SECTOR)0)) < 0) {
  107.             if (znm)  rangelog(dev);
  108.             continue;
  109.         } else {        /* ret >= 0 */
  110.             if (ret > 0) {
  111.                 if (flag) {    /* if non-0, report error if medium changed */
  112.                     if (tsterr(ret) == OK)
  113.                         return ERROR;
  114.                 }
  115.                 if ((ret = getroot(dev, buf, (SECTOR)0))) {    /* try again */
  116.                     if (ret > 0 && flag && tsterr(ret) == OK)    {
  117.                         return ERROR;
  118.                     } else if ((ret > 0) && (!flag))    {
  119.                         if ((inqret == OK) && (sendata[1] & mask))    { 
  120.                             /* it is a removable drive */
  121.                             /* but forget insert the cartridge */
  122.                             err(instdrv);
  123.                             return ERROR;
  124.                         }
  125.                     }
  126.                     if (znm)    {
  127.                         rangelog(dev);
  128.                     }
  129.                     continue;
  130.                 }
  131.             }
  132.  
  133.             if ((inqret == OK) && (sendata[1] & mask))    { 
  134.                 /* it is a removable drive */
  135.                 /* set the relative bit, */ 
  136.                 /* 1 is a removable, other is not */
  137.                 typedev |= setmask << dev;
  138.             }
  139.             livedevs[dev] = 1;
  140.             yesscan = 1;
  141.             if (stgpart(dev, buf, (PART *)&partinfo) == ERROR)    {
  142.                 return ERROR;
  143.             }
  144.             if (ext != NO_EXT)    {
  145.                 sortpart(partinfo,SCAN_BS); 
  146.             }
  147.         for (partno = 0; partno < npart; ++partno) {
  148.             if ((partinfo[partno].p_flg & P_EXISTS) &&
  149.                 (partinfo[partno].p_siz != (SECTOR)0) &&
  150.                 (((partinfo[partno].p_id[0] == 'G') &&
  151.                  (partinfo[partno].p_id[1] == 'E') &&
  152.                  (partinfo[partno].p_id[2] == 'M'))   ||
  153.                  ((partinfo[partno].p_id[0] == 'B') &&
  154.                  (partinfo[partno].p_id[1] == 'G') &&
  155.                  (partinfo[partno].p_id[2] == 'M'))))   
  156.             {
  157.                 if (nlogdevs > EXTRALOGD)    {
  158.                     continue;
  159.                 }
  160.                 logmap[nlogdevs].lm_physdev = dev;
  161.                 logmap[nlogdevs].lm_partno = partno;
  162.                 logmap[nlogdevs].lm_start =  partinfo[partno].p_st;
  163.                 logmap[nlogdevs].lm_siz =      partinfo[partno].p_siz;
  164.                 ++nlogdevs;
  165.                 if (nlogdevs == MAXLOGDEVS)         {
  166.                     showmany = 1;
  167.                 }
  168.             }
  169.         }
  170.     }
  171.     inipart(partinfo, npart);
  172.     if (partinfo > 0)    Mfree(partinfo);
  173.     }
  174.     return OK;
  175. }
  176.  
  177. /* rerange the partition informations. */
  178.  
  179.  sortpart(pinfo, type)
  180.  PART *pinfo;
  181.  int type;                /* USER_ED = 1: for user interface use */
  182.                          /* SCAN_BS = 0: for rescan() and laybs() use */
  183.  {
  184.      int i, j, k;
  185.     PART rpart[2];
  186.  
  187.     if (ext == NO_EXT) return OK;    /* don't need sort */
  188.     for (i = 0; i < 2; i++)    { /* initialize the temple space */
  189.         rpart[i].p_flg = 0L;
  190.         rpart[i].p_st = 0L;
  191.         rpart[i].p_siz = 0L;
  192.         for (k = 0; k < 3; k++)
  193.             rpart[i].p_id[k] = '0';
  194.     }
  195.     /* save the partitions that after the extened partitions */
  196.     for (i = ext+1, j=0; i < 4; i++, j++)        {
  197.         if (pinfo[i].p_flg & P_EXISTS)    {
  198.             rpart[j].p_flg = P_EXISTS;
  199.             rpart[j].p_st = pinfo[i].p_st;
  200.             rpart[j].p_siz = pinfo[i].p_siz;
  201.             for (k = 0; k < 3; k++)
  202.                 rpart[j].p_id[k] = pinfo[i].p_id[k];
  203.         } 
  204.     }
  205.     /* move the extened partition to the frant */
  206.      for (i=4, j = ext; i < npart; i++, j++)    {
  207.         if (pinfo[i].p_flg & P_EXISTS)    {
  208.             pinfo[j].p_flg = P_EXISTS;
  209.             pinfo[j].p_st = (type)?(pinfo[i].p_st):(pinfo[i].p_st + ROOTSECT);
  210.             pinfo[j].p_siz = (type)?(pinfo[i].p_siz):(pinfo[i].p_siz-ROOTSECT);
  211.             for (k = 0; k < 3; k++)
  212.                 pinfo[j].p_id[k] = pinfo[i].p_id[k];
  213.         } else { j--;}    /* stay with that space */
  214.     }
  215.     /* copy the not extended partitions back after the extended partitions */
  216.      for (i=0; i < 2; i++, j++)    {
  217.         if (rpart[i].p_flg & P_EXISTS)    {
  218.             pinfo[j].p_flg = P_EXISTS;
  219.             pinfo[j].p_st = rpart[i].p_st;
  220.             pinfo[j].p_siz = rpart[i].p_siz;
  221.             for (k = 0; k < 3; k++)
  222.                 pinfo[j].p_id[k] = rpart[i].p_id[k];
  223.         } else {j--;}
  224.     }
  225.     for (i = j; i < npart; i++)    { /* set the rest to 0 */
  226.         pinfo[i].p_flg = 0L;
  227.         pinfo[i].p_st = 0L;
  228.         pinfo[i].p_siz = 0L;
  229.         for (k = 0; k < 3; k++)
  230.             pinfo[i].p_id[k] = '0';
  231.     }
  232. }
  233.  
  234.  
  235. /* 
  236.  * check to find out the exist of device
  237.  */
  238.  
  239. rangelog(dev)
  240.  
  241. int dev;
  242.  
  243. {
  244.     PUNINFO *divinfo;
  245.     int devnum;
  246.  
  247.     ostack = Super(NULL);
  248.     divinfo = ((PUNINFO *) *((long *)(0x516)));
  249.     for (devnum = 0; devnum < MAXUNITS; ++devnum)    {
  250.         if ((int)(divinfo->pun[devnum] & 0x07) == dev)    {
  251.             delay();
  252.             nlogdevs++;
  253.         }
  254.     }
  255.     Super(ostack);
  256. }
  257.  
  258. /*
  259.  * From a PHYSICAL device unit (0->7)
  260.  * and a partition number (0->3), figure
  261.  * out the LOGICAL disk number ('C'->'P').
  262.  *
  263.  * return the LOGICAL disk number or
  264.  * ERROR if the PHYSICAL device doesn't exist.
  265.  *
  266.  */
  267. phys2log(pdev, pno)
  268. int  pdev;    /* physical device unit */
  269. int  pno;    /* partition number (0 -> 3) */
  270. {
  271.     int logdev;        /* index to step through partitions of a phys unit */
  272.  
  273.     for (logdev = 0; logdev < EXTRALOGD; logdev++) {
  274.         if (logmap[logdev].lm_physdev == pdev &&
  275.             logmap[logdev].lm_partno == pno)
  276.             return ('C'+logdev);
  277.     }
  278.     return ERROR;
  279. }
  280.  
  281.  
  282. /*
  283.  * Map block on logical device to
  284.  * block on physical device;
  285.  * return ERROR if the logical device
  286.  * doesn't exist.
  287.  */
  288. log2phys(adev, ablk)
  289. int *adev;
  290. SECTOR *ablk;
  291. {
  292.     int dev;
  293.     char xbuf[256];
  294.     
  295.     dev = *adev;
  296.     if (dev >= 0 && dev <= 7)
  297.     return OK;
  298.  
  299.     dev = toupper(dev);
  300.     if (dev >= 'C' && dev <= 
  301.                 ('C'+EXTRALOGD)) /* from C to 't' are 50 logic device */
  302.     {
  303.     dev -= 'C';
  304.     *adev = logmap[dev].lm_physdev;
  305.     *ablk = logmap[dev].lm_start + *ablk;
  306.     return OK;
  307.     }
  308.  
  309.     return ERROR;
  310. }
  311.  
  312.  
  313.  
  314. /*
  315.  * Return physical starting block# of a partition
  316.  *
  317.  */
  318. SECTOR 
  319. logstart(ldev)
  320. int ldev;    /* logical device */
  321. {
  322.     ldev = toupper(ldev);
  323.     if (ldev >= 'C' && ldev <= 
  324.                 ('C'+EXTRALOGD)){/*from C to 't' are 50 logic device */
  325.         ldev -= 'C';
  326.         return (logmap[ldev].lm_start);
  327.     }
  328.     return ERROR;
  329. }
  330.  
  331.  
  332.  
  333. /*
  334.  * Return physical starting block# of a partition's data block.
  335.  *
  336.  */
  337. SECTOR 
  338. logend(ldev)
  339. int ldev;    /* logical device */
  340. {
  341.     ldev = toupper(ldev);
  342.     if (ldev >= 'C' && ldev <= 
  343.                 ('C'+EXTRALOGD)){/*from C to 't' are 50 logic device */
  344.         ldev -= 'C';
  345.         return (logmap[ldev].lm_start+logmap[ldev].lm_siz-1);
  346.     }
  347.     return ERROR;
  348. }
  349.  
  350.  
  351. #define    MFM 17        /* sectors per track for MFM */
  352. #define    RLL 26        /* sectors per track for RLL */
  353.  
  354.  
  355. /*
  356.  * Check if dev's root block is intact.
  357.  * Return number of sectors per track on disk.
  358.  *
  359.  */
  360. chkroot(dev, bs)
  361. int dev;
  362. char *bs;
  363. {
  364.     extern long get3bytes();
  365.     SETMODE *mb;
  366.     int i, ret;
  367.     int cyl, head;
  368.     SECTOR size, msiz;    /* size of media */
  369.     char buf[512], sendata[16];
  370.     long dmaptr, tmpptr;
  371.     char *dmahigh=0xffff8609,
  372.          *dmamid=0xffff860b,
  373.          *dmalow=0xffff860d;
  374.     
  375.     size = ((RSECT *)(bs + 0x200 - sizeof(RSECT)))->hd_siz;
  376.     
  377.     ostack = Super(NULL);
  378.     
  379.     /* Get format parameters/ disk size from media */
  380.     ret = md_sense(dev, sendata);
  381.     delay();
  382.     Super(ostack);
  383.     
  384.     if (ret != 0) {
  385.         ret = errcode(dev);
  386.         if (tsterr(ret) != OK) 
  387.             return ERROR;
  388.         return (-3);    /* don't have to show the alert box */
  389.     }
  390.     
  391.     /* check what kind of sense data it returned  */
  392.     /* If full SCSI, will return number of blocks */
  393.     /* on disk at byte 5, 6 and 7.  If Adaptec,   */
  394.     /* will return 0 for number of blocks on disk */
  395.     /* on SCSI. */
  396.     
  397.     if (!(msiz = get3bytes(sendata+5))) {    /* no disk size returned? */
  398.         /* Yup, ie., it's adaptec's.  Interpret as SETMODE structure */
  399.         mb = (SETMODE *)sendata;
  400.     /* get number of cylinders */
  401.     cyl = mb->smd_cc[0];
  402.     cyl <<= 8;
  403.     cyl |= mb->smd_cc[1];
  404.     
  405.     /* get number of heads */
  406.     head = mb->smd_dhc;
  407.     
  408.     msiz = (SECTOR)head * (SECTOR)cyl * MFM;
  409.     
  410.     for (i = 0; i < 20; i++) {
  411.         if ((ret = rdsects(dev, 1, buf, msiz+i)) == OK) {
  412.         
  413.         /* find out whether data has been transferred, by
  414.               checking if dma pointer has been moved.      */
  415.  
  416.            ostack = Super(NULL);    /* get into Supervisor mode */
  417.            
  418.         dmaptr = *dmahigh;
  419.         dmaptr &= 0x0000003f;
  420.         dmaptr <<= 16;
  421.         tmpptr = *dmamid;
  422.         tmpptr &= 0x000000ff;
  423.         tmpptr <<= 8;
  424.         dmaptr |= tmpptr;
  425.         tmpptr = *dmalow;
  426.         tmpptr &= 0x000000ff;
  427.         dmaptr |= tmpptr;
  428.         
  429.             delay();
  430.             Super(ostack);        /* back to user mode */
  431.             
  432.         if (dmaptr != buf)
  433.             break;
  434.         } else {            /* rdsects return an error */
  435.         if (tsterr(ret) == OK) {
  436.                 break;
  437.         }
  438.             }
  439.         }
  440.     
  441.     if (ret == MDMCHGD)        /* check if error occurred */
  442.         return (ret);
  443.        
  444.     /* Determine if media is MFM or RLL */
  445.     if (i < 20)
  446.         msiz = (SECTOR)head * (SECTOR)cyl * RLL;
  447.     }
  448.         
  449.     if (size != msiz)
  450.         ret = ERROR;
  451.     else 
  452.         ret = OK;
  453.         
  454.     return (ret);
  455. }
  456.  
  457.  
  458. /*
  459.  * Chkparm()
  460.  *    Check if given logical device has the asssumed parameters.
  461.  * Assumptions are:
  462.  *    - 512 bytes/sector
  463.  *    - 2 sectors/cluster
  464.  *    - 1 reserved sector
  465.  *    - 2 FATs
  466.  *
  467.  * Input:
  468.  *    ldev - logical device number ('C' -> 'P').
  469.  *
  470.  * Return:
  471.  *    OK - parameters of partition match the assumptions
  472.  *    ERROR - something went wrong.
  473.  *
  474.  * Comment:
  475.  *    Number of FATs is assumed to be 2.  Cannot check this 
  476.  * because previous version of HDX did not put that in the boot
  477.  * sector.
  478.  */
  479. chkparm(ldev)
  480. int ldev;
  481. {
  482.     char bs[512];        /* boot sector */
  483.     BOOT *boot;            /* boot structure */
  484.     UWORD bps, res, siz;    /* bytes/sector, num reserved sectors, ldev size */
  485.     int ret;
  486.  
  487.     if ((ret = rdsects(ldev, 1, bs, (SECTOR)0)) != 0) {
  488.         if (tsterr(ret) != OK)
  489.             err(bootread);
  490.         ret = ERROR;
  491.         goto parmend;
  492.     }    
  493.  
  494.     boot = (BOOT *)bs;
  495.     gw((UWORD *)&boot->b_bps, &bps);    /* what is number bytes/sector? */
  496.     gw((UWORD *)&boot->b_res, &res);    /* what is num of reserved sectors? */
  497.     gw((UWORD *)&boot->b_nsects, &siz);    /* what is size of partition */
  498.     if (bps % BPS            /* bytes per sector == ratio of 512 ? */
  499.     || res != 1) {            /* num sectors reserved == 1 ? */
  500.     ret = ERROR;            /* Nope, different from assumptions */
  501.     goto parmend;
  502.     }
  503.     
  504.     /* Check if sectors per cluster make sense */
  505.     if (boot->b_spc != 2) {
  506.         ret = ERROR;
  507.         goto parmend;
  508.     }
  509.     
  510.     ret = OK;                /* If yes, return OK */
  511.  
  512. parmend:
  513.     return ret;
  514. }
  515.  
  516.  
  517. ichkparm(ldev)
  518. int ldev;
  519. {
  520.     char bs[512];        /* boot sector */
  521.     BOOT *boot;            /* boot structure */
  522.     UWORD bps, res, siz;    /* bytes/sector, num reserved sectors, ldev size */
  523.     int ret;
  524.  
  525.     if ((ret = rdsects(ldev, 1, bs, (SECTOR)0)) != 0) {
  526.         if (tsterr(ret) != OK)
  527.             err(bootread);
  528.         ret = ERROR;
  529.         goto parmend;
  530.     }    
  531.  
  532.     boot = (BOOT *)bs;
  533.     gw((UWORD *)&boot->b_bps, &bps);    /* what is number bytes/sector? */
  534.     gw((UWORD *)&boot->b_res, &res);    /* what is num of reserved sectors? */
  535.     gw((UWORD *)&boot->b_nsects, &siz);    /* what is size of partition */
  536.     if (bps != 512            /* bytes per sector == 512 ? */
  537.     || res != 1) {            /* num sectors reserved == 1 ? */
  538.     ret = ERROR;            /* Nope, different from assumptions */
  539.     goto parmend;
  540.     }
  541.     
  542.     /* Check if sectors per cluster make sense */
  543.     if ((siz >= 0x8000L && boot->b_spc != 4) ||
  544.         (siz < 0x8000L && boot->b_spc != 2)) {
  545.         ret = ERROR;
  546.         goto parmend;
  547.     }
  548.     
  549.     ret = OK;                /* If yes, return OK */
  550.  
  551. parmend:
  552.     return ret;
  553. }
  554.  
  555.  
  556. /*
  557.  * Get dev's root block.
  558.  *
  559.  */
  560. getroot(dev, buf, sect)
  561. int dev;
  562. char *buf;
  563. SECTOR sect;
  564. {
  565.     return rdsects(dev, 1, buf, sect);
  566. }
  567.  
  568.  
  569. /*
  570.  * Put dev's root block.
  571.  *
  572.  */
  573. putroot(dev, buf, sect)
  574. int dev;
  575. char *buf;
  576. SECTOR sect;
  577. {
  578.     return wrsects(dev, 1, buf, sect);
  579. }
  580.  
  581.  
  582. /*
  583.  *  Read sector(s) from dev.
  584.  *
  585.  *  Input:
  586.  *    dev - device number (logical or physical).
  587.  *    num - number of sectors to read.
  588.  *    buf - buffer to write data read.
  589.  *    sect - starting sector number to read from.
  590.  *
  591.  *  Return:
  592.  *    errnum - 0: if read is successful.
  593.  *         an error code: if read is unsuccessful.
  594.  */
  595. rdsects(dev, num, buf, sect)
  596. int dev;            /* device number (logical or physical) */
  597. UWORD num;            /* number of sectors to read */
  598. char *buf;
  599. SECTOR sect;            /* starting sector to read from */
  600. {
  601.     int errnum;
  602.  
  603.     if (log2phys(&dev, §) < 0)
  604.     return ERROR;
  605.  
  606.     ostack = Super(NULL);
  607.     errnum = hread(sect, num, buf, (UWORD)dev);
  608.     delay();
  609.     Super(ostack);
  610.  
  611.     if (errnum > 0) {
  612.         errnum = errcode(dev);
  613.     }
  614.         
  615.     return errnum;        /* return the error code */
  616. }
  617.  
  618.  
  619. /*
  620.  *  Write sector(s) to dev.
  621.  *
  622.  *  Input:
  623.  *    dev - device number (logical or physical).
  624.  *    num - number of sectors to write.
  625.  *    buf - buffer with data to be written.
  626.  *    sect - starting sector number to write to.
  627.  *
  628.  *  Return:
  629.  *    errnum - 0: if write is successful.
  630.  *         an error code: if write is unsuccessful.
  631.  */
  632. wrsects(dev, num, buf, sect)
  633. int dev;            /* device number (logical or physical */
  634. UWORD num;            /* number of sectors to write */
  635. char *buf;            /* buffer with data to be written */
  636. SECTOR sect;            /* starting sector to write to */
  637. {
  638.     int errnum;
  639.  
  640.     if (log2phys(&dev, §) < 0)
  641.     return ERROR;
  642.  
  643.     ostack = Super(NULL);
  644.     errnum = hwrite(sect, num, buf, (UWORD)dev);
  645.     delay();
  646.     Super(ostack);
  647.  
  648.     if (errnum > 0) {
  649.         errnum = errcode(dev);
  650.     }
  651.  
  652.     return errnum;
  653. }
  654.  
  655.  
  656. /*
  657.  * Zero range of sectors on dev.
  658.  *
  659.  */
  660. zerosect(dev, start, count)
  661. int dev;
  662. SECTOR start;
  663. UWORD count;
  664. {
  665.     char *zbuf;
  666.     int  v;
  667.     UWORD i;
  668.  
  669.     if ((zbuf = (char *)mymalloc(ZBUFSIZ)) <= 0)
  670.         return err(nomemory);
  671.         
  672.     if (log2phys(&dev, &start) < 0) {
  673.         free(zbuf);
  674.     return ERROR;
  675.     }
  676.  
  677.     fillbuf(zbuf, (long)ZBUFSIZ, 0L);
  678.  
  679.     while (count)
  680.     {
  681.         if (count > ZCOUNT)
  682.             i = ZCOUNT;
  683.         else i = count;
  684.  
  685.     if ((v = wrsects(dev, i, zbuf, start)) != 0)
  686.         break;
  687.     start += i;
  688.     count -= i;
  689.     }
  690.     free(zbuf);
  691.     
  692.     return v;
  693. }
  694.