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

📄 fatfs.c

📁 开源DOS的C代码源程序
💻 C
📖 第 1 页 / 共 5 页
字号:
    {
      /* Otherwise just expand the directory          */
      int ret;

      if ((ret = extend_dir(fnp)) != SUCCESS)
        /* fnp already closed in extend_dir */
        return ret;
    }
  }
  return SUCCESS;
}


/*                                                              */
/* dos_getdate for the file date                                */
/*                                                              */
date dos_getdate(void)
{
  struct dosdate dd;

  /* First - get the system date set by either the user   */
  /* on start-up or the CMOS clock                        */
  DosGetDate(&dd);
  return DT_ENCODE(dd.month, dd.monthday, dd.year - EPOCH_YEAR);
}

/*                                                              */
/* dos_gettime for the file time                                */
/*                                                              */
time dos_gettime(void)
{
  struct dostime dt;

  /* First - get the system time set by either the user   */
  /* on start-up or the CMOS clock                        */
  DosGetTime(&dt);
  return time_encode(&dt);
}

/*                                                              */
/* dos_getftime for the file time                               */
/*                                                              */
COUNT dos_getftime(COUNT fd, date FAR * dp, time FAR * tp)
{
  f_node_ptr fnp;

  /* 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 DE_INVLDHNDL;

  /* Get the date and time from the fnode and return              */
  *dp = fnp->f_dir.dir_date;
  *tp = fnp->f_dir.dir_time;

  release_near_f_node(fnp);
  return SUCCESS;
}

/*                                                              */
/* dos_setftime for the file time                               */
/*                                                              */
COUNT dos_setftime(COUNT fd, date dp, time tp)
{
  f_node_ptr fnp;

  /* 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 DE_INVLDHNDL;

  /* Set the date and time from the fnode and return              */
  fnp->f_dir.dir_date = dp;
  fnp->f_dir.dir_time = tp;
  /* mark file as modified and set this date upon closing */
  fnp->f_flags |= F_DMOD | F_DDATE;

  save_far_f_node(fnp);
  return SUCCESS;
}

/*                                                              */
/* dos_getfsize for the file time                               */
/*                                                              */
ULONG dos_getfsize(COUNT fd)
{
  f_node_ptr fnp;

  /* 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 (ULONG)-1l;

  /* Return the file size                                         */
  release_near_f_node(fnp);
  return fnp->f_dir.dir_size;
}

/*                                                              */
/* dos_setfsize for the file time                               */
/*                                                              */
BOOL dos_setfsize(COUNT fd, LONG size)
{
  f_node_ptr fnp;

  /* 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 FALSE;

  /* Change the file size                                         */
  fnp->f_dir.dir_size = size;

  merge_file_changes(fnp, FALSE);       /* /// Added - Ron Cemer */
  save_far_f_node(fnp);

  return TRUE;
}

/*                                                              */
/* Find free cluster in disk FAT table                          */
/*                                                              */
STATIC CLUSTER find_fat_free(f_node_ptr fnp)
{
  REG CLUSTER idx, size;
  struct dpb FAR *dpbp = fnp->f_dpb;

#ifdef DISPLAY_GETBLOCK
  printf("[find_fat_free]\n");
#endif

  /* Start from optimized lookup point for start of FAT   */
  idx = 2;
  size = dpbp->dpb_size;

#ifdef WITHFAT32
  if (ISFAT32(dpbp))
  {
    if (dpbp->dpb_xcluster != UNKNCLUSTER)
      idx = dpbp->dpb_xcluster;
    size = dpbp->dpb_xsize;
  }
  else
#endif
  if (dpbp->dpb_cluster != UNKNCLUSTER)
    idx = dpbp->dpb_cluster;

  /* Search the FAT table looking for the first free      */
  /* entry.                                               */
  for (; idx <= size; idx++)
  {
    if (next_cluster(dpbp, idx) == FREE)
      break;
  }

#ifdef WITHFAT32
  if (ISFAT32(dpbp))
  {
    dpbp->dpb_xcluster = idx;
    if (idx > size)
    {
      /* No empty clusters, disk is FULL!                     */
      dpbp->dpb_xcluster = UNKNCLUSTER;
      idx = LONG_LAST_CLUSTER;
    }
    /* return the free entry                                */
    write_fsinfo(dpbp);
    return idx;
  }
#endif

  dpbp->dpb_cluster = (UWORD)idx;
  if ((UWORD)idx > (UWORD)size)
  {
    /* No empty clusters, disk is FULL!                     */
    dpbp->dpb_cluster = UNKNCLUSTER;
    idx = LONG_LAST_CLUSTER;
  }
  /* return the free entry                                */
  return idx;
}

