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

📄 fatfs.c

📁 GNU FreeDOS兼容MS DOS很好的东东.
💻 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_STRINGSBYTE *RcsId = "$Id: fatfs.c,v 1.74 2005/04/10 15:00:37 perditionc 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 WITHFAT32CLUSTER 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));}#endifULONG 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 directory entry (creation/access stamps 0 as per MS-DOS 7.10) */STATIC void init_direntry(struct dirent *dentry, unsigned attrib,                          CLUSTER cluster, char *name){  dentry->dir_size = 0l;  memset(dentry, 0, sizeof(struct dirent));  memcpy(dentry->dir_name, name, FNAME_SIZE + FEXT_SIZE);#ifdef WITHFAT32  dentry->dir_start_high = (UWORD)(cluster >> 16);#endif  dentry->dir_start = (UWORD)cluster;  dentry->dir_attrib = (UBYTE)attrib;  dentry->dir_time = dos_gettime();  dentry->dir_date = 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;  /* next 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;    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, fcbname);    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;  while (TRUE)  {    if (fnp->f_diroff == 0)      break;    fnp->f_diroff--;    if (dir_read(fnp) <= 0) {      dir_close(fnp);      return DE_BLKINVLD;    }    if (fnp->f_dir.dir_attrib != D_LFN)      break;    fnp->f_dir.dir_name[0] = DELETED;    fnp->f_flags |= F_DMOD;    if (!dir_write(fnp)) return DE_BLKINVLD;  }  fnp->f_diroff = original_diroff;  if (dir_read(fnp) <= 0) {    dir_close(fnp);    return DE_BLKINVLD;  }  return SUCCESS;}    /* /// Added - Ron Cemer */

⌨️ 快捷键说明

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