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

📄 fatfs.c

📁 开源DOS的C代码源程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************/
/*                                                              */
/*                          fatfs.c                             */
/*                           DOS-C                              */
/*                                                              */
/*                 FAT File System I/O Functions                */
/*                                                              */
/*                    Copyright (c) 1995,1998                   */
/*                      Pasquale J. Villani                     */
/*                      All Rights Reserved                     */
/*                                                              */
/* This file is part of DOS-C.                                  */
/*                                                              */
/* DOS-C is free software; you can redistribute it and/or       */
/* modify it under the terms of the GNU General Public License  */
/* as published by the Free Software Foundation; either version */
/* 2, or (at your option) any later version.                    */
/*                                                              */
/* DOS-C is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of   */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See    */
/* the GNU General Public License for more details.             */
/*                                                              */
/* You should have received a copy of the GNU General Public    */
/* License along with DOS-C; see the file COPYING.  If not,     */
/* write to the Free Software Foundation, 675 Mass Ave,         */
/* Cambridge, MA 02139, USA.                                    */
/****************************************************************/

#include "portab.h"
#include "globals.h"

#ifdef VERSION_STRINGS
BYTE *RcsId = "$Id: fatfs.c,v 1.70 2004/05/23 15:10:08 bartoldeman Exp $";
#endif

/*                                                                      */
/*      function prototypes                                             */
/*                                                                      */
f_node_ptr xlt_fd(COUNT);
COUNT xlt_fnp(f_node_ptr);
STATIC void save_far_f_node(f_node_ptr fnp);
STATIC f_node_ptr get_near_f_node(void);
STATIC f_node_ptr split_path(char *, char *);
BOOL find_fname(f_node_ptr, char *, int);
    /* /// Added - Ron Cemer */
STATIC void merge_file_changes(f_node_ptr fnp, int collect);
    /* /// Added - Ron Cemer */
STATIC int is_same_file(f_node_ptr fnp1, f_node_ptr fnp2);
    /* /// Added - Ron Cemer */
STATIC void copy_file_changes(f_node_ptr src, f_node_ptr dst);
BOOL find_free(f_node_ptr);
STATIC int alloc_find_free(f_node_ptr fnp, char *path, char *fcbname);
VOID wipe_out(f_node_ptr);
CLUSTER extend(f_node_ptr);
COUNT extend_dir(f_node_ptr);
CLUSTER first_fat(f_node_ptr);
COUNT map_cluster(f_node_ptr, COUNT);
STATIC VOID shrink_file(f_node_ptr fnp);

/* FAT time notation in the form of hhhh hmmm mmmd dddd (d = double second) */
STATIC time time_encode(struct dostime *t)
{
  return (t->hour << 11) | (t->minute << 5) | (t->second >> 1);
}

#ifdef WITHFAT32
CLUSTER getdstart(struct dpb FAR *dpbp, struct dirent *dentry)
{
  if (!ISFAT32(dpbp))
    return dentry->dir_start;
  return (((CLUSTER)dentry->dir_start_high << 16) | dentry->dir_start);
}

void setdstart(struct dpb FAR *dpbp, struct dirent *dentry, CLUSTER value)
{
  dentry->dir_start = (UWORD)value;
  if (ISFAT32(dpbp))
    dentry->dir_start_high = (UWORD)(value >> 16);
}

BOOL checkdstart(struct dpb FAR *dpbp, struct dirent *dentry, CLUSTER value)
{
  if (!ISFAT32(dpbp))
    return dentry->dir_start == (UWORD)value;
  return (dentry->dir_start == (UWORD)value &&
          dentry->dir_start_high == (UWORD)(value >> 16));
}
#endif

ULONG clus2phys(CLUSTER cl_no, struct dpb FAR * dpbp)
{
  CLUSTER data =
#ifdef WITHFAT32
      ISFAT32(dpbp) ? dpbp->dpb_xdata :
#endif
      dpbp->dpb_data;
  return ((ULONG) (cl_no - 2) << dpbp->dpb_shftcnt) + data;
}

struct dpb FAR *get_dpb(COUNT dsk)
{
  register struct cds FAR *cdsp = get_cds(dsk);
  
  if (cdsp == NULL || cdsp->cdsFlags & CDSNETWDRV)
    return NULL;
  return cdsp->cdsDpb;
}

