home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / alt_os / mint / mfs6011 / source / minixfs / zone.c < prev   
C/C++ Source or Header  |  1994-12-30  |  19KB  |  725 lines

  1. /* This file is part of 'minixfs' Copyright 1991,1992,1993 S.N. Henson */
  2.  
  3. #include "minixfs.h"
  4. #include "proto.h"
  5. #include "global.h"
  6.  
  7. int read_zone(num,buf,drive,control)
  8. long num ;
  9. void *buf;
  10. int drive;
  11. cache_control *control;
  12. {
  13.     if(num) bcopy(cget_block(num,drive,control),buf,(size_t)BLOCK_SIZE);
  14.     else bzero(buf,(size_t)BLOCK_SIZE);
  15.     return(0);
  16. }
  17.  
  18. /* Only ever used for directories so always syscache */
  19. bufr *get_zone(num,drive)
  20. long num ;
  21. int drive;
  22. {
  23.     return(cget_block(num,drive,&syscache));
  24. }
  25.  
  26. /* Zone cache stuff (same as cache stuff but with checking) */
  27. cache *cget_zone(num,drive,control,guess)
  28. long num;
  29. int drive;
  30. cache_control *control;
  31. cache **guess;
  32. {
  33.     return (cache_get(num,drive,control,guess));
  34. }
  35.  
  36. cache *cput_zone(num,drive,control)
  37. long num;
  38. int drive;
  39. cache_control *control;
  40. {
  41.     return (cache_put(num,drive,control));
  42. }
  43.  
  44. int write_zone(num,buf,drive,control)
  45. long num ;
  46. void *buf;
  47. int drive;
  48. cache_control *control;
  49. {
  50.     cput_block(num,drive,buf,control);
  51.     return(0);
  52. }
  53.  
  54. /* This is a 'clever' write_zone which recognises consecutive blocks and
  55.  * queues requests until it gets one out of sequence.This allows large
  56.  * i/o requests to be done with a single Rwabs for consecutive blocks
  57.  * which is much faster than lots of little ones.
  58.  */
  59.  
  60. int write_zones(num,buf,drive,control)
  61. long num;
  62. void *buf;
  63. int drive;
  64. cache_control *control;
  65. {
  66.     static void *qstart,*qnext;
  67.     static long nstart,nnext,count;
  68.     static short qdrive=-1;
  69.     cache *p;
  70.     int i;
  71.  
  72.     if(drive != -1 && (p=in_cache(num,drive,control,NOGUESS)) )
  73.     {
  74.         bcopy(buf,p->buffer,(size_t)BLOCK_SIZE);
  75.         p->status=1;
  76.     }
  77.  
  78.     if(buf!=qnext || nnext!=num || qdrive!=drive || count > MAX_RWS )
  79.     {
  80.         /* Flush out queue */
  81.         if(qdrive!=-1) 
  82.         {
  83.         chk_zone(nstart,count,drive);
  84.         if(count<8) for(i=0;i<count;i++) 
  85.             write_zone(nstart+i,qstart+(i<<L_BS),qdrive,control);
  86.         else crwabs(3,qstart,count,nstart,qdrive);
  87.         }
  88.         qdrive=drive;
  89.         qstart=buf;
  90.         qnext=buf+BLOCK_SIZE;
  91.         nstart=num;
  92.         nnext=num+1;
  93.         count=1;
  94.     }
  95.     else 
  96.     {
  97.         qnext+=BLOCK_SIZE;
  98.         count++;
  99.         nnext++;
  100.     }
  101.     return 0;
  102. }
  103.  
  104. /* This is an equivalent for read ... but this is a bit harder as it is
  105.  * not obvious what to do with the cache . What we finally do is to
  106.  * always get data from the cache if we can , though this could easily
  107.  * turn a large consecutive i/o request into lots of little ones . The
  108.  * cache is not filled from the new read unless we are only reading
  109.  * 1 zone ... basically this assumes that if the user reads several zones
  110.  * then the program will be doing doing some sort of cacheing itself .
  111.  */
  112.  
  113. int read_zones(num,buf,drive,control)
  114. long num;
  115. void *buf;
  116. int drive;
  117. cache_control *control;
  118. {
  119.     static void *qstart,*qnext;
  120.     static long nstart,nnext,count;
  121.     static short qdrive=-1;
  122.     cache *p;
  123.     /* Read from cache if necessary */
  124.  
  125.     if(drive != -1 && (p=in_cache(num,drive,control,NOGUESS)) )
  126.     {
  127.         bcopy(p->buffer,buf,(size_t)BLOCK_SIZE);
  128.         drive=-1; /* Force flush of queued entries */
  129.     }
  130.  
  131.     if( qdrive!=drive || buf!=qnext || nnext!=num || (count > MAX_RWS) )
  132.     {
  133.         /* Flush out queue */
  134.         if(qdrive!=-1)
  135.         {
  136.             if(count==1) read_zone(nstart,qstart,qdrive,control);
  137.             else {
  138.                 if(nnext) crwabs(2,qstart,count,nstart,qdrive);
  139.                 else bzero(qstart,count*(size_t)BLOCK_SIZE);
  140.             }
  141.         }
  142.         qdrive=drive;
  143.         qstart=buf;
  144.         qnext=buf;
  145.         nstart=num;
  146.         nnext=num;
  147.         count=0;
  148.     }
  149.     if(qdrive!=-1)
  150.     {
  151.         qnext+=BLOCK_SIZE;
  152.         count++;
  153.         if(nnext)nnext++;
  154.     }
  155.     return 0;
  156. }
  157.  
  158. /* This routine finds the zone 'numr' of an inode , traversing indirect
  159.  * and double indirect zones as required if flag!=0 zones are added as
  160.  * required . Having two filesystem versions makes this a bit trickier, in
  161.  * fact although using a single routine looks more elegant it is slow,
  162.  * so two versions are used.
  163.  */
  164. /* Special case for l_write:
  165.    if flag > 1, and a new zone is allocated, prepare a cleared block.
  166.    This is for writing to sparse files, when only a partial block is
  167.    written, the rest must be cleared.  Since directories are never
  168.    sparse, always use usrcache in this case. */
  169.  
  170. long find_zone(rip,numr,drive,flag)
  171. d_inode *rip;
  172. long numr;
  173. int drive;
  174. int flag;
  175. {
  176.     super_info *psblk=super_ptr[drive];
  177.  
  178.     return psblk->version ? find_zone2(rip,numr,drive,flag,&dummy) : 
  179.                     find_zone1(rip,numr,drive,flag);
  180. }
  181.  
  182. long find_zone11(rip,numr,drive,flag,fch)
  183. d_inode1 *rip;
  184. long numr;
  185. int drive;
  186. int flag;
  187. f_cache *fch;
  188. {
  189.     long temp_zone;
  190.     unshort *zptr,*zptr2;
  191.     cache *tmp,*tmp2;
  192.  
  193.     /* Past EOF ? */
  194.     if(!flag && (numr*BLOCK_SIZE >= rip->i_size) ) return(0);
  195.  
  196.     /* Zone in inode ? */
  197.     if(numr < NR_DZONE_NUM)
  198.     {
  199.         temp_zone=rip->i_zone[numr];
  200.         if(temp_zone || !flag ) return temp_zone;
  201.         temp_zone = (rip->i_zone[numr]=alloc_zone(drive));
  202.         goto new_zone;
  203.     }
  204.     numr-=NR_DZONE_NUM;
  205.     /* In indirect zone then ? */
  206.     if(numr < NR_INDIRECTS)
  207.     {
  208.         if(rip->i_zone[7])
  209.         {
  210.             tmp=
  211.             cget_zone(rip->i_zone[7],drive,&syscache,&fch->izguess);
  212.             zptr=&tmp->buffer->bind1[numr];
  213.             if( *zptr || !flag )return *zptr;
  214.             if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
  215.             temp_zone = *zptr;
  216.             goto new_zone;
  217.         }
  218.         else
  219.         {
  220.             if(!flag || !(rip->i_zone[7]=alloc_zone(drive))) return 0;
  221.             tmp=cput_zone(rip->i_zone[7],drive,&syscache);
  222.             fch->izguess=tmp;
  223.             bzero(tmp->buffer,(size_t)BLOCK_SIZE);
  224.             temp_zone = tmp->buffer->bind1[numr]=alloc_zone(drive);
  225.             goto new_zone;
  226.         }
  227.     }
  228.     /* Erk double indirect .... */
  229.     numr-=NR_INDIRECTS;
  230.     if (numr < NR_INDIRECTS * NR_INDIRECTS)
  231.     {
  232.  
  233.             if(rip->i_zone[8]) {
  234.         tmp2=cget_zone(rip->i_zone[8],drive,&syscache,&fch->dizguess);
  235.             zptr2=&tmp2->buffer->bind1[numr>>LNR_IND];
  236.             if(*zptr2)
  237.             {
  238.                  tmp=cget_zone(*zptr2,drive,&syscache,&fch->izguess);
  239.                 zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
  240.                 if(*zptr || !flag)return *zptr;
  241.                 if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
  242.                 temp_zone = *zptr;
  243.                 goto new_zone;
  244.               }
  245.               else 
  246.               {
  247.                      if(!flag ||!(*zptr2=alloc_zone(drive)) )return 0;
  248.                 tmp2->status=2;
  249.                 tmp=cput_zone(*zptr2,drive,&syscache);
  250.                 fch->izguess=tmp;
  251.                      bzero(tmp->buffer,(size_t)BLOCK_SIZE);
  252.                 zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
  253.                 temp_zone = *zptr=alloc_zone(drive);
  254.                 goto new_zone;
  255.               }
  256.         }
  257.         if(!flag || !(rip->i_zone[8]=alloc_zone(drive)) ) return 0;
  258.     
  259.         tmp2=cput_zone(rip->i_zone[8],drive,&syscache);
  260.         fch->dizguess=tmp2;
  261.         bzero(tmp2->buffer,(size_t)BLOCK_SIZE);
  262.         zptr2=&tmp2->buffer->bind1[numr>>LNR_IND];
  263.         if(!(*zptr2=alloc_zone(drive))) return 0;
  264.  
  265.         tmp=cput_zone(*zptr2,drive,&syscache);
  266.         fch->izguess=tmp;
  267.         bzero(tmp->buffer,(size_t)BLOCK_SIZE);
  268.         zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
  269.         temp_zone = *zptr=alloc_zone(drive) ;
  270.         goto new_zone;
  271.     }
  272.     return 0;
  273.  
  274.       new_zone:
  275.     if (temp_zone && flag > 1)
  276.       {
  277.         tmp = cput_zone (temp_zone, drive, &usrcache);
  278.         bzero (tmp->buffer, (size_t) BLOCK_SIZE);
  279.       }
  280.     return temp_zone;
  281. }
  282.  
  283. long find_zone1(rip,numr,drive,flag)
  284. d_inode *rip;
  285. long numr;
  286. int drive;
  287. int flag;
  288. {
  289.     long temp_zone;
  290.     unshort *zptr,*zptr2;
  291.     cache *tmp,*tmp2;
  292.  
  293.     /* Past EOF ? */
  294.     if(!flag && (numr*BLOCK_SIZE >= rip->i_size) ) return(0);
  295.  
  296.     /* Zone in inode ? */
  297.     if(numr < NR_DZONE_NUM)
  298.     {
  299.         temp_zone=rip->i_zone[numr];
  300.         if(temp_zone || !flag ) return temp_zone;
  301.         return(rip->i_zone[numr]=alloc_zone(drive));
  302.     }
  303.     numr-=NR_DZONE_NUM;
  304.     /* In indirect zone then ? */
  305.     if(numr < NR_INDIRECTS)
  306.     {
  307.         if(rip->i_zone[7])
  308.         {
  309.             tmp=cget_zone(rip->i_zone[7],drive,&syscache,NOGUESS);
  310.             zptr=&tmp->buffer->bind1[numr];
  311.             if( *zptr || !flag )return *zptr;
  312.             if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
  313.             return *zptr;
  314.         }
  315.         else
  316.         {
  317.             if(!flag || !(rip->i_zone[7]=alloc_zone(drive))) return 0;
  318.             tmp=cput_zone(rip->i_zone[7],drive,&syscache);
  319.             bzero(tmp->buffer,(size_t)BLOCK_SIZE);
  320.             return tmp->buffer->bind1[numr]=alloc_zone(drive);
  321.         }
  322.     }
  323.     /* Erk double indirect .... */
  324.     numr-=NR_INDIRECTS;
  325.     if (numr < NR_INDIRECTS * NR_INDIRECTS)
  326.     {
  327.  
  328.             if(rip->i_zone[8]) {
  329.             tmp2=cget_zone(rip->i_zone[8],drive,&syscache,NOGUESS);
  330.             zptr2=&tmp2->buffer->bind1[numr>>LNR_IND];
  331.             if(*zptr2)
  332.             {
  333.                      tmp=cget_zone(*zptr2,drive,&syscache,NOGUESS);
  334.                 zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
  335.                 if(*zptr || !flag)return *zptr;
  336.                 if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
  337.                 return *zptr;
  338.               }
  339.               else 
  340.               {
  341.                      if(!flag ||!(*zptr2=alloc_zone(drive)) )return 0;
  342.                 tmp2->status=2;
  343.                 tmp=cput_zone(*zptr2,drive,&syscache);
  344.                      bzero(tmp->buffer,(size_t)BLOCK_SIZE);
  345.                 zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
  346.                 return *zptr=alloc_zone(drive);
  347.               }
  348.         }
  349.         if(!flag || !(rip->i_zone[8]=alloc_zone(drive)) ) return 0;
  350.     
  351.         tmp2=cput_zone(rip->i_zone[8],drive,&syscache);
  352.         bzero(tmp2->buffer,(size_t)BLOCK_SIZE);
  353.         zptr2=&tmp2->buffer->bind1[numr>>LNR_IND];
  354.         if(!(*zptr2=alloc_zone(drive))) return 0;
  355.  
  356.         tmp=cput_zone(*zptr2,drive,&syscache);
  357.         bzero(tmp->buffer,(size_t)BLOCK_SIZE);
  358.         zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
  359.         return *zptr=alloc_zone(drive) ;
  360.     }
  361.     return 0;
  362. }
  363.  
  364. long find_zone2(rip,numr,drive,flag,fch)
  365. d_inode *rip;
  366. long numr;
  367. int drive;
  368. int flag;
  369. f_cache *fch;
  370. {
  371.     long temp_zone;
  372.     long *zptr,*zptr2;
  373.     cache *tmp,*tmp2;
  374.  
  375.     /* Past EOF ? */
  376.     if((numr*BLOCK_SIZE >= rip->i_size) && !flag ) return(0);
  377.  
  378.     /* Zone in inode ? */
  379.     if(numr < NR_DZONE_NUM2)
  380.     {
  381.         temp_zone=rip->i_zone[numr];
  382.         if(temp_zone || !flag ) return temp_zone;
  383.         temp_zone = (rip->i_zone[numr]=alloc_zone(drive));
  384.         goto new_zone;
  385.     }
  386.     numr-=NR_DZONE_NUM2;
  387.     /* In indirect zone then ? */
  388.     if(numr < NR_INDIRECTS2)
  389.     {
  390.         if(rip->i_zone[7])
  391.         {
  392.             tmp=
  393.             cget_zone(rip->i_zone[7],drive,&syscache,&fch->izguess);
  394.             zptr=&tmp->buffer->bind[numr];
  395.             if( *zptr || !flag )return *zptr;
  396.             if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
  397.             temp_zone = *zptr;
  398.             goto new_zone;
  399.         }
  400.         else
  401.         {
  402.             if(!flag || !(rip->i_zone[7]=alloc_zone(drive))) return 0;
  403.             tmp=cput_zone(rip->i_zone[7],drive,&syscache);
  404.             bzero(tmp->buffer,(size_t)BLOCK_SIZE);
  405.             temp_zone = tmp->buffer->bind[numr]=alloc_zone(drive);
  406.             goto new_zone;
  407.         }
  408.     }
  409.     /* Erk double indirect .... */
  410.     numr-=NR_INDIRECTS2;
  411.     if (numr < NR_INDIRECTS2 * NR_INDIRECTS2)
  412.     {
  413.         if(rip->i_zone[8]) {
  414.           tmp2=cget_zone(rip->i_zone[8],drive,&syscache,&fch->dizguess);
  415.             zptr2=&tmp2->buffer->bind[numr>>LNR_IND2];
  416.             if(*zptr2)
  417.             {
  418.                      tmp=
  419.                 cget_zone(*zptr2,drive,&syscache,&fch->izguess);
  420.                 zptr=&tmp->buffer->bind[numr & (NR_INDIRECTS2-1)];
  421.                 if(*zptr || !flag)return *zptr;
  422.                 if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
  423.                 temp_zone = *zptr;
  424.                 goto new_zone;
  425.               }
  426.               else 
  427.               {
  428.                      if(!flag ||!(*zptr2=alloc_zone(drive)) )return 0;
  429.                 tmp2->status=2;
  430.                 tmp=cput_zone(*zptr2,drive,&syscache);
  431.                      bzero(tmp->buffer,(size_t)BLOCK_SIZE);
  432.                 zptr=&tmp->buffer->bind[numr & (NR_INDIRECTS2-1)];
  433.                 temp_zone = *zptr=alloc_zone(drive);
  434.                 goto new_zone;
  435.               }
  436.         }
  437.         if(!flag || !(rip->i_zone[8]=alloc_zone(drive)) ) return 0;
  438.     
  439.         tmp2=cput_zone(rip->i_zone[8],drive,&syscache);
  440.         bzero(tmp2->buffer,(size_t)BLOCK_SIZE);
  441.         zptr2=&tmp2->buffer->bind[numr>>LNR_IND2];
  442.         if(!(*zptr2=alloc_zone(drive))) return 0;
  443.  
  444.         tmp=cput_zone(*zptr2,drive,&syscache);
  445.         bzero(tmp->buffer,(size_t)BLOCK_SIZE);
  446.         zptr=&tmp->buffer->bind[numr & (NR_INDIRECTS2-1)];
  447.         temp_zone = *zptr=alloc_zone(drive) ;
  448.         goto new_zone;
  449.     }
  450.     /* Triple indirect */
  451.     numr -= NR_INDIRECTS2 * NR_INDIRECTS2;
  452.     if (numr < NR_INDIRECTS2 * NR_INDIRECTS2 * NR_INDIRECTS2)
  453.       {
  454.         long *zptr3;
  455.         cache *tmp3;
  456.         if (rip->i_zone[9])
  457.           {
  458.         tmp3 = cget_zone (rip->i_zone[9], drive, &syscache, NOGUESS);
  459.         zptr3 = &tmp3->buffer->bind[numr >> (LNR_IND2 * 2)];
  460.         if (*zptr3)
  461.           {
  462.             tmp2 = cget_zone (*zptr3, drive, &syscache,
  463.                       &fch->dizguess);
  464.             zptr2 = &tmp2->buffer->bind[(numr >> LNR_IND2)
  465.                         & (NR_INDIRECTS2 - 1)];
  466.             if (*zptr2)
  467.               {
  468.             tmp = cget_zone (*zptr2, drive, &syscache,
  469.                      &fch->izguess);
  470.             zptr = &tmp->buffer->bind[numr & (NR_INDIRECTS2-1)];
  471.             if (*zptr || !flag)
  472.               return *zptr;
  473.             if ((*zptr = alloc_zone (drive)) != 0)
  474.               tmp->status = 2;
  475.             temp_zone = *zptr;
  476.             goto new_zone;
  477.               }
  478.             else
  479.               {
  480.             if (!flag || !(*zptr2 = alloc_zone (drive)))
  481.               return 0;
  482.             tmp2->status = 2;
  483.             tmp = cput_zone (*zptr2, drive, &syscache);
  484.             bzero (tmp->buffer, (size_t) BLOCK_SIZE);
  485.             zptr = &tmp->buffer->bind[numr & (NR_INDIRECTS2 - 1)];
  486.             temp_zone = *zptr = alloc_zone (drive);
  487.             goto new_zone;
  488.               }
  489.           }
  490.         else
  491.           {
  492.             if (!flag || !(*zptr3 = alloc_zone (drive)))
  493.               return 0;
  494.             tmp3->status = 2;
  495.             tmp2 = cput_zone (*zptr3, drive, &syscache);
  496.             bzero (tmp2->buffer, (size_t) BLOCK_SIZE);
  497.             zptr2 = &tmp2->buffer->bind[(numr >> LNR_IND2)
  498.                         & (NR_INDIRECTS2 - 1)];
  499.             if (!(*zptr2 = alloc_zone (drive)))
  500.               return 0;
  501.             tmp = cput_zone (*zptr2, drive, &syscache);
  502.             bzero (tmp->buffer, (size_t) BLOCK_SIZE);
  503.             zptr = &tmp->buffer->bind[numr & (NR_INDIRECTS2 - 1)];
  504.             temp_zone = *zptr = alloc_zone (drive);
  505.             goto new_zone;
  506.           }
  507.           }
  508.         if (!flag || !(rip->i_zone[9] = alloc_zone (drive)))
  509.           return 0;
  510.  
  511.         tmp3 = cput_zone (rip->i_zone[9], drive, &syscache);
  512.         bzero (tmp3->buffer, (size_t) BLOCK_SIZE);
  513.         zptr3 = &tmp3->buffer->bind[numr >> (LNR_IND2 * 2)];
  514.         if (!(*zptr3 = alloc_zone (drive)))
  515.           return 0;
  516.  
  517.         tmp2 = cput_zone (*zptr3, drive, &syscache);
  518.         bzero (tmp2->buffer, (size_t) BLOCK_SIZE);
  519.         zptr2 = &tmp2->buffer->bind[(numr >> LNR_IND2)
  520.                     & (NR_INDIRECTS2 - 1)];
  521.         if (!(*zptr2 = alloc_zone (drive)))
  522.           return 0;
  523.  
  524.         tmp = cput_zone (*zptr2, drive, &syscache);
  525.         bzero (tmp->buffer, (size_t) BLOCK_SIZE);
  526.         zptr = &tmp->buffer->bind[numr & (NR_INDIRECTS2 - 1)];
  527.         temp_zone = *zptr = alloc_zone (drive);
  528.         goto new_zone;
  529.       }
  530.     return 0;
  531.  
  532.       new_zone:
  533.     if (temp_zone && flag > 1)
  534.       {
  535. #if 1
  536.         cache_control *control = &usrcache;
  537.         if (IS_DIR((*rip))) {
  538.         ALERT("find_zone: Drive %d sparse dir!",drive);
  539.         control = &syscache;
  540.         }
  541.         tmp = cput_zone (temp_zone, drive, control);
  542. #else
  543.         tmp = cput_zone (temp_zone, drive, &usrcache);
  544. #endif
  545.         bzero (tmp->buffer, (size_t) BLOCK_SIZE);
  546.       }
  547.     return temp_zone;
  548. }
  549.  
  550. /* This reads zone number 'numr' of an inode .
  551.  * It returns the actual number of valid characters in 'numr' , this is only
  552.  * used for directories so it is hard-coded for the system cache. 
  553.  */
  554.  
  555. int next_zone(rip,numr,buf,drive)
  556. d_inode *rip;
  557. long numr;
  558. void *buf;
  559. int drive;
  560. {
  561.     long ztemp;
  562.     long ret;
  563.  
  564.     ret=min(rip->i_size-numr*BLOCK_SIZE,BLOCK_SIZE);
  565.     if(ret <= 0)return 0;
  566.     ztemp=find_zone(rip,numr,drive,0);
  567.     read_zone(ztemp,buf,drive,&syscache);
  568.     return (int)ret;
  569. }
  570.  
  571. /* As above but reads in cache pointer */
  572.  
  573. int cnext_zone(rip,numr,buf,drive)
  574. d_inode *rip;
  575. long numr;
  576. cache **buf;
  577. int drive;
  578. {
  579.     long ztemp;
  580.     long ret;
  581.  
  582.     ret=min(rip->i_size-numr*BLOCK_SIZE,BLOCK_SIZE);
  583.     if(ret <= 0)return 0;
  584.     ztemp=find_zone(rip,numr,drive,0);
  585.     *buf=cget_zone(ztemp,drive,&syscache,NOGUESS);
  586.     return (int)ret;
  587. }
  588.  
  589. /* l_write is used internally for doing things a normal user cannot such
  590.  * as writing to a directory ... it accepts 5 parameters , an inode num
  591.  * a position (current position of write) a count which is the number of
  592.  * characters to write,a buffer and a drive , it updates i_size as needed 
  593.  * and allocates zones as required , it is nastier than a read because it 
  594.  * has to write partial blocks within valid blocks and to write beyond EOF
  595.  */
  596.  
  597. long l_write(inum,pos,len,buf,drive)
  598. unsigned inum;
  599. long pos;
  600. long len;
  601. const void *buf;
  602. int drive;
  603. {
  604.     return super_ptr[drive]->version ? l_write2(inum,pos,len,buf,drive) :
  605.                     l_write1(inum,pos,len,buf,drive);
  606. }
  607.  
  608. long l_write1(inum,pos,len,buf,drive)
  609. unsigned inum;
  610. long pos;
  611. long len;
  612. const void *buf;
  613. int drive;
  614. {
  615.     register const void *p = buf;    /* Current position in buffer */
  616.     d_inode1 *rip;
  617.     long chunk;
  618.     long left=len;
  619.     long zne;
  620.     cache_control *control;
  621.     int *status;
  622.  
  623.     rip=get_inode1(inum,drive,&status,NOGUESS);
  624.  
  625.      /* Work out which cache to use */
  626.     control = (IS_DIR((*rip))||IS_SYM((*rip))) ? &syscache : &usrcache;
  627.     if(pos==-1l) pos=rip->i_size; /* If pos==-1 append */
  628.     chunk=pos/BLOCK_SIZE;
  629.  
  630.     while(left)    /* Loop while characters remain to be written */
  631.     {
  632.     long zoff;
  633.     ushort wleft;
  634.     cache *cp;
  635.  
  636.     zoff = pos & (BLOCK_SIZE -1);        /* Current zone position */
  637.     wleft=min(BLOCK_SIZE-zoff,left);    /*Left to write in curr blk*/    
  638.     zne = find_zone11 (rip, chunk++, drive,
  639.                1 + (zoff || pos < rip->i_size),
  640.                &dummy); /* Current zone in file */
  641.     if(zne==0) break;            /* Partition full */
  642.  
  643.     if((zoff) || ( (left < BLOCK_SIZE) && (pos+left<rip->i_size)))
  644.     {
  645.         cp=cget_zone(zne,drive,control,NOGUESS);
  646.         cp->status=2;
  647.     }
  648.     else 
  649.     {
  650.         cp=cput_zone(zne,drive,control);
  651.         if(wleft!=BLOCK_SIZE)bzero(cp->buffer->bdata,(size_t)BLOCK_SIZE);
  652.     }
  653.     bcopy(p,&cp->buffer->bdata[zoff],(size_t)wleft);
  654.     pos+=wleft;
  655.     p+=wleft;
  656.     if(pos>rip->i_size)rip->i_size=pos;
  657.     left-=wleft;
  658.     }
  659.  
  660.     rip->i_mtime=Unixtime(Timestamp(), Datestamp());
  661.     *status=2;
  662.  
  663.     return(len-left);
  664. }
  665.  
  666. long l_write2(inum,pos,len,buf,drive)
  667. unsigned inum;
  668. long pos;
  669. long len;
  670. const void *buf;
  671. int drive;
  672. {
  673.     register const void *p = buf;    /* Current position in buffer */
  674.     d_inode *rip;
  675.     long chunk;
  676.     long left=len;
  677.     long zne;
  678.     cache_control *control;
  679.     int *status;
  680.  
  681.     rip=get_inode2(inum,drive,&status,NOGUESS);
  682.  
  683.      /* Work out which cache to use */
  684.     control = (IS_DIR((*rip))||IS_SYM((*rip))) ? &syscache : &usrcache;
  685.     if(pos==-1l) pos=rip->i_size; /* If pos==-1 append */
  686.     chunk=pos/BLOCK_SIZE;
  687.  
  688.     while(left)    /* Loop while characters remain to be written */
  689.     {
  690.     long zoff;
  691.     ushort wleft;
  692.     cache *cp;
  693.  
  694.     zoff = pos & (BLOCK_SIZE -1);        /* Current zone position */
  695.     wleft=min(BLOCK_SIZE-zoff,left);    /*Left to write in curr blk*/    
  696.  
  697.     if((zoff) || ( (left < BLOCK_SIZE) && (pos+left<rip->i_size)))
  698.     {
  699.         zne = find_zone2 (rip, chunk++, drive, 2,
  700.                   &dummy); /* Current zone in file */
  701.         if(zne==0)break;            /* Partition full */
  702.         cp=cget_zone(zne,drive,control,NOGUESS);
  703.         cp->status=2;
  704.     }
  705.     else 
  706.     {
  707.         zne = find_zone2 (rip, chunk++, drive, 1,
  708.                   &dummy); /* Current zone in file */
  709.         if(zne==0)break;            /* Partition full */
  710.         cp=cput_zone(zne,drive,control);
  711.         if(wleft!=BLOCK_SIZE)bzero(cp->buffer->bdata,(size_t)BLOCK_SIZE);
  712.     }
  713.     bcopy(p,&cp->buffer->bdata[zoff],(size_t)wleft);
  714.     pos+=wleft;
  715.     p+=wleft;
  716.     if(pos>rip->i_size)rip->i_size=pos;
  717.     left-=wleft;
  718.     }
  719.  
  720.     rip->i_mtime=Unixtime(Timestamp(), Datestamp());
  721.     *status=2;
  722.  
  723.     return(len-left);
  724. }
  725.