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

📄 fatfs.c

📁 开源DOS的C代码源程序
💻 C
📖 第 1 页 / 共 5 页
字号:
      /* 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;

  update_pointers:
    ret_cnt += xfr_cnt;
    to_xfer -= xfr_cnt;
    buffer = adjust_far((char FAR *)buffer + xfr_cnt);
    if (mode == XFR_WRITE)
    {
      if (fnp->f_offset > fnp->f_dir.dir_size)
      {
        fnp->f_dir.dir_size = fnp->f_offset;
      }
      merge_file_changes(fnp, FALSE);     /* /// Added - Ron Cemer */
    }
  }
  save_far_f_node(fnp);
  return ret_cnt;
}

/* Position the file pointer to the desired offset                      */
/* Returns a long current offset or a negative error code               */
LONG dos_lseek(COUNT fd, LONG foffset, COUNT origin)
{
  REG f_node_ptr fnp;

  /* Translate the fd into a useful pointer                       */

  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 (LONG) DE_INVLDHNDL;

  /* now do the actual lseek adjustment to the file poitner       */
  switch (origin)
  {
      /* offset from beginning of file                                */
    case 0:
      fnp->f_offset = (ULONG) foffset;
      break;

      /* offset from current location                                 */
    case 1:
      fnp->f_offset += foffset;
      break;

      /* offset from eof                                              */
    case 2:
      fnp->f_offset = fnp->f_dir.dir_size + foffset;
      break;

      /* default to an invalid function                               */
    default:
      release_near_f_node(fnp);
      return (LONG) DE_INVLDFUNC;
  }
  save_far_f_node(fnp);
  return fnp->f_offset;
}

/* returns the number of unused clusters */
CLUSTER dos_free(struct dpb FAR * dpbp)
{
  /* There's an unwritten rule here. All fs       */
  /* cluster start at 2 and run to max_cluster+2  */
  REG CLUSTER i;
  REG CLUSTER cnt = 0;
  CLUSTER max_cluster = dpbp->dpb_size;

#ifdef WITHFAT32
  if (ISFAT32(dpbp))
  {
    if (dpbp->dpb_xnfreeclst != XUNKNCLSTFREE)
      return dpbp->dpb_xnfreeclst;
    max_cluster = dpbp->dpb_xsize;
  }
  else
#endif
  if (dpbp->dpb_nfreeclst != UNKNCLSTFREE)
    return dpbp->dpb_nfreeclst;

  for (i = 2; i <= max_cluster; i++)
  {
    if (next_cluster(dpbp, i) == 0)
      ++cnt;
  }
#ifdef WITHFAT32
  if (ISFAT32(dpbp))
  {
    dpbp->dpb_xnfreeclst = cnt;
    write_fsinfo(dpbp);
    return cnt;
  }
#endif
  dpbp->dpb_nfreeclst = (UWORD)cnt;
  return cnt;
}

#ifndef IPL
int dos_cd(char * PathName)
{
  f_node_ptr fnp;
  struct cds FAR *cdsp = get_cds(PathName[0] - 'A');

  if ((media_check(cdsp->cdsDpb) < 0))
    return DE_INVLDDRV;

  /* now test for its existance. If it doesn't, return an error.  */
  if ((fnp = dir_open(PathName)) == NULL)
    return DE_PATHNOTFND;

  /* problem: RBIL table 01643 does not give a FAT32 field for the
     CDS start cluster. But we are not using this field ourselves */
  cdsp->cdsStrtClst = (UWORD)fnp->f_dirstart;
  dir_close(fnp);
  return SUCCESS;
}
#endif

/* try to allocate a near f_node                            */
/* (there are just two of them, in the SDA)                 */

f_node_ptr get_near_f_node(void)
{
  f_node_ptr fnp = fnode;

  if (fnp->f_count == 0)
    fnp->f_count++;
  else
  {
    fnp++;
    if (fnp->f_count == 0)
      fnp->f_count++;
    else
    {
      fnp = (f_node_ptr) 0;
      panic("more than two near fnodes requested at the same time!\n");
    }
  }
  return fnp;
}