/* initialize all direntry fields except for the name */
STATIC void init_direntry(struct dirent *dentry, unsigned attrib,
                          CLUSTER cluster)
{
  struct dostime dt;

  dentry->dir_size = 0l;
#ifdef WITHFAT32
  dentry->dir_start_high = (UWORD)(cluster >> 16);
#else
  dentry->dir_start_high = 0;
#endif
  dentry->dir_start = (UWORD)cluster;
  dentry->dir_attrib = attrib;
  dentry->dir_case = 0;
  DosGetTime(&dt);
  dentry->dir_crtimems = dt.hundredth;
  if (dt.second & 1)
    dentry->dir_crtimems += 100;
  dentry->dir_time = dentry->dir_crtime = time_encode(&dt);
  dentry->dir_date = dentry->dir_crdate = dentry->dir_accdate = dos_getdate();
}

/************************************************************************/
/*                                                                      */
/*      Internal file handlers - open, create, read, write, close, etc. */
/*                                                                      */
/************************************************************************/

/* Open a file given the path. Flags is 0 for read, 1 for write and 2   */
/* for update.                                                          */
/* Returns an long where the high word is a status code and the low     */
/* word is an integer file descriptor or a negative error code          */
/* see DosOpenSft(), dosfns.c for an explanation of the flags bits      */
/* directory opens are allowed here; these are not allowed by DosOpenSft*/

long dos_open(char *path, unsigned flags, unsigned attrib)
{
  REG f_node_ptr fnp;
  char fcbname[FNAME_SIZE + FEXT_SIZE];
  int status = S_OPENED;

  /* First test the flags to see if the user has passed a valid   */
  /* file mode...                                                 */
  if ((flags & O_ACCMODE) > 2)
    return DE_INVLDACC;

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

  /* Check that we don't have a duplicate name, so if we  */
  /* find one, truncate it (O_CREAT).                     */
  if (find_fname(fnp, fcbname, D_ALL | attrib))
  {
    if (flags & O_TRUNC)
    {
      /* The only permissable attribute is archive,   */
      /* check for any other bit set. If it is, give  */
      /* an access error.                             */
      if ((fnp->f_dir.dir_attrib & (D_RDONLY | D_DIR | D_VOLID))
          || (fnp->f_dir.dir_attrib & ~D_ARCHIVE & ~attrib))
      {
        dir_close(fnp);
        return DE_ACCESS;
      }
      
      /* Release the existing files FAT and set the   */
      /* length to zero, effectively truncating the   */
      /* file to zero.                                */
      wipe_out(fnp);
      status = S_REPLACED;
    }
    else if (flags & O_OPEN)
    {
      /* force r/o open for FCB if the file is read-only */
      if ((flags & O_FCB) && (fnp->f_dir.dir_attrib & D_RDONLY))
        flags = (flags & ~3) | O_RDONLY;

      /* Check permissions. -- JPP */
      if ((fnp->f_dir.dir_attrib & D_RDONLY) &&
          ((flags & O_ACCMODE) != O_RDONLY))
      {
        dir_close(fnp);
        return DE_ACCESS;
      }
    }
    else
    {
      dir_close(fnp);
      return DE_FILEEXISTS;
    }
  }
  else if (flags & O_CREAT)
  {
    int ret = alloc_find_free(fnp, path, fcbname);
    if (ret != SUCCESS)
      return ret;

    /* put the fnode's name into the directory.             */
    memcpy(fnp->f_dir.dir_name, fcbname, FNAME_SIZE + FEXT_SIZE);
    status = S_CREATED;
  }
  else
  {
    /* open: If we can't find the file, just return a not    */
    /* found error.                                          */
    dir_close(fnp);
    return DE_FILENOTFND;
  }
  
  /* Set the fnode to the desired mode                    */
  /* Updating the directory entry first.                  */
  fnp->f_mode = flags & O_ACCMODE;

  if (status != S_OPENED)
  {
    init_direntry(&fnp->f_dir, attrib, FREE);
    fnp->f_flags = F_DMOD | F_DDIR;
    if (!dir_write(fnp))
    {
      release_f_node(fnp);
      return DE_ACCESS;
    }
  }

  /* Now change to file                                   */
  fnp->f_offset = 0l;

  if (status != S_OPENED)
  {
    fnp->f_cluster = FREE;
    setdstart(fnp->f_dpb, &fnp->f_dir, FREE);
    fnp->f_cluster_offset = 0;
  }

  fnp->f_flags = 0;
  if (status != S_OPENED)
    fnp->f_flags = F_DMOD;

  merge_file_changes(fnp, status == S_OPENED); /* /// Added - Ron Cemer */
  /* /// Moved from above.  - Ron Cemer */
  fnp->f_cluster = getdstart(fnp->f_dpb, &fnp->f_dir);
  fnp->f_cluster_offset = 0;

  save_far_f_node(fnp);
  return xlt_fnp(fnp) | ((long)status << 16);
}