/*                                                              */
/* create a directory - returns success or a negative error     */
/* number                                                       */
/*                                                              */
COUNT dos_mkdir(BYTE * dir)
{
  REG f_node_ptr fnp;
  REG COUNT idx;
  struct buffer FAR *bp;
  struct dpb FAR *dpbp;
  CLUSTER free_fat, parent;
  COUNT ret;
  char fcbname[FNAME_SIZE + FEXT_SIZE];

  /* first split the passed dir into components (i.e. -   */
  /* path to new directory and name of new directory      */
  if ((fnp = split_path(dir, fcbname)) == NULL)
  {
    return DE_PATHNOTFND;
  }

  /* check that the resulting combined path does not exceed
     the 67 MAX_CDSPATH limit. this leads to problems:
     A) you can't CD to this directory later
     B) you can't create files in this subdirectory
     C) the created dir will not be found later, so you
     can create an unlimited amount of same dirs. this space
     is lost forever
   */
  if (strlen(dir) >= MAX_CDSPATH)  /* dir is already output of "truename" */
  {
    dir_close(fnp);
    return DE_PATHNOTFND;
  }

  /* Check that we don't have a duplicate name, so if we  */
  /* find one, it's an error.                             */
  if (find_fname(fnp, fcbname, D_ALL))
  {
    dir_close(fnp);
    return DE_ACCESS;
  }

  parent = fnp->f_dirstart;

  ret = alloc_find_free(fnp, dir, fcbname);
  if (ret != SUCCESS)
    return ret;

  /* get an empty cluster, so that we make it into a      */
  /* directory.                                           */
  /* TE this has to be done (and failed) BEFORE the dir entry */
  /* is changed                                           */
  free_fat = find_fat_free(fnp);

  /* No empty clusters, disk is FULL! Translate into a    */
  /* useful error message.                                */
  if (free_fat == LONG_LAST_CLUSTER)
  {
    dir_close(fnp);
    return DE_HNDLDSKFULL;
  }

  /* put the fnode's name into the directory.             */
  memcpy(fnp->f_dir.dir_name, fcbname, FNAME_SIZE + FEXT_SIZE);

  /* Set the fnode to the desired mode                            */
  fnp->f_mode = WRONLY;

  init_direntry(&fnp->f_dir, D_DIR, free_fat);

  fnp->f_flags = F_DMOD | F_DDIR;

  fnp->f_offset = 0l;

  /* Mark the cluster in the FAT as used                  */
  dpbp = fnp->f_dpb;
  link_fat(dpbp, free_fat, LONG_LAST_CLUSTER);

  /* Craft the new directory. Note that if we're in a new */
  /* directory just under the root, ".." pointer is 0.    */
  /* as we are overwriting it completely, don't read first */
  bp = getblockOver(clus2phys(free_fat, dpbp), dpbp->dpb_unit);
#ifdef DISPLAY_GETBLOCK
  printf("FAT (dos_mkdir)\n");
#endif
  if (bp == NULL)
  {
    dir_close(fnp);
    return DE_BLKINVLD;
  }

  /* Create the "." entry                                 */
  DirEntBuffer.dir_name[0] = '.';
  memset(DirEntBuffer.dir_name + 1, ' ', FNAME_SIZE + FEXT_SIZE - 1);
  init_direntry(&DirEntBuffer, D_DIR, free_fat);

  /* And put it out                                       */
  putdirent(&DirEntBuffer, bp->b_buffer);

  /* create the ".." entry                                */
  DirEntBuffer.dir_name[1] = '.';
#ifdef WITHFAT32
  if (ISFAT32(dpbp) && parent == dpbp->dpb_xrootclst)
  {
    parent = 0;
  }
#endif
  setdstart(dpbp, &DirEntBuffer, parent);

  /* and put it out                                       */
  putdirent(&DirEntBuffer, &bp->b_buffer[DIRENT_SIZE]);

  /* fill the rest of the block with zeros                */
  fmemset(&bp->b_buffer[2 * DIRENT_SIZE], 0, BUFFERSIZE - 2 * DIRENT_SIZE);

  /* Mark the block to be written out                     */
  bp->b_flag |= BFR_DIRTY | BFR_VALID;

  /* clear out the rest of the blocks in the cluster      */
  for (idx = 1; idx <= dpbp->dpb_clsmask; idx++)
  {

    /* as we are overwriting it completely, don't read first */
    bp = getblockOver(clus2phys(getdstart(dpbp, &fnp->f_dir), dpbp) + idx,
                      dpbp->dpb_unit);
#ifdef DISPLAY_GETBLOCK
    printf("DIR (dos_mkdir)\n");
#endif
    if (bp == NULL)
    {
      dir_close(fnp);
      return DE_BLKINVLD;
    }
    fmemset(bp->b_buffer, 0, BUFFERSIZE);
    bp->b_flag |= BFR_DIRTY | BFR_VALID | BFR_UNCACHE; /* need not be cached */
  }

  /* flush the drive buffers so that all info is written  */
  /* hazard: no error checking! */
  flush_buffers(dpbp->dpb_unit);

  /* Close the directory so that the entry is updated     */
  fnp->f_flags |= F_DMOD;
  dir_close(fnp);

  return SUCCESS;
}

