📄 fatfs.c
字号:
/****************************************************************//* *//* 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 + -