BOOL fcmp_wild(const char * s1, const char * s2, unsigned n)
{
  for ( ; n--; ++s1, ++s2)
    if (*s1 != '?' && *s1 != *s2)
      return FALSE;
  return TRUE;
}

COUNT dos_close(COUNT fd)
{
  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 DE_INVLDHNDL;

  if (fnp->f_flags & F_DMOD)
  {
    if (!(fnp->f_flags & F_DDATE))
    {
      fnp->f_dir.dir_time = dos_gettime();
      fnp->f_dir.dir_date = dos_getdate();
    }

    merge_file_changes(fnp, FALSE);     /* /// Added - Ron Cemer */
  }
  fnp->f_flags |= F_DDIR;

  dir_close(fnp);
  return SUCCESS;
}

COUNT dos_commit(COUNT fd)
{
  f_node_ptr fnp, fnp2;

  /* 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 DE_INVLDHNDL;
  fnp2 = get_f_node();
  if (fnp2 == (f_node_ptr) 0)
  {
    release_near_f_node(fnp);
    return DE_INVLDHNDL;
  }

  /* a copy of the fnode is closed meaning that the directory info
     is updated etc, but we keep our old info */
  memcpy(fnp2, fnp, sizeof(*fnp));
  save_far_f_node(fnp2);
  release_near_f_node(fnp);
  return dos_close(xlt_fnp(fnp2));
}

/*                                                                      */
/* split a path into it's component directory and file name             */
/*                                                                      */
f_node_ptr split_path(char * path, char * fcbname)
{
  REG f_node_ptr fnp;

  /* Start off by parsing out the components.                     */ 
  int dirlength = ParseDosName(path, fcbname, FALSE);

  if (dirlength < SUCCESS)
    return (f_node_ptr) 0;

/*  11/29/99 jt
   * Networking and Cdroms. You can put in here a return.
   * Maybe a return of 0xDEADBEEF or something for Split or Dir_open.
   * Just to let upper level Fdos know its a sft, CDS function.
   * Right now for Networking there is no support for Rename, MkDir
   * RmDir & Delete.

   <insert code here or in dir_open. I would but it in Dir_open.
   Do the redirection in Network.c>

 */
#ifdef DEBUG
  if (get_cds(path[0]-'A')->cdsFlags & CDSNETWDRV)
  {
    printf("split path called for redirected file: `%s'\n",
           fcbname);
    return (f_node_ptr) 0;
  }
#endif

  /* Translate the path into a useful pointer                     */
  {
    char tmp = path[dirlength];
    path[dirlength] = '\0';
    fnp = dir_open(path);
    path[dirlength] = tmp;
  } 

  /* 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 || fnp->f_count <= 0)
  {
    dir_close(fnp);
    return (f_node_ptr) 0;
  }

  return fnp;
}

/* checks whether directory part of path exists */
BOOL dir_exists(char * path)
{
  REG f_node_ptr fnp;
  char fcbname[FNAME_SIZE + FEXT_SIZE];

  if ((fnp = split_path(path, fcbname)) == NULL)
    return FALSE;
  
  dir_close(fnp);
  return TRUE;
}

BOOL fcbmatch(const char *fcbname1, const char *fcbname2)
{
  return memcmp(fcbname1, fcbname2, FNAME_SIZE + FEXT_SIZE) == 0;
}

STATIC BOOL find_fname(f_node_ptr fnp, char *fcbname, int attr)
{
  while (dir_read(fnp) == 1)
  {
    if (fcbmatch(fnp->f_dir.dir_name, fcbname)
        && (fnp->f_dir.dir_attrib & ~(D_RDONLY | D_ARCHIVE | attr)) == 0)
    {
      return TRUE;
    }
    fnp->f_diroff++;
  }
  return FALSE;
}

/* Description.
 *  Remove entries with D_LFN attribute preceeding the directory entry
 *  pointed by fnp, fnode isn't modified (I hope).
 * Return value. 
 *  SUCCESS     - completed successfully.
 *  DE_BLKINVLD - error occured, fnode is released.
 * input: fnp with valid non-LFN directory entry, not equal to '..' or
 *  '.'
 */
COUNT remove_lfn_entries(f_node_ptr fnp)
{
  unsigned original_diroff = fnp->f_diroff;

⌨️ 快捷键说明

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