STATIC CLUSTER extend(f_node_ptr fnp)
{
  CLUSTER free_fat;

  /* get an empty cluster, so that we use it to extend the file.  */
  free_fat = find_fat_free(fnp);

  /* No empty clusters, disk is FULL! Translate into a useful     */
  /* error message.                                               */
  if (free_fat == LONG_LAST_CLUSTER)
    return free_fat;

  /* Now that we've found a free FAT entry, mark it as the last   */
  /* entry and save.                                              */
  if (fnp->f_cluster == FREE)
    setdstart(fnp->f_dpb, &fnp->f_dir, free_fat);
  else
    link_fat(fnp->f_dpb, fnp->f_cluster, free_fat);
  link_fat(fnp->f_dpb, free_fat, LONG_LAST_CLUSTER);

  /* Mark the directory so that the entry is updated              */
  fnp->f_flags |= F_DMOD;
  return free_fat;
}

STATIC COUNT extend_dir(f_node_ptr fnp)
{
  REG COUNT idx;

  CLUSTER cluster = extend(fnp);
  if (cluster == LONG_LAST_CLUSTER)
  {
    dir_close(fnp);
    return DE_HNDLDSKFULL;
  }

  /* clear out the blocks in the cluster      */
  for (idx = 0; idx <= fnp->f_dpb->dpb_clsmask; idx++)
  {
    REG struct buffer FAR *bp;

    /* as we are overwriting it completely, don't read first */
    bp = getblockOver(clus2phys(cluster, fnp->f_dpb) + idx,
                      fnp->f_dpb->dpb_unit);
#ifdef DISPLAY_GETBLOCK
    printf("DIR (extend_dir)\n");
#endif
    if (bp == NULL)
    {
      dir_close(fnp);
      return DE_BLKINVLD;
    }
    fmemset(bp->b_buffer, 0, BUFFERSIZE);
    bp->b_flag |= BFR_DIRTY | BFR_VALID;

    if (idx != 0)
      bp->b_flag |= BFR_UNCACHE;        /* needs not be cached */
  }

  if (!find_free(fnp))
  {
    dir_close(fnp);
    return DE_HNDLDSKFULL;
  }

  /* flush the drive buffers so that all info is written          */
  /* hazard: no error checking! */
  flush_buffers(fnp->f_dpb->dpb_unit);

  return SUCCESS;

⌨️ 快捷键说明

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