/* Try to allocate an f_node from the available files array */

f_node_ptr get_f_node(void)
{
  REG int i;
  f_node_ptr fnp = get_near_f_node();

  if (fnp != (f_node_ptr)0)
  {
    for (i = 0; i < f_nodes_cnt; i++)
    {
      if (f_nodes[i].f_count == 0)
      {
        ++f_nodes[i].f_count;
        fnode_fd[fnp - fnode] = i;
        return fnp;
      }
    }
    release_near_f_node(fnp);
  }
  return (f_node_ptr) 0;
}

VOID release_f_node(f_node_ptr fnp)
{
  struct f_node FAR *fp = &f_nodes[xlt_fnp(fnp)];

  if (fp->f_count > 0)
    --fp->f_count;
  else
    fp->f_count = 0;
  release_near_f_node(fnp);
}

#ifndef IPL
COUNT dos_getfattr_fd(COUNT fd)
{
  f_node_ptr 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 DE_TOOMANY;

  release_near_f_node(fnp);
  return fnp->f_dir.dir_attrib;
}

COUNT dos_getfattr(BYTE * name)
{
  COUNT result, fd;

  fd = (short)dos_open(name, O_RDONLY | O_OPEN, 0);
  if (fd < SUCCESS)
    return fd;

  result = dos_getfattr_fd(fd);
  dos_close(fd);
  return result;
}

COUNT dos_setfattr(BYTE * name, UWORD attrp)
{
  COUNT fd;
  f_node_ptr fnp;

  /* JPP-If user tries to set VOLID or DIR bits, return error */
  if ((attrp & (D_VOLID | D_DIR | 0xC0)) != 0)
    return DE_ACCESS;

  fd = (short)dos_open(name, O_RDONLY | O_OPEN, 0);
  if (fd < SUCCESS)
    return fd;

  fnp = xlt_fd(fd);
  
  /* Set the attribute from the fnode and return          */
  /* clear all attributes but DIR and VOLID */
  fnp->f_dir.dir_attrib &= (D_VOLID | D_DIR);   /* JPP */
    
  /* set attributes that user requested */
  fnp->f_dir.dir_attrib |= attrp;       /* JPP */
  fnp->f_flags |= F_DMOD | F_DDATE;
  save_far_f_node(fnp);
  dos_close(fd);
  return SUCCESS;
}
#endif

#ifdef WITHFAT32
VOID bpb_to_dpb(bpb FAR * bpbp, REG struct dpb FAR * dpbp, BOOL extended)
#else
VOID bpb_to_dpb(bpb FAR * bpbp, REG struct dpb FAR * dpbp)
#endif
{
  ULONG size;
  REG UWORD shftcnt;
  bpb sbpb;

  fmemcpy(&sbpb, bpbp, sizeof(sbpb));
  for (shftcnt = 0; (sbpb.bpb_nsector >> shftcnt) > 1; shftcnt++)
    ;
  dpbp->dpb_shftcnt = shftcnt;

  dpbp->dpb_mdb = sbpb.bpb_mdesc;
  dpbp->dpb_secsize = sbpb.bpb_nbyte;
  dpbp->dpb_clsmask = sbpb.bpb_nsector - 1;
  dpbp->dpb_fatstrt = sbpb.bpb_nreserved;
  dpbp->dpb_fats = sbpb.bpb_nfat;
  dpbp->dpb_dirents = sbpb.bpb_ndirent;
  size = sbpb.bpb_nsize == 0 ? sbpb.bpb_huge : (ULONG) sbpb.bpb_nsize;
  dpbp->dpb_fatsize = sbpb.bpb_nfsect;
  dpbp->dpb_dirstrt = dpbp->dpb_fatstrt + dpbp->dpb_fats * dpbp->dpb_fatsize;
  dpbp->dpb_data = dpbp->dpb_dirstrt
      + (dpbp->dpb_dirents + dpbp->dpb_secsize/DIRENT_SIZE - 1) /
          (dpbp->dpb_secsize/DIRENT_SIZE);
  dpbp->dpb_size = (UWORD)((size - dpbp->dpb_data) >> shftcnt) + 1;
  { /* Make sure the number of FAT sectors is actually enough to hold that */
    /* many clusters. Otherwise back the number of clusters down (LG & AB) */
    unsigned fatsiz;
    ULONG tmp = dpbp->dpb_fatsize * (ULONG)(dpbp->dpb_secsize / 2);/* entries/2 */
    if (tmp >= 0x10000UL)
      goto ckok;
    fatsiz = (unsigned) tmp;
    if (dpbp->dpb_size > FAT_MAGIC) {/* FAT16 */
      if (fatsiz <= FAT_MAGIC)       /* FAT12 - let it pass through rather */
        goto ckok;                   /* than lose data correcting FAT type */
    } else {                         /* FAT12 */
      if (fatsiz >= 0x4000)
        goto ckok;
      fatsiz = fatsiz * 4 / 3;
    }
    if (dpbp->dpb_size >= fatsiz)    /* FAT too short */
      dpbp->dpb_size = fatsiz - 1;   /* - 2 reserved entries + 1 */
ckok:;
  }
  dpbp->dpb_flags = 0;
  dpbp->dpb_cluster = UNKNCLUSTER;
  /* number of free clusters */
  dpbp->dpb_nfreeclst = UNKNCLSTFREE;

#ifdef WITHFAT32
  if (extended)
  {
    dpbp->dpb_xfatsize = sbpb.bpb_nfsect == 0 ? sbpb.bpb_xnfsect
        : sbpb.bpb_nfsect;
    dpbp->dpb_xcluster = UNKNCLUSTER;
    dpbp->dpb_xnfreeclst = XUNKNCLSTFREE;       /* number of free clusters */

    dpbp->dpb_xflags = 0;
    dpbp->dpb_xfsinfosec = 0xffff;
    dpbp->dpb_xbackupsec = 0xffff;
    dpbp->dpb_xrootclst = 0;
    dpbp->dpb_xdata = dpbp->dpb_data;
    dpbp->dpb_xsize = dpbp->dpb_size;

    if (ISFAT32(dpbp))
    {
      dpbp->dpb_xflags = sbpb.bpb_xflags;
      dpbp->dpb_xfsinfosec = sbpb.bpb_xfsinfosec;
      dpbp->dpb_xbackupsec = sbpb.bpb_xbackupsec;
      dpbp->dpb_dirents = 0;
      dpbp->dpb_dirstrt = 0xffff;
      dpbp->dpb_size = 0;
      dpbp->dpb_xdata =
          dpbp->dpb_fatstrt + dpbp->dpb_fats * dpbp->dpb_xfatsize;
      dpbp->dpb_xsize = ((size - dpbp->dpb_xdata) >> shftcnt) + 1;
      dpbp->dpb_xrootclst = sbpb.bpb_xrootclst;
      read_fsinfo(dpbp);
    }
  }
#endif
}

STATIC int rqblockio(unsigned char command, struct dpb FAR * dpbp)
{
 retry:
  MediaReqHdr.r_length = sizeof(request);
  MediaReqHdr.r_unit = dpbp->dpb_subunit;
  MediaReqHdr.r_command = command;
  MediaReqHdr.r_mcmdesc = dpbp->dpb_mdb;
  MediaReqHdr.r_status = 0;

  if (command == C_BLDBPB) /* help USBASPI.SYS & DI1000DD.SYS (TE) */
    MediaReqHdr.r_bpfat = (boot FAR *)DiskTransferBuffer;
  execrh((request FAR *) & MediaReqHdr, dpbp->dpb_device);
  if ((MediaReqHdr.r_status & S_ERROR) || !(MediaReqHdr.r_status & S_DONE))
  {
    FOREVER
    {
      switch (block_error(&MediaReqHdr, dpbp->dpb_unit, dpbp->dpb_device, 0))
      {
      case ABORT:
      case FAIL:
        return DE_INVLDDRV;

      case RETRY:
      

⌨️ 快捷键说明

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