⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fatfs.c

📁 GNU FreeDOS兼容MS DOS很好的东东.
💻 C
📖 第 1 页 / 共 5 页
字号:
  /* Now begin the linear search. The relative cluster is         */  /* maintained as part of the set of physical indices. It is     */  /* also the highest order index and is mapped directly into     */  /* physical cluster. Our search is performed by pacing an index */  /* up to the relative cluster position where the index falls    */  /* within the cluster.                                          */  while (fnp->f_cluster_offset != relcluster)  {    /* get next cluster in the chain */    cluster = next_cluster(fnp->f_dpb, fnp->f_cluster);    if (cluster == 1)      return DE_SEEK;    /* If this is a read and the next is a LAST_CLUSTER,               */    /* then we are going to read past EOF, return zero read            */    /* or expand the list if we're going to write and have run into    */    /* the last cluster marker.                                        */    if (cluster == LONG_LAST_CLUSTER)    {      if (mode == XFR_READ)        return DE_SEEK;      /* mode == XFR_WRITE */      cluster = extend(fnp);      if (cluster == LONG_LAST_CLUSTER)        return DE_HNDLDSKFULL;    }    fnp->f_cluster = cluster;    fnp->f_cluster_offset++;  }#ifdef DISPLAY_GETBLOCK  printf("done.\n");#endif  return SUCCESS;}/* extends a file from f_dir.dir_size to f_offset              *//* Proper OS's write zeros in between, but DOS just adds       *//* garbage sectors, and lets the caller do the zero filling    *//* if you prefer you can have this enabled using               *//* #define WRITEZEROS 1                                        *//* but because we want to be compatible, we don't do this by   *//* default                                                     */STATIC COUNT dos_extend(f_node_ptr fnp){#ifdef WRITEZEROS  struct buffer FAR *bp;  UCOUNT xfr_cnt = 0;  /* The variable secsize will be used later.                     */  UWORD secsize = fnp->f_dpb->dpb_secsize;  ULONG count;  unsigned sector, boff;#endif  if (fnp->f_offset <= fnp->f_dir.dir_size)    return SUCCESS;#ifdef WRITEZEROS  count = fnp->f_offset - fnp->f_dir.dir_size;  fnp->f_offset = fnp->f_dir.dir_size;  while (count > 0)#endif  {    if (map_cluster(fnp, XFR_WRITE) != SUCCESS)      return DE_HNDLDSKFULL;#ifdef WRITEZEROS    /* Compute the block within the cluster and the offset  */    /* within the block.                                    */    sector = (UBYTE)(fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask;    boff = (UWORD)(fnp->f_offset % secsize);#ifdef DSK_DEBUG    printf("write %d links; dir offset %ld, cluster %d\n",           fnp->f_count, fnp->f_diroff, fnp->f_cluster);#endif    xfr_cnt = count < (ULONG) secsize - boff ?        (UWORD) count : secsize - boff;    /* get a buffer to store the block in */    if ((boff == 0) && (xfr_cnt == secsize))    {      bp = getblockOver(clus2phys(fnp->f_cluster, fnp->f_dpb) +                        sector, fnp->f_dpb->dpb_unit);    }    else    {      bp = getblock(clus2phys(fnp->f_cluster, fnp->f_dpb) + sector,                    fnp->f_dpb->dpb_unit);    }    if (bp == NULL)    {      return DE_BLKINVLD;    }    /* set a block to zero                                  */    fmemset((BYTE FAR *) & bp->b_buffer[boff], 0, xfr_cnt);    bp->b_flag |= BFR_DIRTY | BFR_VALID;    if (xfr_cnt == sizeof(bp->b_buffer))        /* probably not used later */    {      bp->b_flag |= BFR_UNCACHE;    }    /* update pointers and counters                         */    count -= xfr_cnt;    fnp->f_offset += xfr_cnt;#endif    fnp->f_dir.dir_size = fnp->f_offset;    merge_file_changes(fnp, FALSE);     /* /// Added - Ron Cemer */  }  return SUCCESS;}/*  comments read optimization for large reads: read total clusters in one piece  running a program like     while (1) {    read(fd, header, sizeof(header));   // small read     read(fd, buffer, header.size);      // where size is large, up to 63K                                         // with average ~32K    }                                            FreeDOS 2025 is really slow.     on a P200 with modern 30GB harddisk, doing above for a 14.5 MB file        MSDOS 6.22 clustersize 8K  ~2.5 sec (accumulates over clusters, reads for 63 sectors seen),    IBM PCDOS 7.0          8K  ~4.3     IBM PCDOS 7.0          16K ~2.8     FreeDOS ke2025             ~17.5    with the read optimization (ke2025a),                clustersize 8K  ~6.5 sec        clustersize 16K ~4.2 sec            it was verified with IBM feature tool,    that the drive read ahead cache (says it) is on. still this huge difference ;-)            it's coded pretty conservative to avoid all special cases,     so it shouldn't break anything :-)    possible further optimization:            collect read across clusters (if file is not fragmented).        MSDOS does this (as readcounts up to 63 sectors where seen)        specially important for diskettes, where clustersize is 1 sector                 the same should be done for writes as well    the time to compile the complete kernel (on some P200) is     reduced from 67 to 56 seconds - in an otherwise identical configuration.    it's not clear if this improvement shows up elsewhere, but it shouldn't harm either        TE 10/18/01 14:00        collect read across clusters (if file is not fragmented) done.            seems still to work :-))        no large performance gains visible, but should now work _much_    better for the people, that complain about slow floppy access    the         fnp->f_offset +to_xfer < fnp->f_dir.dir_size &&  avoid EOF problems     condition can probably _carefully_ be dropped                TE 10/18/01 19:00    *//* Read/write block from disk *//* checking for valid access was already done by the functions in   dosfns.c */long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode){  REG f_node_ptr fnp;  REG struct buffer FAR *bp;  UCOUNT xfr_cnt = 0;  UCOUNT ret_cnt = 0;  unsigned secsize;  unsigned to_xfer = count;  ULONG currentblock;#if 0 /*DSK_DEBUG*/  if (bDumpRdWrParms)  {    printf("rwblock:fd %02x  buffer %04x:%04x count %x\n",           fd, FP_SEG(buffer), FP_OFF(buffer), count);  }#endif  /* Translate the fd into an fnode pointer, since all internal   */  /* operations are achieved through fnodes.                      */  fnp = xlt_fd(fd);  /* If the fd was invalid because it was out of range or the     */  /* requested file was not open, tell the caller and exit        */  /* note: an invalid fd is indicated by a 0 return               */  if (fnp == (f_node_ptr) 0)  {    return 0;  }  if (mode==XFR_WRITE)  {    fnp->f_dir.dir_attrib |= D_ARCHIVE;    fnp->f_flags |= F_DMOD;       /* mark file as modified */    fnp->f_flags &= ~F_DDATE;     /* set date not valid any more */        if (dos_extend(fnp) != SUCCESS)    {      save_far_f_node(fnp);      return 0;    }  }    /* Test that we are really about to do a data transfer. If the  */  /* count is zero and the mode is XFR_READ, just exit. (Any      */  /* read with a count of zero is a nop).                         */  /*                                                              */  /* A write (mode is XFR_WRITE) is a special case.  It sets the  */  /* file length to the current length (truncates it).            */  /*                                                              */  /* NOTE: doing this up front saves a lot of headaches later.    */  if (count == 0)  {    /* NOTE: doing this up front made a lot of headaches later :-( TE */    /* FAT allocation has to be extended if necessary              TE */    /* Now done in dos_extend                                      BO */    /* remove all the following allocated clusters in shrink_file     */    if (mode == XFR_WRITE)    {      fnp->f_dir.dir_size = fnp->f_offset;      shrink_file(fnp);    }    save_far_f_node(fnp);    return 0;  }  /* The variable secsize will be used later.                     */  secsize = fnp->f_dpb->dpb_secsize;  /* Adjust the far pointer from user space to supervisor space   */  buffer = adjust_far(buffer);  /* Do the data transfer. Use block transfer methods so that we  */  /* can utilize memory management in future DOS-C versions.      */  while (ret_cnt < count)  {    unsigned sector, boff;    /* Do an EOF test and return whatever was transferred   */    /* but only for regular files.                          */    if (mode == XFR_READ && !(fnp->f_flags & F_DDIR) && (fnp->f_offset >= fnp->f_dir.dir_size))    {      save_far_f_node(fnp);      return ret_cnt;    }    /* Position the file to the fnode's pointer position. This is   */    /* done by updating the fnode's cluster, block (sector) and     */    /* byte offset so that read or write becomes a simple data move */    /* into or out of the block data buffer.                        */    /* The more difficult scenario is the (more common)     */    /* file offset case. Here, we need to take the fnode's  */    /* offset pointer (f_offset) and translate it into a    */    /* relative cluster position, cluster block (sector)    */    /* offset (sector) and byte offset (boff). Once we      */    /* have this information, we need to translate the      */    /* relative cluster position into an absolute cluster   */    /* position (f_cluster). This is unfortunate because it */    /* requires a linear search through the file's FAT      */    /* entries. It made sense when DOS was originally       */    /* designed as a simple floppy disk operating system    */    /* where the FAT was contained in core, but now         */    /* requires a search through the FAT blocks.            */    /*                                                      */    /* The algorithm in this function takes advantage of    */    /* the blockio block buffering scheme to simplify the   */    /* task.                                                */#ifdef DISPLAY_GETBLOCK    printf("rwblock: ");#endif    if (map_cluster(fnp, mode) != SUCCESS)    {      save_far_f_node(fnp);      return ret_cnt;    }    if (mode == XFR_WRITE)    {      merge_file_changes(fnp, FALSE);   /* /// Added - Ron Cemer */    }    /* Compute the block within the cluster and the offset  */    /* within the block.                                    */    sector = (UBYTE)(fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask;    boff = (UWORD)(fnp->f_offset % secsize);    currentblock = clus2phys(fnp->f_cluster, fnp->f_dpb) + sector;    /* see comments above */    if (!(fnp->f_flags & F_DDIR) && /* don't experiment with directories yet */        boff == 0)              /* complete sectors only */    {      static ULONG startoffset;      UCOUNT sectors_to_xfer, sectors_wanted;      startoffset = fnp->f_offset;      sectors_wanted = to_xfer;      /* avoid EOF problems */      if (mode == XFR_READ && to_xfer > fnp->f_dir.dir_size - fnp->f_offset)        sectors_wanted = (UCOUNT)(fnp->f_dir.dir_size - fnp->f_offset);            sectors_wanted /= secsize;      if (sectors_wanted == 0)        goto normal_xfer;      sectors_to_xfer = fnp->f_dpb->dpb_clsmask + 1 - sector;      sectors_to_xfer = min(sectors_to_xfer, sectors_wanted);      fnp->f_offset += sectors_to_xfer * secsize;      while (sectors_to_xfer < sectors_wanted)      {        if (map_cluster(fnp, mode) != SUCCESS)          break;        if (clus2phys(fnp->f_cluster, fnp->f_dpb) !=            currentblock + sectors_to_xfer)          break;        sectors_to_xfer += fnp->f_dpb->dpb_clsmask + 1;        sectors_to_xfer = min(sectors_to_xfer, sectors_wanted);        fnp->f_offset = startoffset + sectors_to_xfer * secsize;      }      xfr_cnt = sectors_to_xfer * secsize;      /* avoid caching trouble */      DeleteBlockInBufferCache(currentblock,                               currentblock + sectors_to_xfer - 1,                               fnp->f_dpb->dpb_unit, mode);      if (dskxfer(fnp->f_dpb->dpb_unit,                  currentblock,                  (VOID FAR *) buffer, sectors_to_xfer,                  mode == XFR_READ ? DSKREAD : DSKWRITE))      {        fnp->f_offset = startoffset;        save_far_f_node(fnp);        return DE_ACCESS;      }      goto update_pointers;    }    /* normal read: just the old, buffer = sector based read */  normal_xfer:#ifdef DSK_DEBUG    printf("r/w %d links; dir offset %d, cluster %d, mode %x\n",           fnp->f_count, fnp->f_diroff, fnp->f_cluster, mode);#endif    /* Get the block we need from cache                     */    bp = getblock(currentblock                    /*clus2phys(fnp->f_cluster, fnp->f_dpb) + fnp->f_sector */                    , fnp->f_dpb->dpb_unit);    #ifdef DISPLAY_GETBLOCK    printf("DATA (rwblock)\n");#endif    if (bp == NULL)             /* (struct buffer *)0 --> DS:0 !! */    {      save_far_f_node(fnp);      return ret_cnt;    }    /* transfer a block                                     */    /* Transfer size as either a full block size, or the    */    /* requested transfer size, whichever is smaller.       */    /* Then compare to what is left, since we can transfer  */    /* a maximum of what is left.                           */    xfr_cnt = min(to_xfer, secsize - boff);    if (!(fnp->f_flags & F_DDIR) && mode == XFR_READ)      xfr_cnt = (UWORD) min(xfr_cnt, fnp->f_dir.dir_size - fnp->f_offset);    /* transfer a block                                     */    /* Transfer size as either a full block size, or the    */    /* requested transfer size, whichever is smaller.       */    /* Then compare to what is left, since we can transfer  */    /* a maximum of what is left.                           */    if (mode == XFR_WRITE)    {      fmemcpy(&bp->b_buffer[boff], buffer, xfr_cnt);      bp->b_flag |= BFR_DIRTY | BFR_VALID;    }    else    {      fmemcpy(buffer, &bp->b_buffer[boff], xfr_cnt);    }    /* complete buffer transferred ?        probably not reused later     */    if (xfr_cnt == sizeof(bp->b_buffer) ||        (mode == XFR_READ && fnp->f_offset + xfr_cnt == fnp->f_dir.dir_size))    {      bp->b_flag |= BFR_UNCACHE;    }    /* update pointers and counters                         */    fnp->f_offset += xfr_cnt;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -