2000-05-06 21:34:20 +02:00
|
|
|
/****************************************************************/
|
|
|
|
/* */
|
|
|
|
/* 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$";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* */
|
|
|
|
/* function prototypes */
|
|
|
|
/* */
|
2001-07-10 00:19:33 +02:00
|
|
|
f_node_ptr xlt_fd(COUNT);
|
2001-06-03 16:16:18 +02:00
|
|
|
COUNT xlt_fnp(f_node_ptr);
|
2002-08-04 03:14:18 +02:00
|
|
|
STATIC f_node_ptr split_path(char *, char *);
|
|
|
|
BOOL find_fname(f_node_ptr, char *, int);
|
2000-10-30 00:51:56 +01:00
|
|
|
/* /// Added - Ron Cemer */
|
2001-06-03 16:16:18 +02:00
|
|
|
STATIC void merge_file_changes(f_node_ptr fnp, int collect);
|
2000-10-30 00:51:56 +01:00
|
|
|
/* /// Added - Ron Cemer */
|
2001-06-03 16:16:18 +02:00
|
|
|
STATIC int is_same_file(f_node_ptr fnp1, f_node_ptr fnp2);
|
2000-10-30 00:51:56 +01:00
|
|
|
/* /// Added - Ron Cemer */
|
2001-06-03 16:16:18 +02:00
|
|
|
STATIC void copy_file_changes(f_node_ptr src, f_node_ptr dst);
|
|
|
|
BOOL find_free(f_node_ptr);
|
2004-03-23 02:36:16 +01:00
|
|
|
STATIC int alloc_find_free(f_node_ptr fnp, char *path, char *fcbname);
|
2001-06-03 16:16:18 +02:00
|
|
|
VOID wipe_out(f_node_ptr);
|
2004-03-22 23:33:05 +01:00
|
|
|
CLUSTER extend(f_node_ptr);
|
2001-06-03 16:16:18 +02:00
|
|
|
COUNT extend_dir(f_node_ptr);
|
2004-03-22 23:33:05 +01:00
|
|
|
CLUSTER first_fat(f_node_ptr);
|
2001-06-03 16:16:18 +02:00
|
|
|
COUNT map_cluster(f_node_ptr, COUNT);
|
2001-07-10 00:19:33 +02:00
|
|
|
STATIC VOID shrink_file(f_node_ptr fnp);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-01-26 01:51:49 +01:00
|
|
|
#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)
|
|
|
|
{
|
|
|
|
if (!ISFAT32(dpbp))
|
|
|
|
{
|
|
|
|
dentry->dir_start = (UWORD)value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dentry->dir_start = (UWORD)value;
|
|
|
|
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
|
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
ULONG clus2phys(CLUSTER cl_no, struct dpb FAR * dpbp)
|
2001-11-04 20:47:39 +01:00
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
CLUSTER data =
|
2001-11-04 20:47:39 +01:00
|
|
|
#ifdef WITHFAT32
|
2001-11-18 15:01:12 +01:00
|
|
|
ISFAT32(dpbp) ? dpbp->dpb_xdata :
|
2001-11-04 20:47:39 +01:00
|
|
|
#endif
|
|
|
|
dpbp->dpb_data;
|
2001-11-18 15:01:12 +01:00
|
|
|
return ((ULONG) (cl_no - 2) << dpbp->dpb_shftcnt) + data;
|
2001-11-04 20:47:39 +01:00
|
|
|
}
|
|
|
|
|
2002-10-22 04:40:19 +02:00
|
|
|
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;
|
2004-01-26 01:51:49 +01:00
|
|
|
#ifdef WITHFAT32
|
|
|
|
dentry->dir_start_high = (UWORD)(cluster >> 16);
|
|
|
|
#else
|
2002-10-22 04:40:19 +02:00
|
|
|
dentry->dir_start_high = 0;
|
2004-01-26 01:51:49 +01:00
|
|
|
#endif
|
|
|
|
dentry->dir_start = (UWORD)cluster;
|
2002-10-22 04:40:19 +02:00
|
|
|
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 =
|
|
|
|
TM_ENCODE(dt.hour, dt.minute, dt.second >> 1);
|
|
|
|
dentry->dir_date = dentry->dir_crdate = dentry->dir_accdate = dos_getdate();
|
|
|
|
}
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* 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. */
|
2002-08-04 03:14:18 +02:00
|
|
|
/* 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*/
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
long dos_open(char *path, unsigned flags, unsigned attrib)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
REG f_node_ptr fnp;
|
2002-08-04 03:14:18 +02:00
|
|
|
char fcbname[FNAME_SIZE + FEXT_SIZE];
|
|
|
|
int status = S_OPENED;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
/* First test the flags to see if the user has passed a valid */
|
2000-05-06 21:34:20 +02:00
|
|
|
/* file mode... */
|
2002-08-04 03:14:18 +02:00
|
|
|
if ((flags & 3) > 2)
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_INVLDACC;
|
|
|
|
|
|
|
|
/* first split the passed dir into comopnents (i.e. - path to */
|
|
|
|
/* new directory and name of new directory. */
|
2002-08-04 03:14:18 +02:00
|
|
|
if ((fnp = split_path(path, fcbname)) == NULL)
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_PATHNOTFND;
|
2002-08-04 03:14:18 +02:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
2003-11-23 19:03:35 +01:00
|
|
|
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 & 3) != O_RDONLY))
|
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_ACCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2002-08-04 03:14:18 +02:00
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_FILEEXISTS;
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2002-08-04 03:14:18 +02:00
|
|
|
else if (flags & O_CREAT)
|
|
|
|
{
|
2004-03-23 02:36:16 +01:00
|
|
|
int ret = alloc_find_free(fnp, path, fcbname);
|
|
|
|
if (ret != SUCCESS)
|
|
|
|
return ret;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
/* put the fnode's name into the directory. */
|
|
|
|
memcpy(fnp->f_dir.dir_name, fcbname, FNAME_SIZE + FEXT_SIZE);
|
|
|
|
status = S_CREATED;
|
|
|
|
}
|
|
|
|
else
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-08-04 03:14:18 +02:00
|
|
|
/* open: If we can't find the file, just return a not */
|
|
|
|
/* found error. */
|
2000-05-06 21:34:20 +02:00
|
|
|
dir_close(fnp);
|
|
|
|
return DE_FILENOTFND;
|
|
|
|
}
|
2002-08-04 03:14:18 +02:00
|
|
|
|
|
|
|
/* Set the fnode to the desired mode */
|
|
|
|
/* Updating the directory entry first. */
|
|
|
|
fnp->f_mode = flags & 3;
|
|
|
|
|
|
|
|
if (status != S_OPENED)
|
2002-10-22 04:40:19 +02:00
|
|
|
{
|
|
|
|
init_direntry(&fnp->f_dir, attrib, FREE);
|
2002-08-04 03:14:18 +02:00
|
|
|
fnp->f_flags.f_dmod = TRUE;
|
|
|
|
fnp->f_flags.f_ddate = FALSE;
|
|
|
|
fnp->f_flags.f_dnew = FALSE;
|
|
|
|
fnp->f_flags.f_ddir = TRUE;
|
|
|
|
if (!dir_write(fnp))
|
|
|
|
{
|
|
|
|
release_f_node(fnp);
|
|
|
|
return DE_ACCESS;
|
|
|
|
}
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
/* Now change to file */
|
2000-05-06 21:34:20 +02:00
|
|
|
fnp->f_offset = 0l;
|
2004-03-22 23:33:05 +01:00
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
if (status != S_OPENED)
|
|
|
|
{
|
|
|
|
fnp->f_cluster = FREE;
|
2004-01-26 01:51:49 +01:00
|
|
|
setdstart(fnp->f_dpb, &fnp->f_dir, FREE);
|
2002-12-09 01:17:15 +01:00
|
|
|
fnp->f_cluster_offset = 0;
|
2002-08-04 03:14:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fnp->f_flags.f_dmod = (status != S_OPENED);
|
|
|
|
fnp->f_flags.f_ddate = FALSE;
|
2000-05-06 21:34:20 +02:00
|
|
|
fnp->f_flags.f_dnew = FALSE;
|
|
|
|
fnp->f_flags.f_ddir = FALSE;
|
2002-08-04 03:14:18 +02:00
|
|
|
|
|
|
|
merge_file_changes(fnp, status == S_OPENED); /* /// Added - Ron Cemer */
|
2001-11-18 15:01:12 +01:00
|
|
|
/* /// Moved from above. - Ron Cemer */
|
2004-01-26 01:51:49 +01:00
|
|
|
fnp->f_cluster = getdstart(fnp->f_dpb, &fnp->f_dir);
|
2002-12-09 01:17:15 +01:00
|
|
|
fnp->f_cluster_offset = 0;
|
2000-10-30 00:51:56 +01:00
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
return xlt_fnp(fnp) | ((long)status << 16);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
BOOL fcmp_wild(const char * s1, const char * s2, unsigned n)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (*s1 == '?')
|
|
|
|
{
|
|
|
|
++s1, ++s2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*s1++ != *s2++)
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
COUNT dos_close(COUNT fd)
|
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
f_node_ptr fnp;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* 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 */
|
2001-11-18 15:01:12 +01:00
|
|
|
if (fnp == (f_node_ptr) 0 || fnp->f_count <= 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_INVLDHNDL;
|
|
|
|
|
2001-08-19 14:58:36 +02:00
|
|
|
if (fnp->f_flags.f_dmod)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-08-19 14:58:36 +02:00
|
|
|
if (fnp->f_flags.f_ddate == FALSE)
|
|
|
|
{
|
|
|
|
fnp->f_dir.dir_time = dos_gettime();
|
|
|
|
fnp->f_dir.dir_date = dos_getdate();
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
fnp->f_flags.f_ddir = TRUE;
|
|
|
|
|
|
|
|
dir_close(fnp);
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2002-01-23 23:29:41 +01:00
|
|
|
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 || fnp->f_count <= 0)
|
|
|
|
return DE_INVLDHNDL;
|
|
|
|
fnp2 = get_f_node();
|
|
|
|
if (fnp2 == (f_node_ptr) 0)
|
|
|
|
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));
|
|
|
|
return dos_close(xlt_fnp(fnp2));
|
|
|
|
}
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* */
|
|
|
|
/* split a path into it's component directory and file name */
|
|
|
|
/* */
|
2002-08-04 03:14:18 +02:00
|
|
|
f_node_ptr split_path(char * path, char * fcbname)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
REG f_node_ptr fnp;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
/* Start off by parsing out the components. */
|
|
|
|
int dirlength = ParseDosName(path, fcbname, FALSE);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
if (dirlength < SUCCESS)
|
2001-11-18 15:01:12 +01:00
|
|
|
return (f_node_ptr) 0;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* 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>
|
|
|
|
|
|
|
|
*/
|
2000-05-08 06:30:00 +02:00
|
|
|
#ifdef DEBUG
|
2002-10-22 04:40:19 +02:00
|
|
|
if (get_cds(path[0]-'A')->cdsFlags & CDSNETWDRV)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2002-08-04 12:26:31 +02:00
|
|
|
printf("split path called for redirected file: `%s'\n",
|
|
|
|
fcbname);
|
2001-11-18 15:01:12 +01:00
|
|
|
return (f_node_ptr) 0;
|
2000-05-08 06:30:00 +02:00
|
|
|
}
|
|
|
|
#endif
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Translate the path into a useful pointer */
|
2002-08-04 03:14:18 +02:00
|
|
|
{
|
|
|
|
char tmp = path[dirlength];
|
|
|
|
path[dirlength] = '\0';
|
|
|
|
fnp = dir_open(path);
|
|
|
|
path[dirlength] = tmp;
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* 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 */
|
2001-11-18 15:01:12 +01:00
|
|
|
if (fnp == (f_node_ptr) 0 || fnp->f_count <= 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
dir_close(fnp);
|
2001-11-18 15:01:12 +01:00
|
|
|
return (f_node_ptr) 0;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return fnp;
|
|
|
|
}
|
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
/* 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)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-11-04 20:47:39 +01:00
|
|
|
while (dir_read(fnp) == 1)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-08-04 03:14:18 +02:00
|
|
|
if (fcbmatch(fnp->f_dir.dir_name, fcbname)
|
2002-05-09 00:49:35 +02:00
|
|
|
&& (fnp->f_dir.dir_attrib & ~(D_RDONLY | D_ARCHIVE | attr)) == 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-05-09 00:49:35 +02:00
|
|
|
return TRUE;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
}
|
2002-05-09 00:49:35 +02:00
|
|
|
return FALSE;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/* Description.
|
|
|
|
* Remove entries with D_LFN attribute preceeding the directory entry
|
|
|
|
* pointed by fnp, fnode isn't modified (I hope).
|
|
|
|
* Return value.
|
2002-01-23 23:29:41 +01:00
|
|
|
* SUCCESS - completed successfully.
|
|
|
|
* DE_BLKINVLD - error occured, fnode is released.
|
2001-11-04 20:47:39 +01:00
|
|
|
* input: fnp with valid non-LFN directory entry, not equal to '..' or
|
|
|
|
* '.'
|
|
|
|
*/
|
|
|
|
COUNT remove_lfn_entries(f_node_ptr fnp)
|
2001-09-23 22:39:44 +02:00
|
|
|
{
|
2004-03-22 11:29:26 +01:00
|
|
|
unsigned original_diroff = fnp->f_diroff;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
if (fnp->f_diroff == 0)
|
|
|
|
break;
|
2004-03-22 11:29:26 +01:00
|
|
|
fnp->f_diroff -= 2;
|
2004-03-22 16:43:56 +01:00
|
|
|
/* it cannot / should not get below 0 because of '.' and '..'
|
|
|
|
* except for root directories... but then dir_read() makes it 0
|
|
|
|
* again */
|
2002-01-23 23:29:41 +01:00
|
|
|
if (dir_read(fnp) <= 0) {
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_BLKINVLD;
|
|
|
|
}
|
2001-09-23 22:39:44 +02:00
|
|
|
if (fnp->f_dir.dir_attrib != D_LFN)
|
|
|
|
break;
|
|
|
|
fnp->f_dir.dir_name[0] = DELETED;
|
|
|
|
fnp->f_flags.f_dmod = TRUE;
|
2002-01-23 23:29:41 +01:00
|
|
|
if (!dir_write(fnp)) return DE_BLKINVLD;
|
2001-09-23 22:39:44 +02:00
|
|
|
}
|
2004-03-22 11:29:26 +01:00
|
|
|
fnp->f_diroff = original_diroff - 1;
|
2002-01-23 23:29:41 +01:00
|
|
|
if (dir_read(fnp) <= 0) {
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_BLKINVLD;
|
|
|
|
}
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
return SUCCESS;
|
2001-09-23 22:39:44 +02:00
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2000-10-30 00:51:56 +01:00
|
|
|
/* /// Added - Ron Cemer */
|
|
|
|
/* If more than one f_node has a file open, and a write
|
|
|
|
occurs, this function must be called to propagate the
|
|
|
|
results of that write to the other f_nodes which have
|
|
|
|
that file open. Note that this function only has an
|
|
|
|
effect if SHARE is installed. This is for compatibility
|
|
|
|
reasons, since DOS without SHARE does not share changes
|
|
|
|
between two or more open instances of the same file
|
|
|
|
unless these instances were generated by dup() or dup2(). */
|
2001-11-18 15:01:12 +01:00
|
|
|
STATIC void merge_file_changes(f_node_ptr fnp, int collect)
|
|
|
|
{
|
|
|
|
f_node_ptr fnp2;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!IsShareInstalled())
|
|
|
|
return;
|
|
|
|
for (i = 0; i < f_nodes_cnt; i++)
|
|
|
|
{
|
|
|
|
fnp2 = (f_node_ptr) & f_nodes[i];
|
|
|
|
if ((fnp != (f_node_ptr) 0)
|
|
|
|
&& (fnp != fnp2)
|
|
|
|
&& (fnp->f_count > 0) && (is_same_file(fnp, fnp2)))
|
|
|
|
{
|
|
|
|
if (collect)
|
|
|
|
{
|
|
|
|
/* We're collecting file changes from any other
|
|
|
|
f_node which refers to this file. */
|
|
|
|
if (fnp2->f_mode != RDONLY)
|
|
|
|
{
|
|
|
|
copy_file_changes(fnp2, fnp);
|
|
|
|
break;
|
2000-10-30 00:51:56 +01:00
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* We just made changes to this file, so we are
|
|
|
|
distributing these changes to the other f_nodes
|
|
|
|
which refer to this file. */
|
|
|
|
copy_file_changes(fnp, fnp2);
|
|
|
|
}
|
2000-10-30 00:51:56 +01:00
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
2000-10-30 00:51:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* /// Added - Ron Cemer */
|
2001-11-18 15:01:12 +01:00
|
|
|
STATIC int is_same_file(f_node_ptr fnp1, f_node_ptr fnp2)
|
|
|
|
{
|
|
|
|
return
|
|
|
|
(fnp1->f_dpb->dpb_unit == fnp2->f_dpb->dpb_unit)
|
|
|
|
&& (fnp1->f_dpb->dpb_subunit == fnp2->f_dpb->dpb_subunit)
|
2002-08-04 03:14:18 +02:00
|
|
|
&& (fcbmatch(fnp1->f_dir.dir_name, fnp2->f_dir.dir_name))
|
2001-11-18 15:01:12 +01:00
|
|
|
&& ((fnp1->f_dir.dir_attrib & D_VOLID) == 0)
|
|
|
|
&& ((fnp2->f_dir.dir_attrib & D_VOLID) == 0)
|
|
|
|
&& (fnp1->f_diroff == fnp2->f_diroff)
|
|
|
|
&& (fnp1->f_dirstart == fnp2->f_dirstart)
|
|
|
|
&& (fnp1->f_dpb == fnp2->f_dpb);
|
2000-10-30 00:51:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* /// Added - Ron Cemer */
|
2001-11-18 15:01:12 +01:00
|
|
|
STATIC void copy_file_changes(f_node_ptr src, f_node_ptr dst)
|
|
|
|
{
|
|
|
|
dst->f_dir.dir_start = src->f_dir.dir_start;
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
2001-11-18 15:01:12 +01:00
|
|
|
dst->f_dir.dir_start_high = src->f_dir.dir_start_high;
|
2001-09-23 22:39:44 +02:00
|
|
|
#endif
|
2001-11-18 15:01:12 +01:00
|
|
|
dst->f_dir.dir_size = src->f_dir.dir_size;
|
|
|
|
dst->f_dir.dir_date = src->f_dir.dir_date;
|
|
|
|
dst->f_dir.dir_time = src->f_dir.dir_time;
|
2000-10-30 00:51:56 +01:00
|
|
|
}
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
STATIC COUNT delete_dir_entry(f_node_ptr fnp)
|
|
|
|
{
|
|
|
|
COUNT rc;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/* Ok, so we can delete. Start out by */
|
|
|
|
/* clobbering all FAT entries for this file */
|
|
|
|
/* (or, in English, truncate the FAT). */
|
2001-11-18 15:01:12 +01:00
|
|
|
if ((rc = remove_lfn_entries(fnp)) < 0)
|
2001-11-04 20:47:39 +01:00
|
|
|
return rc;
|
|
|
|
|
|
|
|
wipe_out(fnp);
|
|
|
|
*(fnp->f_dir.dir_name) = DELETED;
|
|
|
|
|
|
|
|
/* The directory has been modified, so set the */
|
|
|
|
/* bit before closing it, allowing it to be */
|
|
|
|
/* updated */
|
|
|
|
fnp->f_flags.f_dmod = TRUE;
|
|
|
|
dir_close(fnp);
|
|
|
|
|
|
|
|
/* SUCCESSful completion, return it */
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2002-02-16 20:20:20 +01:00
|
|
|
COUNT dos_delete(BYTE * path, int attrib)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
REG f_node_ptr fnp;
|
2002-08-04 03:14:18 +02:00
|
|
|
char fcbname[FNAME_SIZE + FEXT_SIZE];
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* first split the passed dir into components (i.e. - */
|
|
|
|
/* path to new directory and name of new directory */
|
2002-08-04 03:14:18 +02:00
|
|
|
if ((fnp = split_path(path, fcbname)) == NULL)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
return DE_PATHNOTFND;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check that we don't have a duplicate name, so if we */
|
|
|
|
/* find one, it's an error. */
|
2002-08-04 03:14:18 +02:00
|
|
|
if (find_fname(fnp, fcbname, attrib))
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-02-16 20:20:20 +01:00
|
|
|
/* Do not delete directories or r/o files */
|
|
|
|
/* lfn entries and volume labels are only found */
|
|
|
|
/* by find_fname() if attrib is set to a */
|
|
|
|
/* special value */
|
|
|
|
if (fnp->f_dir.dir_attrib & (D_RDONLY | D_DIR))
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_ACCESS;
|
|
|
|
}
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
return delete_dir_entry(fnp);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* No such file, return the error */
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_FILENOTFND;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-07-22 03:58:58 +02:00
|
|
|
COUNT dos_rmdir(BYTE * path)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
REG f_node_ptr fnp;
|
|
|
|
REG f_node_ptr fnp1;
|
2000-05-06 21:34:20 +02:00
|
|
|
BOOL found;
|
2002-08-04 03:14:18 +02:00
|
|
|
char fcbname[FNAME_SIZE + FEXT_SIZE];
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* first split the passed dir into comopnents (i.e. - */
|
|
|
|
/* path to new directory and name of new directory */
|
2002-08-04 03:14:18 +02:00
|
|
|
if ((fnp = split_path(path, fcbname)) == NULL)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
return DE_PATHNOTFND;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check that we're not trying to remove the root! */
|
|
|
|
if ((path[0] == '\\') && (path[1] == NULL))
|
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_ACCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check that we don't have a duplicate name, so if we */
|
|
|
|
/* find one, it's an error. */
|
2002-08-04 03:14:18 +02:00
|
|
|
if (find_fname(fnp, fcbname, D_ALL))
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
/* The only permissable attribute is directory, */
|
|
|
|
/* check for any other bit set. If it is, give */
|
|
|
|
/* an access error. */
|
2001-06-03 16:16:18 +02:00
|
|
|
/* if (fnp->f_dir.dir_attrib & ~D_DIR) */
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2001-06-03 16:16:18 +02:00
|
|
|
/* directories may have attributes, too. at least my WinNT disk
|
|
|
|
has many 'archive' directories
|
2001-11-18 15:01:12 +01:00
|
|
|
we still don't allow RDONLY directories to be deleted TE */
|
|
|
|
|
2001-09-23 22:39:44 +02:00
|
|
|
/* if (fnp->f_dir.dir_attrib & ~(D_DIR |D_HIDDEN|D_ARCHIVE|D_SYSTEM))
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_ACCESS;
|
2001-09-23 22:39:44 +02:00
|
|
|
} */
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Check that the directory is empty. Only the */
|
|
|
|
/* "." and ".." are permissable. */
|
|
|
|
fnp->f_flags.f_dmod = FALSE;
|
2001-07-22 03:58:58 +02:00
|
|
|
fnp1 = dir_open(path);
|
2003-02-20 21:51:42 +01:00
|
|
|
if (fnp1 == NULL)
|
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_ACCESS;
|
|
|
|
}
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
dir_read(fnp1);
|
|
|
|
if (fnp1->f_dir.dir_name[0] != '.')
|
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_ACCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
dir_read(fnp1);
|
|
|
|
if (fnp1->f_dir.dir_name[0] != '.')
|
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_ACCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now search through the directory and make certain */
|
|
|
|
/* that there are no entries. */
|
|
|
|
found = FALSE;
|
2001-11-04 20:47:39 +01:00
|
|
|
while (dir_read(fnp1) == 1)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
if (fnp1->f_dir.dir_name[0] == '\0')
|
|
|
|
break;
|
2001-11-18 15:01:12 +01:00
|
|
|
if (fnp1->f_dir.dir_name[0] == DELETED
|
|
|
|
|| fnp1->f_dir.dir_attrib == D_LFN)
|
2000-05-06 21:34:20 +02:00
|
|
|
continue;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
found = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dir_close(fnp1);
|
|
|
|
/* If anything was found, exit with an error. */
|
|
|
|
if (found)
|
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_ACCESS;
|
|
|
|
}
|
2001-11-04 20:47:39 +01:00
|
|
|
return delete_dir_entry(fnp);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* No such file, return the error */
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_FILENOTFND;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-02-16 20:20:20 +01:00
|
|
|
COUNT dos_rename(BYTE * path1, BYTE * path2, int attrib)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
REG f_node_ptr fnp1;
|
|
|
|
REG f_node_ptr fnp2;
|
2001-11-04 20:47:39 +01:00
|
|
|
COUNT ret;
|
2002-08-04 03:14:18 +02:00
|
|
|
char fcbname[FNAME_SIZE + FEXT_SIZE];
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* first split the passed target into compnents (i.e. - path to */
|
|
|
|
/* new file name and name of new file name */
|
2002-08-04 03:14:18 +02:00
|
|
|
if ((fnp2 = split_path(path2, fcbname)) == NULL)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
return DE_PATHNOTFND;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check that we don't have a duplicate name, so if we find */
|
|
|
|
/* one, it's an error. */
|
2002-08-04 03:14:18 +02:00
|
|
|
if (find_fname(fnp2, fcbname, attrib))
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
dir_close(fnp2);
|
|
|
|
return DE_ACCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* next split the passed source into compnents (i.e. - path to */
|
|
|
|
/* old file name and name of old file name */
|
2002-08-04 03:14:18 +02:00
|
|
|
if ((fnp1 = split_path(path1, fcbname)) == NULL)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
dir_close(fnp2);
|
|
|
|
return DE_PATHNOTFND;
|
|
|
|
}
|
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
if (!find_fname(fnp1, fcbname, attrib))
|
2001-07-22 03:58:58 +02:00
|
|
|
{
|
|
|
|
/* No such file, return the error */
|
|
|
|
dir_close(fnp1);
|
|
|
|
dir_close(fnp2);
|
|
|
|
return DE_FILENOTFND;
|
|
|
|
}
|
|
|
|
|
2004-03-23 02:36:16 +01:00
|
|
|
ret = alloc_find_free(fnp2, path2, fcbname);
|
|
|
|
if (ret != SUCCESS) {
|
2000-05-06 21:34:20 +02:00
|
|
|
dir_close(fnp1);
|
2004-03-23 02:36:16 +01:00
|
|
|
return ret;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
if ((ret = remove_lfn_entries(fnp1)) < 0)
|
2001-11-04 20:47:39 +01:00
|
|
|
return ret;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* put the fnode's name into the directory. */
|
2002-08-04 03:14:18 +02:00
|
|
|
memcpy(fnp2->f_dir.dir_name, fcbname, FNAME_SIZE + FEXT_SIZE);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Set the fnode to the desired mode */
|
|
|
|
fnp2->f_dir.dir_size = fnp1->f_dir.dir_size;
|
|
|
|
fnp2->f_dir.dir_start = fnp1->f_dir.dir_start;
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
|
|
|
fnp2->f_dir.dir_start_high = fnp1->f_dir.dir_start_high;
|
|
|
|
#endif
|
2000-05-06 21:34:20 +02:00
|
|
|
fnp2->f_dir.dir_attrib = fnp1->f_dir.dir_attrib;
|
|
|
|
fnp2->f_dir.dir_time = fnp1->f_dir.dir_time;
|
|
|
|
fnp2->f_dir.dir_date = fnp1->f_dir.dir_date;
|
|
|
|
|
|
|
|
/* The directory has been modified, so set the bit before */
|
|
|
|
/* closing it, allowing it to be updated. */
|
|
|
|
fnp1->f_flags.f_dmod = fnp2->f_flags.f_dmod = TRUE;
|
|
|
|
fnp1->f_flags.f_dnew = fnp2->f_flags.f_dnew = FALSE;
|
|
|
|
fnp1->f_flags.f_ddir = fnp2->f_flags.f_ddir = TRUE;
|
|
|
|
|
|
|
|
/* Ok, so we can delete this one. Save the file info. */
|
|
|
|
*(fnp1->f_dir.dir_name) = DELETED;
|
|
|
|
|
|
|
|
dir_close(fnp1);
|
|
|
|
dir_close(fnp2);
|
|
|
|
|
|
|
|
/* SUCCESSful completion, return it */
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
2001-11-04 20:47:39 +01:00
|
|
|
/* wipe out all FAT entries starting from st for create, delete, etc. */
|
2000-05-06 21:34:20 +02:00
|
|
|
/* */
|
2001-11-18 15:01:12 +01:00
|
|
|
STATIC VOID wipe_out_clusters(struct dpb FAR * dpbp, CLUSTER st)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-11-04 20:47:39 +01:00
|
|
|
REG CLUSTER next;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* Loop from start until either a FREE entry is */
|
|
|
|
/* encountered (due to a fractured file system) of the */
|
|
|
|
/* last cluster is encountered. */
|
2001-11-04 20:47:39 +01:00
|
|
|
while (st != LONG_LAST_CLUSTER)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
/* get the next cluster pointed to */
|
|
|
|
next = next_cluster(dpbp, st);
|
|
|
|
|
|
|
|
/* just exit if a damaged file system exists */
|
2002-08-04 03:14:18 +02:00
|
|
|
if (next == FREE || next == 1)
|
2000-05-06 21:34:20 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* zap the FAT pointed to */
|
|
|
|
link_fat(dpbp, st, FREE);
|
|
|
|
|
|
|
|
/* and the start of free space pointer */
|
2001-11-04 20:47:39 +01:00
|
|
|
#ifdef WITHFAT32
|
|
|
|
if (ISFAT32(dpbp))
|
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
if ((dpbp->dpb_xcluster == UNKNCLUSTER) || (dpbp->dpb_xcluster > st))
|
2001-11-04 20:47:39 +01:00
|
|
|
dpbp->dpb_xcluster = st;
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
|
|
|
else
|
2001-11-04 20:47:39 +01:00
|
|
|
#endif
|
2001-11-18 15:01:12 +01:00
|
|
|
if ((dpbp->dpb_cluster == UNKNCLUSTER) || (dpbp->dpb_cluster > st))
|
2004-02-07 19:04:50 +01:00
|
|
|
dpbp->dpb_cluster = (UWORD)st;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* and just follow the linked list */
|
|
|
|
st = next;
|
|
|
|
}
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
2001-11-18 15:01:12 +01:00
|
|
|
if (ISFAT32(dpbp))
|
|
|
|
write_fsinfo(dpbp);
|
2001-09-23 22:39:44 +02:00
|
|
|
#endif
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/* */
|
|
|
|
/* wipe out all FAT entries for create, delete, etc. */
|
|
|
|
/* */
|
|
|
|
STATIC VOID wipe_out(f_node_ptr fnp)
|
|
|
|
{
|
|
|
|
/* if already free or not valid file, just exit */
|
2004-01-26 01:51:49 +01:00
|
|
|
if ((fnp == NULL) || checkdstart(fnp->f_dpb, &fnp->f_dir, FREE))
|
2001-11-04 20:47:39 +01:00
|
|
|
return;
|
|
|
|
|
2004-01-26 01:51:49 +01:00
|
|
|
wipe_out_clusters(fnp->f_dpb, getdstart(fnp->f_dpb, &fnp->f_dir));
|
2001-11-04 20:47:39 +01:00
|
|
|
}
|
|
|
|
|
2001-06-03 16:16:18 +02:00
|
|
|
STATIC BOOL find_free(f_node_ptr fnp)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-11-04 20:47:39 +01:00
|
|
|
COUNT rc;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
while ((rc = dir_read(fnp)) == 1)
|
|
|
|
if (fnp->f_dir.dir_name[0] == DELETED)
|
2000-05-06 21:34:20 +02:00
|
|
|
return TRUE;
|
2001-11-04 20:47:39 +01:00
|
|
|
return rc >= 0;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2004-03-23 02:36:16 +01:00
|
|
|
/* alloc_find_free: resets the directory by a close followed by */
|
|
|
|
/* an open. Then finds a spare directory entry and if not */
|
|
|
|
/* available, tries to extend the directory. */
|
|
|
|
STATIC int alloc_find_free(f_node_ptr fnp, char *path, char *fcbname)
|
|
|
|
{
|
|
|
|
fnp->f_flags.f_dmod = FALSE;
|
|
|
|
dir_close(fnp);
|
|
|
|
fnp = split_path(path, fcbname);
|
|
|
|
|
|
|
|
/* Get a free f_node pointer so that we can use */
|
|
|
|
/* it in building the new file. */
|
|
|
|
/* Note that if we're in the root and we don't */
|
|
|
|
/* find an empty slot, we need to abort. */
|
|
|
|
if (find_free(fnp) == 0)
|
|
|
|
{
|
|
|
|
if (fnp->f_flags.f_droot)
|
|
|
|
{
|
|
|
|
fnp->f_flags.f_dmod = FALSE;
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_TOOMANY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Otherwise just expand the directory */
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((ret = extend_dir(fnp)) != SUCCESS)
|
|
|
|
/* fnp already closed in extend_dir */
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* */
|
|
|
|
/* dos_getdate for the file date */
|
|
|
|
/* */
|
2002-10-22 04:40:19 +02:00
|
|
|
date dos_getdate(void)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-10-22 04:40:19 +02:00
|
|
|
struct dosdate dd;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* First - get the system date set by either the user */
|
|
|
|
/* on start-up or the CMOS clock */
|
2002-10-22 04:40:19 +02:00
|
|
|
DosGetDate(&dd);
|
|
|
|
return DT_ENCODE(dd.month, dd.monthday, dd.year - EPOCH_YEAR);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
|
|
|
/* dos_gettime for the file time */
|
|
|
|
/* */
|
2002-10-22 04:40:19 +02:00
|
|
|
time dos_gettime(void)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-10-22 04:40:19 +02:00
|
|
|
struct dostime dt;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* First - get the system time set by either the user */
|
|
|
|
/* on start-up or the CMOS clock */
|
2002-10-22 04:40:19 +02:00
|
|
|
DosGetTime(&dt);
|
|
|
|
return TM_ENCODE(dt.hour, dt.minute, dt.second >> 1);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
|
|
|
/* dos_getftime for the file time */
|
|
|
|
/* */
|
|
|
|
COUNT dos_getftime(COUNT fd, date FAR * dp, time FAR * tp)
|
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
f_node_ptr fnp;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* 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 */
|
2001-11-18 15:01:12 +01:00
|
|
|
if (fnp == (f_node_ptr) 0 || fnp->f_count <= 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
|
|
|
/* dos_setftime for the file time */
|
|
|
|
/* */
|
2001-08-19 14:58:36 +02:00
|
|
|
COUNT dos_setftime(COUNT fd, date dp, time tp)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
f_node_ptr fnp;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* 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 */
|
2001-11-18 15:01:12 +01:00
|
|
|
if (fnp == (f_node_ptr) 0 || fnp->f_count <= 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_INVLDHNDL;
|
|
|
|
|
|
|
|
/* Set the date and time from the fnode and return */
|
2001-08-19 14:58:36 +02:00
|
|
|
fnp->f_dir.dir_date = dp;
|
|
|
|
fnp->f_dir.dir_time = tp;
|
2001-11-18 15:01:12 +01:00
|
|
|
fnp->f_flags.f_dmod = TRUE; /* mark file as modified */
|
|
|
|
fnp->f_flags.f_ddate = TRUE; /* set this date upon closing */
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
|
|
|
/* dos_getfsize for the file time */
|
|
|
|
/* */
|
2002-08-04 03:14:18 +02:00
|
|
|
ULONG dos_getfsize(COUNT fd)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
f_node_ptr fnp;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* 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 */
|
2001-11-18 15:01:12 +01:00
|
|
|
if (fnp == (f_node_ptr) 0 || fnp->f_count <= 0)
|
2002-08-04 03:14:18 +02:00
|
|
|
return (ULONG)-1l;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Return the file size */
|
2003-03-13 00:29:08 +01:00
|
|
|
return fnp->f_dir.dir_size;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
|
|
|
/* dos_setfsize for the file time */
|
|
|
|
/* */
|
|
|
|
BOOL dos_setfsize(COUNT fd, LONG size)
|
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
f_node_ptr fnp;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* 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 */
|
2001-11-18 15:01:12 +01:00
|
|
|
if (fnp == (f_node_ptr) 0 || fnp->f_count <= 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Change the file size */
|
|
|
|
fnp->f_dir.dir_size = size;
|
2000-10-30 00:51:56 +01:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */
|
2000-10-30 00:51:56 +01:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
|
|
|
/* Find free cluster in disk FAT table */
|
|
|
|
/* */
|
2001-09-23 22:39:44 +02:00
|
|
|
STATIC CLUSTER find_fat_free(f_node_ptr fnp)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-11-04 20:47:39 +01:00
|
|
|
REG CLUSTER idx, size;
|
|
|
|
struct dpb FAR *dpbp = fnp->f_dpb;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
#ifdef DISPLAY_GETBLOCK
|
|
|
|
printf("[find_fat_free]\n");
|
|
|
|
#endif
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* Start from optimized lookup point for start of FAT */
|
2001-11-04 20:47:39 +01:00
|
|
|
idx = 2;
|
|
|
|
size = dpbp->dpb_size;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
#ifdef WITHFAT32
|
|
|
|
if (ISFAT32(dpbp))
|
|
|
|
{
|
|
|
|
if (dpbp->dpb_xcluster != UNKNCLUSTER)
|
|
|
|
idx = dpbp->dpb_xcluster;
|
2001-11-18 15:01:12 +01:00
|
|
|
size = dpbp->dpb_xsize;
|
|
|
|
}
|
|
|
|
else
|
2001-11-04 20:47:39 +01:00
|
|
|
#endif
|
|
|
|
if (dpbp->dpb_cluster != UNKNCLUSTER)
|
|
|
|
idx = dpbp->dpb_cluster;
|
2001-09-23 22:39:44 +02:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* Search the FAT table looking for the first free */
|
|
|
|
/* entry. */
|
2001-11-04 20:47:39 +01:00
|
|
|
for (; idx <= size; idx++)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-11-04 20:47:39 +01:00
|
|
|
if (next_cluster(dpbp, idx) == FREE)
|
2000-05-06 21:34:20 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No empty clusters, disk is FULL! */
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
2001-11-04 20:47:39 +01:00
|
|
|
if (ISFAT32(dpbp))
|
|
|
|
{
|
|
|
|
if (idx > dpbp->dpb_xsize)
|
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
dpbp->dpb_xcluster = UNKNCLUSTER;
|
2001-11-04 20:47:39 +01:00
|
|
|
write_fsinfo(dpbp);
|
|
|
|
return LONG_LAST_CLUSTER;
|
|
|
|
}
|
|
|
|
if (dpbp->dpb_xnfreeclst != XUNKNCLSTFREE)
|
2001-11-18 15:01:12 +01:00
|
|
|
dpbp->dpb_xnfreeclst--; /* TE: moved from link_fat() */
|
2001-11-04 20:47:39 +01:00
|
|
|
|
|
|
|
/* return the free entry */
|
|
|
|
dpbp->dpb_xcluster = idx;
|
|
|
|
write_fsinfo(dpbp);
|
|
|
|
return idx;
|
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
#endif
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2004-02-07 19:04:50 +01:00
|
|
|
if ((UWORD)idx > dpbp->dpb_size)
|
2001-11-04 20:47:39 +01:00
|
|
|
{
|
|
|
|
dpbp->dpb_cluster = UNKNCLUSTER;
|
2000-05-06 21:34:20 +02:00
|
|
|
return LONG_LAST_CLUSTER;
|
|
|
|
}
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
if (dpbp->dpb_nfreeclst != UNKNCLSTFREE)
|
2001-11-18 15:01:12 +01:00
|
|
|
dpbp->dpb_nfreeclst--; /* TE: moved from link_fat() */
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* return the free entry */
|
2004-02-07 19:04:50 +01:00
|
|
|
dpbp->dpb_cluster = (UWORD)idx;
|
2000-05-06 21:34:20 +02:00
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
2001-06-03 16:16:18 +02:00
|
|
|
/* create a directory - returns success or a negative error */
|
2000-05-06 21:34:20 +02:00
|
|
|
/* number */
|
|
|
|
/* */
|
2001-07-22 03:58:58 +02:00
|
|
|
COUNT dos_mkdir(BYTE * dir)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
REG f_node_ptr fnp;
|
2000-05-06 21:34:20 +02:00
|
|
|
REG COUNT idx;
|
|
|
|
struct buffer FAR *bp;
|
2001-11-04 20:47:39 +01:00
|
|
|
struct dpb FAR *dpbp;
|
2001-09-23 22:39:44 +02:00
|
|
|
CLUSTER free_fat, parent;
|
2001-07-10 00:19:33 +02:00
|
|
|
COUNT ret;
|
2002-08-04 03:14:18 +02:00
|
|
|
char fcbname[FNAME_SIZE + FEXT_SIZE];
|
2004-03-07 13:59:38 +01:00
|
|
|
|
|
|
|
/* first split the passed dir into components (i.e. - */
|
2000-05-06 21:34:20 +02:00
|
|
|
/* path to new directory and name of new directory */
|
2002-08-04 03:14:18 +02:00
|
|
|
if ((fnp = split_path(dir, fcbname)) == NULL)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
return DE_PATHNOTFND;
|
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2004-03-07 13:59:38 +01:00
|
|
|
/* check that the resulting combined path does not exceed
|
|
|
|
the 67 MAX_CDSPATH limit. this leads to problems:
|
2001-06-03 16:16:18 +02:00
|
|
|
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
|
2001-11-18 15:01:12 +01:00
|
|
|
can create an unlimited amount of same dirs. this space
|
|
|
|
is lost forever
|
|
|
|
*/
|
2004-03-07 13:59:38 +01:00
|
|
|
if (strlen(dir) >= MAX_CDSPATH) /* dir is already output of "truename" */
|
2001-06-03 16:16:18 +02:00
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_PATHNOTFND;
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Check that we don't have a duplicate name, so if we */
|
|
|
|
/* find one, it's an error. */
|
2002-08-04 03:14:18 +02:00
|
|
|
if (find_fname(fnp, fcbname, D_ALL))
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_ACCESS;
|
|
|
|
}
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
parent = fnp->f_dirstart;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-03-23 02:36:16 +01:00
|
|
|
ret = alloc_find_free(fnp, dir, fcbname);
|
|
|
|
if (ret != SUCCESS)
|
|
|
|
return ret;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
/* 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);
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
/* No empty clusters, disk is FULL! Translate into a */
|
|
|
|
/* useful error message. */
|
|
|
|
if (free_fat == LONG_LAST_CLUSTER)
|
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_HNDLDSKFULL;
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
/* put the fnode's name into the directory. */
|
2002-08-04 03:14:18 +02:00
|
|
|
memcpy(fnp->f_dir.dir_name, fcbname, FNAME_SIZE + FEXT_SIZE);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
/* Set the fnode to the desired mode */
|
|
|
|
fnp->f_mode = WRONLY;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-10-22 04:40:19 +02:00
|
|
|
init_direntry(&fnp->f_dir, D_DIR, free_fat);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
fnp->f_flags.f_dmod = TRUE;
|
|
|
|
fnp->f_flags.f_dnew = FALSE;
|
|
|
|
fnp->f_flags.f_ddir = TRUE;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
fnp->f_offset = 0l;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Mark the cluster in the FAT as used */
|
2001-11-04 20:47:39 +01:00
|
|
|
dpbp = fnp->f_dpb;
|
|
|
|
link_fat(dpbp, free_fat, LONG_LAST_CLUSTER);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Craft the new directory. Note that if we're in a new */
|
|
|
|
/* directory just under the root, ".." pointer is 0. */
|
2001-06-03 16:16:18 +02:00
|
|
|
/* as we are overwriting it completely, don't read first */
|
2001-11-18 15:01:12 +01:00
|
|
|
bp = getblockOver(clus2phys(free_fat, dpbp), dpbp->dpb_unit);
|
2000-05-06 21:34:20 +02:00
|
|
|
#ifdef DISPLAY_GETBLOCK
|
|
|
|
printf("FAT (dos_mkdir)\n");
|
|
|
|
#endif
|
|
|
|
if (bp == NULL)
|
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_BLKINVLD;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create the "." entry */
|
2002-08-04 03:14:18 +02:00
|
|
|
DirEntBuffer.dir_name[0] = '.';
|
|
|
|
memset(DirEntBuffer.dir_name + 1, ' ', FNAME_SIZE + FEXT_SIZE - 1);
|
2002-10-22 04:40:19 +02:00
|
|
|
init_direntry(&DirEntBuffer, D_DIR, free_fat);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* And put it out */
|
2002-08-04 03:14:18 +02:00
|
|
|
putdirent(&DirEntBuffer, bp->b_buffer);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* create the ".." entry */
|
2002-08-04 03:14:18 +02:00
|
|
|
DirEntBuffer.dir_name[1] = '.';
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
2001-11-18 15:01:12 +01:00
|
|
|
if (ISFAT32(dpbp) && parent == dpbp->dpb_xrootclst)
|
|
|
|
{
|
|
|
|
parent = 0;
|
2001-09-23 22:39:44 +02:00
|
|
|
}
|
|
|
|
#endif
|
2004-01-26 01:51:49 +01:00
|
|
|
setdstart(dpbp, &DirEntBuffer, parent);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* and put it out */
|
2002-08-04 03:14:18 +02:00
|
|
|
putdirent(&DirEntBuffer, &bp->b_buffer[DIRENT_SIZE]);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* fill the rest of the block with zeros */
|
2001-11-18 15:01:12 +01:00
|
|
|
fmemset(&bp->b_buffer[2 * DIRENT_SIZE], 0, BUFFERSIZE - 2 * DIRENT_SIZE);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Mark the block to be written out */
|
2001-06-03 16:16:18 +02:00
|
|
|
bp->b_flag |= BFR_DIRTY | BFR_VALID;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* clear out the rest of the blocks in the cluster */
|
2001-11-04 20:47:39 +01:00
|
|
|
for (idx = 1; idx <= dpbp->dpb_clsmask; idx++)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
/* as we are overwriting it completely, don't read first */
|
2004-01-26 01:51:49 +01:00
|
|
|
bp = getblockOver(clus2phys(getdstart(dpbp, &fnp->f_dir), dpbp) + idx,
|
2001-11-04 20:47:39 +01:00
|
|
|
dpbp->dpb_unit);
|
2000-05-06 21:34:20 +02:00
|
|
|
#ifdef DISPLAY_GETBLOCK
|
|
|
|
printf("DIR (dos_mkdir)\n");
|
|
|
|
#endif
|
|
|
|
if (bp == NULL)
|
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_BLKINVLD;
|
|
|
|
}
|
2001-06-03 16:16:18 +02:00
|
|
|
fmemset(bp->b_buffer, 0, BUFFERSIZE);
|
|
|
|
bp->b_flag |= BFR_DIRTY | BFR_VALID;
|
2001-11-18 15:01:12 +01:00
|
|
|
bp->b_flag |= BFR_UNCACHE; /* need not be cached */
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* flush the drive buffers so that all info is written */
|
2002-08-04 03:14:18 +02:00
|
|
|
/* hazard: no error checking! */
|
2002-10-22 04:40:19 +02:00
|
|
|
flush_buffers(dpbp->dpb_unit);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Close the directory so that the entry is updated */
|
|
|
|
fnp->f_flags.f_dmod = TRUE;
|
|
|
|
dir_close(fnp);
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2004-03-22 23:33:05 +01:00
|
|
|
STATIC CLUSTER extend(f_node_ptr fnp)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-09-23 22:39:44 +02:00
|
|
|
CLUSTER free_fat;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* 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)
|
2004-03-22 23:33:05 +01:00
|
|
|
return free_fat;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Now that we've found a free FAT entry, mark it as the last */
|
|
|
|
/* entry and save. */
|
2004-03-23 01:45:24 +01:00
|
|
|
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);
|
2001-09-23 22:39:44 +02:00
|
|
|
link_fat(fnp->f_dpb, free_fat, LONG_LAST_CLUSTER);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Mark the directory so that the entry is updated */
|
|
|
|
fnp->f_flags.f_dmod = TRUE;
|
2004-03-22 23:33:05 +01:00
|
|
|
return free_fat;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2001-06-03 16:16:18 +02:00
|
|
|
STATIC COUNT extend_dir(f_node_ptr fnp)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
REG COUNT idx;
|
|
|
|
|
2004-03-22 23:33:05 +01:00
|
|
|
CLUSTER cluster = extend(fnp);
|
|
|
|
if (cluster == LONG_LAST_CLUSTER)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_HNDLDSKFULL;
|
|
|
|
}
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/* clear out the blocks in the cluster */
|
|
|
|
for (idx = 0; idx <= fnp->f_dpb->dpb_clsmask; idx++)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
REG struct buffer FAR *bp;
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/* as we are overwriting it completely, don't read first */
|
2004-03-22 23:33:05 +01:00
|
|
|
bp = getblockOver(clus2phys(cluster, fnp->f_dpb) + idx,
|
2001-11-04 20:47:39 +01:00
|
|
|
fnp->f_dpb->dpb_unit);
|
2000-05-06 21:34:20 +02:00
|
|
|
#ifdef DISPLAY_GETBLOCK
|
|
|
|
printf("DIR (extend_dir)\n");
|
|
|
|
#endif
|
2001-11-18 15:01:12 +01:00
|
|
|
if (bp == NULL)
|
|
|
|
{
|
2000-05-06 21:34:20 +02:00
|
|
|
dir_close(fnp);
|
|
|
|
return DE_BLKINVLD;
|
|
|
|
}
|
2001-11-04 20:47:39 +01:00
|
|
|
fmemset(bp->b_buffer, 0, BUFFERSIZE);
|
2001-06-03 16:16:18 +02:00
|
|
|
bp->b_flag |= BFR_DIRTY | BFR_VALID;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2001-06-03 16:16:18 +02:00
|
|
|
if (idx != 0)
|
2001-11-18 15:01:12 +01:00
|
|
|
bp->b_flag |= BFR_UNCACHE; /* needs not be cached */
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!find_free(fnp))
|
|
|
|
{
|
|
|
|
dir_close(fnp);
|
|
|
|
return DE_HNDLDSKFULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* flush the drive buffers so that all info is written */
|
2002-08-04 03:14:18 +02:00
|
|
|
/* hazard: no error checking! */
|
2002-10-22 04:40:19 +02:00
|
|
|
flush_buffers(fnp->f_dpb->dpb_unit);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2001-11-14 00:36:45 +01:00
|
|
|
/* Description.
|
|
|
|
* Finds the cluster which contains byte at the fnp->f_offset offset and
|
|
|
|
* stores its number to the fnp->f_cluster. The search begins from the start of
|
|
|
|
* a file or a directory depending whether fnp->f_ddir is FALSE or TRUE
|
|
|
|
* and continues through the FAT chain until the target cluster is found.
|
|
|
|
* The mode can have only XFR_READ or XFR_WRITE values.
|
|
|
|
* In the XFR_WRITE mode map_cluster extends the FAT chain by creating
|
|
|
|
* new clusters upon necessity.
|
|
|
|
* Return value.
|
|
|
|
* DE_HNDLDSKFULL - [XFR_WRITE mode only] unable to find free cluster
|
|
|
|
* for extending the FAT chain, the disk is full.
|
|
|
|
* The fnode is released from memory.
|
|
|
|
* DE_SEEK - [XFR_READ mode only] byte at f_offset lies outside of
|
|
|
|
* the FAT chain. The fnode is not released.
|
|
|
|
* Notes.
|
2002-12-09 01:17:15 +01:00
|
|
|
* If we are moving forward, then use the relative cluster number offset
|
2001-11-14 00:36:45 +01:00
|
|
|
* that we are at now (f_cluster_offset) to start, instead of starting
|
|
|
|
* at the beginning. */
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-06-03 16:16:18 +02:00
|
|
|
COUNT map_cluster(REG f_node_ptr fnp, COUNT mode)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-03-22 23:33:05 +01:00
|
|
|
CLUSTER relcluster, cluster;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
#ifdef DISPLAY_GETBLOCK
|
|
|
|
printf("map_cluster: current %lu, offset %lu, diff=%lu ",
|
2002-12-09 01:17:15 +01:00
|
|
|
(ULONG)fnp->f_cluster_offset, fnp->f_offset,
|
2000-05-06 21:34:20 +02:00
|
|
|
fnp->f_offset - fnp->f_cluster_offset);
|
|
|
|
#endif
|
2001-09-23 22:39:44 +02:00
|
|
|
|
2004-03-23 01:45:24 +01:00
|
|
|
if (fnp->f_cluster == FREE)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-03-23 01:45:24 +01:00
|
|
|
/* If this is a read but the file still has zero bytes return */
|
|
|
|
/* immediately.... */
|
|
|
|
if (mode == XFR_READ)
|
|
|
|
return DE_SEEK;
|
|
|
|
|
|
|
|
/* If someone did a seek, but no writes have occured, we will */
|
|
|
|
/* need to initialize the fnode. */
|
|
|
|
/* (mode == XFR_WRITE) */
|
2000-05-06 21:34:20 +02:00
|
|
|
/* If there are no more free fat entries, then we are full! */
|
2004-03-23 01:45:24 +01:00
|
|
|
cluster = extend(fnp);
|
2004-03-22 23:33:05 +01:00
|
|
|
if (cluster == LONG_LAST_CLUSTER)
|
2001-11-14 00:36:45 +01:00
|
|
|
{
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_HNDLDSKFULL;
|
2001-11-14 00:36:45 +01:00
|
|
|
}
|
2004-03-22 23:33:05 +01:00
|
|
|
fnp->f_cluster = cluster;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2004-03-22 23:33:05 +01:00
|
|
|
relcluster = (CLUSTER)((fnp->f_offset / fnp->f_dpb->dpb_secsize) >>
|
|
|
|
fnp->f_dpb->dpb_shftcnt);
|
2002-12-09 01:17:15 +01:00
|
|
|
if (relcluster < fnp->f_cluster_offset)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
/* Set internal index and cluster size. */
|
|
|
|
fnp->f_cluster = fnp->f_flags.f_ddir ? fnp->f_dirstart :
|
2004-01-26 01:51:49 +01:00
|
|
|
getdstart(fnp->f_dpb, &fnp->f_dir);
|
2000-05-06 21:34:20 +02:00
|
|
|
fnp->f_cluster_offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now begin the linear search. The relative cluster is */
|
|
|
|
/* maintained as part of the set of physical indices. It is */
|
|
|
|
/* also the highest order index and is mapped directly into */
|
|
|
|
/* physical cluster. Our search is performed by pacing an index */
|
|
|
|
/* up to the relative cluster position where the index falls */
|
|
|
|
/* within the cluster. */
|
2001-11-14 00:36:45 +01:00
|
|
|
|
2004-03-22 23:33:05 +01:00
|
|
|
while (fnp->f_cluster_offset != relcluster)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-03-22 23:33:05 +01:00
|
|
|
/* get next cluster in the chain */
|
|
|
|
cluster = next_cluster(fnp->f_dpb, fnp->f_cluster);
|
|
|
|
if (cluster == 1)
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_SEEK;
|
2001-11-14 00:36:45 +01:00
|
|
|
|
2004-03-22 23:33:05 +01:00
|
|
|
/* If this is a read and the next is a LAST_CLUSTER, */
|
|
|
|
/* then we are going to read past EOF, return zero read */
|
|
|
|
/* or expand the list if we're going to write and have run into */
|
|
|
|
/* the last cluster marker. */
|
|
|
|
if (cluster == LONG_LAST_CLUSTER)
|
|
|
|
{
|
|
|
|
if (mode == XFR_READ)
|
|
|
|
return DE_SEEK;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2004-03-22 23:33:05 +01:00
|
|
|
/* mode == XFR_WRITE */
|
|
|
|
cluster = extend(fnp);
|
|
|
|
if (cluster == LONG_LAST_CLUSTER)
|
|
|
|
return DE_HNDLDSKFULL;
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-03-22 23:33:05 +01:00
|
|
|
fnp->f_cluster = cluster;
|
2002-12-09 01:17:15 +01:00
|
|
|
fnp->f_cluster_offset++;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
#ifdef DISPLAY_GETBLOCK
|
|
|
|
printf("done.\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2003-03-13 00:29:08 +01:00
|
|
|
/* extends a file from f_dir.dir_size to f_offset */
|
2002-05-09 00:49:35 +02:00
|
|
|
/* Proper OS's write zeros in between, but DOS just adds */
|
|
|
|
/* garbage sectors, and lets the caller do the zero filling */
|
|
|
|
/* if you prefer you can have this enabled using */
|
|
|
|
/* #define WRITEZEROS 1 */
|
|
|
|
/* but because we want to be compatible, we don't do this by */
|
|
|
|
/* default */
|
|
|
|
STATIC COUNT dos_extend(f_node_ptr fnp)
|
|
|
|
{
|
|
|
|
#ifdef WRITEZEROS
|
|
|
|
struct buffer FAR *bp;
|
|
|
|
UCOUNT xfr_cnt = 0;
|
|
|
|
/* The variable secsize will be used later. */
|
|
|
|
UWORD secsize = fnp->f_dpb->dpb_secsize;
|
|
|
|
ULONG count;
|
2004-03-22 17:56:34 +01:00
|
|
|
unsigned sector, boff;
|
2002-05-09 00:49:35 +02:00
|
|
|
#endif
|
|
|
|
|
2003-03-13 00:29:08 +01:00
|
|
|
if (fnp->f_offset <= fnp->f_dir.dir_size)
|
2002-05-09 00:49:35 +02:00
|
|
|
return SUCCESS;
|
|
|
|
|
|
|
|
#ifdef WRITEZEROS
|
2003-03-13 00:29:08 +01:00
|
|
|
count = fnp->f_offset - fnp->f_dir.dir_size;
|
|
|
|
fnp->f_offset = fnp->f_dir.dir_size;
|
2002-05-09 00:49:35 +02:00
|
|
|
while (count > 0)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
if (map_cluster(fnp, XFR_WRITE) != SUCCESS)
|
|
|
|
return DE_HNDLDSKFULL;
|
|
|
|
|
|
|
|
#ifdef WRITEZEROS
|
|
|
|
/* Compute the block within the cluster and the offset */
|
|
|
|
/* within the block. */
|
2004-03-22 17:56:34 +01:00
|
|
|
sector = (UBYTE)(fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask;
|
|
|
|
boff = (UWORD)(fnp->f_offset % secsize);
|
2002-05-09 00:49:35 +02:00
|
|
|
|
|
|
|
#ifdef DSK_DEBUG
|
|
|
|
printf("write %d links; dir offset %ld, cluster %d\n",
|
|
|
|
fnp->f_count, fnp->f_diroff, fnp->f_cluster);
|
|
|
|
#endif
|
|
|
|
|
2004-03-22 17:56:34 +01:00
|
|
|
xfr_cnt = count < (ULONG) secsize - boff ?
|
|
|
|
(UWORD) count : secsize - boff;
|
2002-05-09 00:49:35 +02:00
|
|
|
|
|
|
|
/* get a buffer to store the block in */
|
2004-03-22 17:56:34 +01:00
|
|
|
if ((boff == 0) && (xfr_cnt == secsize))
|
2002-05-09 00:49:35 +02:00
|
|
|
{
|
|
|
|
bp = getblockOver(clus2phys(fnp->f_cluster, fnp->f_dpb) +
|
2004-03-22 17:56:34 +01:00
|
|
|
sector, fnp->f_dpb->dpb_unit);
|
2002-05-09 00:49:35 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-03-22 17:56:34 +01:00
|
|
|
bp = getblock(clus2phys(fnp->f_cluster, fnp->f_dpb) + sector,
|
2002-05-09 00:49:35 +02:00
|
|
|
fnp->f_dpb->dpb_unit);
|
|
|
|
}
|
|
|
|
if (bp == NULL)
|
|
|
|
{
|
|
|
|
return DE_BLKINVLD;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set a block to zero */
|
2004-03-22 17:56:34 +01:00
|
|
|
fmemset((BYTE FAR *) & bp->b_buffer[boff], 0, xfr_cnt);
|
2002-05-09 00:49:35 +02:00
|
|
|
bp->b_flag |= BFR_DIRTY | BFR_VALID;
|
|
|
|
|
|
|
|
if (xfr_cnt == sizeof(bp->b_buffer)) /* probably not used later */
|
|
|
|
{
|
|
|
|
bp->b_flag |= BFR_UNCACHE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update pointers and counters */
|
|
|
|
count -= xfr_cnt;
|
|
|
|
fnp->f_offset += xfr_cnt;
|
|
|
|
#endif
|
2003-03-13 00:29:08 +01:00
|
|
|
fnp->f_dir.dir_size = fnp->f_offset;
|
2002-05-09 00:49:35 +02:00
|
|
|
merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */
|
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/*
|
|
|
|
comments read optimization for large reads: read total clusters in one piece
|
|
|
|
|
|
|
|
running a program like
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
read(fd, header, sizeof(header)); // small read
|
|
|
|
read(fd, buffer, header.size); // where size is large, up to 63K
|
|
|
|
// with average ~32K
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeDOS 2025 is really slow.
|
|
|
|
on a P200 with modern 30GB harddisk, doing above for a 14.5 MB file
|
|
|
|
|
|
|
|
MSDOS 6.22 clustersize 8K ~2.5 sec (accumulates over clusters, reads for 63 sectors seen),
|
|
|
|
IBM PCDOS 7.0 8K ~4.3
|
|
|
|
IBM PCDOS 7.0 16K ~2.8
|
|
|
|
FreeDOS ke2025 ~17.5
|
|
|
|
|
|
|
|
with the read optimization (ke2025a),
|
|
|
|
|
|
|
|
clustersize 8K ~6.5 sec
|
|
|
|
clustersize 16K ~4.2 sec
|
|
|
|
|
|
|
|
it was verified with IBM feature tool,
|
|
|
|
that the drive read ahead cache (says it) is on. still this huge difference ;-)
|
|
|
|
|
|
|
|
|
|
|
|
it's coded pretty conservative to avoid all special cases,
|
|
|
|
so it shouldn't break anything :-)
|
|
|
|
|
|
|
|
possible further optimization:
|
|
|
|
|
|
|
|
collect read across clusters (if file is not fragmented).
|
|
|
|
MSDOS does this (as readcounts up to 63 sectors where seen)
|
|
|
|
specially important for diskettes, where clustersize is 1 sector
|
|
|
|
|
|
|
|
the same should be done for writes as well
|
|
|
|
|
|
|
|
the time to compile the complete kernel (on some P200) is
|
|
|
|
reduced from 67 to 56 seconds - in an otherwise identical configuration.
|
|
|
|
|
|
|
|
it's not clear if this improvement shows up elsewhere, but it shouldn't harm either
|
|
|
|
|
|
|
|
|
|
|
|
TE 10/18/01 14:00
|
|
|
|
|
|
|
|
collect read across clusters (if file is not fragmented) done.
|
|
|
|
|
|
|
|
seems still to work :-))
|
|
|
|
|
|
|
|
no large performance gains visible, but should now work _much_
|
|
|
|
better for the people, that complain about slow floppy access
|
|
|
|
|
|
|
|
the
|
2003-03-13 00:29:08 +01:00
|
|
|
fnp->f_offset +to_xfer < fnp->f_dir.dir_size && avoid EOF problems
|
2001-11-04 20:47:39 +01:00
|
|
|
|
|
|
|
condition can probably _carefully_ be dropped
|
|
|
|
|
|
|
|
|
|
|
|
TE 10/18/01 19:00
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
/* Read/write block from disk */
|
|
|
|
/* checking for valid access was already done by the functions in
|
|
|
|
dosfns.c */
|
2003-09-24 21:34:11 +02:00
|
|
|
long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
REG f_node_ptr fnp;
|
2000-05-06 21:34:20 +02:00
|
|
|
REG struct buffer FAR *bp;
|
|
|
|
UCOUNT xfr_cnt = 0;
|
|
|
|
UCOUNT ret_cnt = 0;
|
2002-08-04 03:14:18 +02:00
|
|
|
unsigned secsize;
|
|
|
|
unsigned to_xfer = count;
|
2001-11-18 15:01:12 +01:00
|
|
|
ULONG currentblock;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
#if 0 /*DSK_DEBUG*/
|
2000-05-06 21:34:20 +02:00
|
|
|
if (bDumpRdWrParms)
|
|
|
|
{
|
2002-05-09 00:49:35 +02:00
|
|
|
printf("rwblock:fd %02x buffer %04x:%04x count %x\n",
|
2001-03-21 03:56:26 +01:00
|
|
|
fd, FP_SEG(buffer), FP_OFF(buffer), count);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/* 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 */
|
2001-11-18 15:01:12 +01:00
|
|
|
if (fnp == (f_node_ptr) 0 || fnp->f_count <= 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
if (mode==XFR_WRITE)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-05-09 00:49:35 +02:00
|
|
|
fnp->f_dir.dir_attrib |= D_ARCHIVE;
|
|
|
|
fnp->f_flags.f_dmod = TRUE; /* mark file as modified */
|
|
|
|
fnp->f_flags.f_ddate = FALSE; /* set date not valid any more */
|
|
|
|
|
|
|
|
if (dos_extend(fnp) != SUCCESS)
|
|
|
|
return 0;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2002-05-09 00:49:35 +02:00
|
|
|
|
|
|
|
/* Test that we are really about to do a data transfer. If the */
|
|
|
|
/* count is zero and the mode is XFR_READ, just exit. (Any */
|
|
|
|
/* read with a count of zero is a nop). */
|
|
|
|
/* */
|
|
|
|
/* A write (mode is XFR_WRITE) is a special case. It sets the */
|
|
|
|
/* file length to the current length (truncates it). */
|
|
|
|
/* */
|
|
|
|
/* NOTE: doing this up front saves a lot of headaches later. */
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
if (count == 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-05-09 00:49:35 +02:00
|
|
|
/* NOTE: doing this up front made a lot of headaches later :-( TE */
|
|
|
|
/* FAT allocation has to be extended if necessary TE */
|
|
|
|
/* Now done in dos_extend BO */
|
|
|
|
/* remove all the following allocated clusters in shrink_file */
|
|
|
|
if (mode == XFR_WRITE)
|
|
|
|
{
|
2003-03-13 00:29:08 +01:00
|
|
|
fnp->f_dir.dir_size = fnp->f_offset;
|
2002-05-09 00:49:35 +02:00
|
|
|
shrink_file(fnp);
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The variable secsize will be used later. */
|
|
|
|
secsize = fnp->f_dpb->dpb_secsize;
|
|
|
|
|
|
|
|
/* Adjust the far pointer from user space to supervisor space */
|
2004-03-22 17:38:46 +01:00
|
|
|
buffer = adjust_far(buffer);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Do the data transfer. Use block transfer methods so that we */
|
|
|
|
/* can utilize memory management in future DOS-C versions. */
|
|
|
|
while (ret_cnt < count)
|
|
|
|
{
|
2004-03-22 17:56:34 +01:00
|
|
|
unsigned sector, boff;
|
|
|
|
|
2001-11-18 00:26:45 +01:00
|
|
|
/* Do an EOF test and return whatever was transferred */
|
|
|
|
/* but only for regular files. */
|
2003-03-13 00:29:08 +01:00
|
|
|
if (mode == XFR_READ && !(fnp->f_flags.f_ddir) && (fnp->f_offset >= fnp->f_dir.dir_size))
|
2001-11-18 00:26:45 +01:00
|
|
|
{
|
|
|
|
return ret_cnt;
|
|
|
|
}
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* Position the file to the fnode's pointer position. This is */
|
|
|
|
/* done by updating the fnode's cluster, block (sector) and */
|
2002-05-09 00:49:35 +02:00
|
|
|
/* byte offset so that read or write becomes a simple data move */
|
|
|
|
/* into or out of the block data buffer. */
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* The more difficult scenario is the (more common) */
|
|
|
|
/* file offset case. Here, we need to take the fnode's */
|
|
|
|
/* offset pointer (f_offset) and translate it into a */
|
|
|
|
/* relative cluster position, cluster block (sector) */
|
2004-03-22 17:56:34 +01:00
|
|
|
/* offset (sector) and byte offset (boff). Once we */
|
2000-05-06 21:34:20 +02:00
|
|
|
/* have this information, we need to translate the */
|
|
|
|
/* relative cluster position into an absolute cluster */
|
|
|
|
/* position (f_cluster). This is unfortunate because it */
|
|
|
|
/* requires a linear search through the file's FAT */
|
|
|
|
/* entries. It made sense when DOS was originally */
|
|
|
|
/* designed as a simple floppy disk operating system */
|
|
|
|
/* where the FAT was contained in core, but now */
|
|
|
|
/* requires a search through the FAT blocks. */
|
|
|
|
/* */
|
|
|
|
/* The algorithm in this function takes advantage of */
|
|
|
|
/* the blockio block buffering scheme to simplify the */
|
|
|
|
/* task. */
|
|
|
|
#ifdef DISPLAY_GETBLOCK
|
2002-05-09 00:49:35 +02:00
|
|
|
printf("rwblock: ");
|
2000-05-06 21:34:20 +02:00
|
|
|
#endif
|
2002-05-09 00:49:35 +02:00
|
|
|
if (map_cluster(fnp, mode) != SUCCESS)
|
2001-11-18 00:26:45 +01:00
|
|
|
{
|
|
|
|
return ret_cnt;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2002-05-09 00:49:35 +02:00
|
|
|
if (mode == XFR_WRITE)
|
|
|
|
{
|
|
|
|
merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Compute the block within the cluster and the offset */
|
2001-11-18 15:01:12 +01:00
|
|
|
/* within the block. */
|
2004-03-22 17:56:34 +01:00
|
|
|
sector = (UBYTE)(fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask;
|
|
|
|
boff = (UWORD)(fnp->f_offset % secsize);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-03-22 17:56:34 +01:00
|
|
|
currentblock = clus2phys(fnp->f_cluster, fnp->f_dpb) + sector;
|
2001-11-04 20:47:39 +01:00
|
|
|
|
|
|
|
/* see comments above */
|
2001-11-18 15:01:12 +01:00
|
|
|
|
|
|
|
if (!fnp->f_flags.f_ddir && /* don't experiment with directories yet */
|
2004-03-22 17:56:34 +01:00
|
|
|
boff == 0) /* complete sectors only */
|
2001-11-04 20:47:39 +01:00
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
static ULONG startoffset;
|
2002-05-09 00:49:35 +02:00
|
|
|
UCOUNT sectors_to_xfer, sectors_wanted;
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
startoffset = fnp->f_offset;
|
2002-05-09 00:49:35 +02:00
|
|
|
sectors_wanted = to_xfer;
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
/* avoid EOF problems */
|
2003-03-13 00:29:08 +01:00
|
|
|
if (mode == XFR_READ && to_xfer > fnp->f_dir.dir_size - fnp->f_offset)
|
|
|
|
sectors_wanted = (UCOUNT)(fnp->f_dir.dir_size - fnp->f_offset);
|
2002-05-09 00:49:35 +02:00
|
|
|
|
|
|
|
sectors_wanted /= secsize;
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
if (sectors_wanted == 0)
|
|
|
|
goto normal_xfer;
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2004-03-22 17:56:34 +01:00
|
|
|
sectors_to_xfer = fnp->f_dpb->dpb_clsmask + 1 - sector;
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
sectors_to_xfer = min(sectors_to_xfer, sectors_wanted);
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
fnp->f_offset += sectors_to_xfer * secsize;
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
while (sectors_to_xfer < sectors_wanted)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2002-05-09 00:49:35 +02:00
|
|
|
if (map_cluster(fnp, mode) != SUCCESS)
|
2001-11-18 15:01:12 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (clus2phys(fnp->f_cluster, fnp->f_dpb) !=
|
2002-05-09 00:49:35 +02:00
|
|
|
currentblock + sectors_to_xfer)
|
2001-11-18 15:01:12 +01:00
|
|
|
break;
|
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
sectors_to_xfer += fnp->f_dpb->dpb_clsmask + 1;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
sectors_to_xfer = min(sectors_to_xfer, sectors_wanted);
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
fnp->f_offset = startoffset + sectors_to_xfer * secsize;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
|
|
|
}
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
xfr_cnt = sectors_to_xfer * secsize;
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
/* avoid caching trouble */
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
DeleteBlockInBufferCache(currentblock,
|
2002-05-09 00:49:35 +02:00
|
|
|
currentblock + sectors_to_xfer - 1,
|
2003-06-17 10:38:20 +02:00
|
|
|
fnp->f_dpb->dpb_unit, mode);
|
2001-11-18 15:01:12 +01:00
|
|
|
|
|
|
|
if (dskxfer(fnp->f_dpb->dpb_unit,
|
|
|
|
currentblock,
|
2002-05-09 00:49:35 +02:00
|
|
|
(VOID FAR *) buffer, sectors_to_xfer,
|
|
|
|
mode == XFR_READ ? DSKREAD : DSKWRITE))
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
|
|
|
fnp->f_offset = startoffset;
|
2003-09-24 21:34:11 +02:00
|
|
|
return DE_ACCESS;
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
goto update_pointers;
|
|
|
|
}
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
/* normal read: just the old, buffer = sector based read */
|
2002-05-09 00:49:35 +02:00
|
|
|
normal_xfer:
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
#ifdef DSK_DEBUG
|
2004-03-22 11:29:26 +01:00
|
|
|
printf("r/w %d links; dir offset %d, cluster %d, mode %x\n",
|
2002-05-09 00:49:35 +02:00
|
|
|
fnp->f_count, fnp->f_diroff, fnp->f_cluster, mode);
|
2000-05-06 21:34:20 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Get the block we need from cache */
|
2001-11-18 15:01:12 +01:00
|
|
|
bp = getblock(currentblock
|
2002-05-09 00:49:35 +02:00
|
|
|
/*clus2phys(fnp->f_cluster, fnp->f_dpb) + fnp->f_sector */
|
|
|
|
, fnp->f_dpb->dpb_unit);
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
#ifdef DISPLAY_GETBLOCK
|
2002-05-09 00:49:35 +02:00
|
|
|
printf("DATA (rwblock)\n");
|
2000-05-06 21:34:20 +02:00
|
|
|
#endif
|
2001-11-18 15:01:12 +01:00
|
|
|
if (bp == NULL) /* (struct buffer *)0 --> DS:0 !! */
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
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. */
|
2004-03-22 17:56:34 +01:00
|
|
|
xfr_cnt = min(to_xfer, secsize - boff);
|
2002-05-09 00:49:35 +02:00
|
|
|
if (!fnp->f_flags.f_ddir && mode == XFR_READ)
|
2003-03-13 00:29:08 +01:00
|
|
|
xfr_cnt = (UWORD) min(xfr_cnt, fnp->f_dir.dir_size - fnp->f_offset);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
/* 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)
|
|
|
|
{
|
2004-03-22 17:56:34 +01:00
|
|
|
fmemcpy(&bp->b_buffer[boff], buffer, xfr_cnt);
|
2002-05-09 00:49:35 +02:00
|
|
|
bp->b_flag |= BFR_DIRTY | BFR_VALID;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-03-22 17:56:34 +01:00
|
|
|
fmemcpy(buffer, &bp->b_buffer[boff], xfr_cnt);
|
2002-05-09 00:49:35 +02:00
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-05-09 00:49:35 +02:00
|
|
|
/* complete buffer transferred ?
|
2001-11-18 15:01:12 +01:00
|
|
|
probably not reused later
|
|
|
|
*/
|
2001-06-03 16:16:18 +02:00
|
|
|
if (xfr_cnt == sizeof(bp->b_buffer) ||
|
2003-03-13 00:29:08 +01:00
|
|
|
(mode == XFR_READ && fnp->f_offset + xfr_cnt == fnp->f_dir.dir_size))
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
|
|
|
bp->b_flag |= BFR_UNCACHE;
|
|
|
|
}
|
2001-11-04 20:47:39 +01:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* update pointers and counters */
|
2001-11-04 20:47:39 +01:00
|
|
|
fnp->f_offset += xfr_cnt;
|
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
update_pointers:
|
2000-05-06 21:34:20 +02:00
|
|
|
ret_cnt += xfr_cnt;
|
|
|
|
to_xfer -= xfr_cnt;
|
2004-03-22 17:38:46 +01:00
|
|
|
buffer = adjust_far((char FAR *)buffer + xfr_cnt);
|
2002-05-09 00:49:35 +02:00
|
|
|
if (mode == XFR_WRITE)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2003-03-13 00:29:08 +01:00
|
|
|
if (fnp->f_offset > fnp->f_dir.dir_size)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2003-03-13 00:29:08 +01:00
|
|
|
fnp->f_dir.dir_size = fnp->f_offset;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2002-05-09 00:49:35 +02:00
|
|
|
merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */
|
2000-10-30 00:51:56 +01:00
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
REG f_node_ptr fnp;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
if (fnp == (f_node_ptr) 0 || fnp->f_count <= 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
return (LONG) DE_INVLDHNDL;
|
|
|
|
|
|
|
|
/* now do the actual lseek adjustment to the file poitner */
|
|
|
|
|
|
|
|
switch (origin)
|
|
|
|
{
|
|
|
|
/* offset from beginning of file */
|
|
|
|
case 0:
|
|
|
|
return fnp->f_offset = (ULONG) foffset;
|
|
|
|
|
|
|
|
/* offset from current location */
|
|
|
|
case 1:
|
|
|
|
return fnp->f_offset += foffset;
|
|
|
|
|
|
|
|
/* offset from eof */
|
|
|
|
case 2:
|
2003-03-13 00:29:08 +01:00
|
|
|
return fnp->f_offset = fnp->f_dir.dir_size + foffset;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* default to an invalid function */
|
|
|
|
default:
|
|
|
|
return (LONG) DE_INVLDFUNC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns the number of unused clusters */
|
2001-11-18 15:01:12 +01:00
|
|
|
CLUSTER dos_free(struct dpb FAR * dpbp)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
/* There's an unwritten rule here. All fs */
|
|
|
|
/* cluster start at 2 and run to max_cluster+2 */
|
2001-09-23 22:39:44 +02:00
|
|
|
REG CLUSTER i;
|
|
|
|
REG CLUSTER cnt = 0;
|
2004-01-26 01:51:49 +01:00
|
|
|
CLUSTER max_cluster = dpbp->dpb_size;
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
#ifdef WITHFAT32
|
|
|
|
if (ISFAT32(dpbp))
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2001-11-04 20:47:39 +01:00
|
|
|
if (dpbp->dpb_xnfreeclst != XUNKNCLSTFREE)
|
|
|
|
return dpbp->dpb_xnfreeclst;
|
2004-01-26 01:51:49 +01:00
|
|
|
max_cluster = dpbp->dpb_xsize;
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
if (dpbp->dpb_nfreeclst != UNKNCLSTFREE)
|
|
|
|
return dpbp->dpb_nfreeclst;
|
|
|
|
|
2004-01-26 01:51:49 +01:00
|
|
|
for (i = 2; i <= max_cluster; i++)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-11-04 20:47:39 +01:00
|
|
|
if (next_cluster(dpbp, i) == 0)
|
|
|
|
++cnt;
|
|
|
|
}
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
2001-11-18 15:01:12 +01:00
|
|
|
if (ISFAT32(dpbp))
|
|
|
|
{
|
2001-11-04 20:47:39 +01:00
|
|
|
dpbp->dpb_xnfreeclst = cnt;
|
|
|
|
write_fsinfo(dpbp);
|
2000-05-06 21:34:20 +02:00
|
|
|
return cnt;
|
|
|
|
}
|
2001-11-04 20:47:39 +01:00
|
|
|
#endif
|
2004-02-07 19:04:50 +01:00
|
|
|
dpbp->dpb_nfreeclst = (UWORD)cnt;
|
2001-11-04 20:47:39 +01:00
|
|
|
return cnt;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef IPL
|
2002-10-22 04:40:19 +02:00
|
|
|
int dos_cd(char * PathName)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
f_node_ptr fnp;
|
2002-10-22 04:40:19 +02:00
|
|
|
struct cds FAR *cdsp = get_cds(PathName[0] - 'A');
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
if ((media_check(cdsp->cdsDpb) < 0))
|
2001-11-18 15:01:12 +01:00
|
|
|
return DE_INVLDDRV;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* now test for its existance. If it doesn't, return an error. */
|
2001-07-22 03:58:58 +02:00
|
|
|
if ((fnp = dir_open(PathName)) == NULL)
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_PATHNOTFND;
|
2000-05-08 06:30:00 +02:00
|
|
|
|
2004-02-07 19:04:50 +01:00
|
|
|
/* 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;
|
2000-05-06 21:34:20 +02:00
|
|
|
dir_close(fnp);
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Try to allocate an f_node from the available files array */
|
|
|
|
|
2001-06-03 16:16:18 +02:00
|
|
|
f_node_ptr get_f_node(void)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-08-04 03:14:18 +02:00
|
|
|
REG int i;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-03-30 21:30:06 +02:00
|
|
|
for (i = 0; i < f_nodes_cnt; i++)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
if (f_nodes[i].f_count == 0)
|
|
|
|
{
|
|
|
|
++f_nodes[i].f_count;
|
|
|
|
return &f_nodes[i];
|
|
|
|
}
|
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
return (f_node_ptr) 0;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2001-06-03 16:16:18 +02:00
|
|
|
VOID release_f_node(f_node_ptr fnp)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
if (fnp->f_count > 0)
|
|
|
|
--fnp->f_count;
|
|
|
|
else
|
|
|
|
fnp->f_count = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef IPL
|
|
|
|
VOID dos_setdta(BYTE FAR * newdta)
|
|
|
|
{
|
|
|
|
dta = newdta;
|
|
|
|
}
|
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
COUNT dos_getfattr_fd(COUNT fd)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-08-04 03:14:18 +02:00
|
|
|
f_node_ptr fnp = xlt_fd(fd);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* note: an invalid fd is indicated by a 0 return */
|
2002-08-04 03:14:18 +02:00
|
|
|
if (fnp == (f_node_ptr) 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_TOOMANY;
|
|
|
|
|
|
|
|
/* If the fd was invalid because it was out of range or the */
|
|
|
|
/* requested file was not open, tell the caller and exit */
|
|
|
|
if (fnp->f_count <= 0)
|
|
|
|
return DE_FILENOTFND;
|
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
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);
|
2000-05-06 21:34:20 +02:00
|
|
|
dos_close(fd);
|
2001-07-22 03:58:58 +02:00
|
|
|
return result;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2001-07-22 03:58:58 +02:00
|
|
|
COUNT dos_setfattr(BYTE * name, UWORD attrp)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
COUNT fd;
|
2002-08-04 03:14:18 +02:00
|
|
|
f_node_ptr fnp;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* JPP-If user tries to set VOLID or DIR bits, return error */
|
2001-07-22 03:58:58 +02:00
|
|
|
if ((attrp & (D_VOLID | D_DIR | 0xC0)) != 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_ACCESS;
|
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
fd = (short)dos_open(name, O_RDONLY | O_OPEN, 0);
|
|
|
|
if (fd < SUCCESS)
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
fnp = xlt_fd(fd);
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* Set the attribute from the fnode and return */
|
|
|
|
/* clear all attributes but DIR and VOLID */
|
2001-11-18 15:01:12 +01:00
|
|
|
fnp->f_dir.dir_attrib &= (D_VOLID | D_DIR); /* JPP */
|
2002-08-04 03:14:18 +02:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* set attributes that user requested */
|
2001-11-18 15:01:12 +01:00
|
|
|
fnp->f_dir.dir_attrib |= attrp; /* JPP */
|
2000-05-06 21:34:20 +02:00
|
|
|
fnp->f_flags.f_dmod = TRUE;
|
2001-08-19 14:58:36 +02:00
|
|
|
fnp->f_flags.f_ddate = TRUE;
|
2000-05-06 21:34:20 +02:00
|
|
|
dos_close(fd);
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
2001-11-18 15:01:12 +01:00
|
|
|
VOID bpb_to_dpb(bpb FAR * bpbp, REG struct dpb FAR * dpbp, BOOL extended)
|
2001-09-23 22:39:44 +02:00
|
|
|
#else
|
2001-11-18 15:01:12 +01:00
|
|
|
VOID bpb_to_dpb(bpb FAR * bpbp, REG struct dpb FAR * dpbp)
|
|
|
|
#endif
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
ULONG size;
|
2001-11-04 20:47:39 +01:00
|
|
|
REG UWORD shftcnt;
|
2003-08-28 22:30:09 +02:00
|
|
|
bpb sbpb;
|
2001-04-15 05:21:50 +02:00
|
|
|
|
2003-08-28 22:30:09 +02:00
|
|
|
fmemcpy(&sbpb, bpbp, sizeof(sbpb));
|
|
|
|
for (shftcnt = 0; (sbpb.bpb_nsector >> shftcnt) > 1; shftcnt++)
|
2002-01-27 02:13:07 +01:00
|
|
|
;
|
|
|
|
dpbp->dpb_shftcnt = shftcnt;
|
|
|
|
|
2003-08-28 22:30:09 +02:00
|
|
|
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;
|
2002-01-27 02:13:07 +01:00
|
|
|
dpbp->dpb_dirstrt = dpbp->dpb_fatstrt + dpbp->dpb_fats * dpbp->dpb_fatsize;
|
2001-11-04 20:47:39 +01:00
|
|
|
dpbp->dpb_data = dpbp->dpb_dirstrt
|
2002-01-27 02:13:07 +01:00
|
|
|
+ (dpbp->dpb_dirents + dpbp->dpb_secsize/DIRENT_SIZE - 1) /
|
|
|
|
(dpbp->dpb_secsize/DIRENT_SIZE);
|
2004-02-07 19:04:50 +01:00
|
|
|
dpbp->dpb_size = (UWORD)((size - dpbp->dpb_data) >> shftcnt) + 1;
|
2003-08-28 22:30:09 +02:00
|
|
|
{ /* 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 */
|
2003-08-31 12:22:32 +02:00
|
|
|
if (tmp >= 0x10000UL)
|
2003-08-28 22:30:09 +02:00
|
|
|
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:;
|
|
|
|
}
|
2001-09-23 22:39:44 +02:00
|
|
|
dpbp->dpb_flags = 0;
|
2001-11-04 20:47:39 +01:00
|
|
|
dpbp->dpb_cluster = UNKNCLUSTER;
|
2001-09-23 22:39:44 +02:00
|
|
|
/* number of free clusters */
|
2001-11-04 20:47:39 +01:00
|
|
|
dpbp->dpb_nfreeclst = UNKNCLSTFREE;
|
2001-09-23 22:39:44 +02:00
|
|
|
|
|
|
|
#ifdef WITHFAT32
|
|
|
|
if (extended)
|
|
|
|
{
|
2003-08-28 22:30:09 +02:00
|
|
|
dpbp->dpb_xfatsize = sbpb.bpb_nfsect == 0 ? sbpb.bpb_xnfsect
|
|
|
|
: sbpb.bpb_nfsect;
|
2001-11-04 20:47:39 +01:00
|
|
|
dpbp->dpb_xcluster = UNKNCLUSTER;
|
2001-11-18 15:01:12 +01:00
|
|
|
dpbp->dpb_xnfreeclst = XUNKNCLSTFREE; /* number of free clusters */
|
2001-09-23 22:39:44 +02:00
|
|
|
|
|
|
|
dpbp->dpb_xflags = 0;
|
|
|
|
dpbp->dpb_xfsinfosec = 0xffff;
|
|
|
|
dpbp->dpb_xbackupsec = 0xffff;
|
|
|
|
dpbp->dpb_xrootclst = 0;
|
2001-11-04 20:47:39 +01:00
|
|
|
dpbp->dpb_xdata = dpbp->dpb_data;
|
|
|
|
dpbp->dpb_xsize = dpbp->dpb_size;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
|
|
|
if (ISFAT32(dpbp))
|
2001-09-23 22:39:44 +02:00
|
|
|
{
|
2003-08-28 22:30:09 +02:00
|
|
|
dpbp->dpb_xflags = sbpb.bpb_xflags;
|
|
|
|
dpbp->dpb_xfsinfosec = sbpb.bpb_xfsinfosec;
|
|
|
|
dpbp->dpb_xbackupsec = sbpb.bpb_xbackupsec;
|
2001-09-23 22:39:44 +02:00
|
|
|
dpbp->dpb_dirents = 0;
|
|
|
|
dpbp->dpb_dirstrt = 0xffff;
|
2001-11-04 20:47:39 +01:00
|
|
|
dpbp->dpb_size = 0;
|
2001-11-18 15:01:12 +01:00
|
|
|
dpbp->dpb_xdata =
|
|
|
|
dpbp->dpb_fatstrt + dpbp->dpb_fats * dpbp->dpb_xfatsize;
|
2002-01-27 02:13:07 +01:00
|
|
|
dpbp->dpb_xsize = ((size - dpbp->dpb_xdata) >> shftcnt) + 1;
|
2003-08-28 22:30:09 +02:00
|
|
|
dpbp->dpb_xrootclst = sbpb.bpb_xrootclst;
|
2001-09-23 22:39:44 +02:00
|
|
|
read_fsinfo(dpbp);
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
|
|
|
}
|
2001-09-23 22:39:44 +02:00
|
|
|
#endif
|
2001-04-15 05:21:50 +02:00
|
|
|
}
|
|
|
|
|
2003-12-03 00:34:43 +01:00
|
|
|
STATIC int rqblockio(unsigned char command, struct dpb FAR * dpbp)
|
2001-04-15 05:21:50 +02:00
|
|
|
{
|
2003-10-30 15:34:39 +01:00
|
|
|
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;
|
|
|
|
execrh((request FAR *) & MediaReqHdr, dpbp->dpb_device);
|
|
|
|
if ((MediaReqHdr.r_status & S_ERROR) || !(MediaReqHdr.r_status & S_DONE))
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2003-10-30 15:34:39 +01:00
|
|
|
FOREVER
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2003-09-24 21:34:11 +02:00
|
|
|
switch (block_error(&MediaReqHdr, dpbp->dpb_unit, dpbp->dpb_device, 0))
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2003-10-30 15:34:39 +01:00
|
|
|
case ABORT:
|
|
|
|
case FAIL:
|
|
|
|
return DE_INVLDDRV;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2003-10-30 15:34:39 +01:00
|
|
|
case RETRY:
|
|
|
|
goto retry;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2003-10-30 15:34:39 +01:00
|
|
|
case CONTINUE:
|
|
|
|
return SUCCESS;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-10-30 15:34:39 +01:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
COUNT media_check(REG struct dpb FAR * dpbp)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
if (dpbp == NULL)
|
|
|
|
return DE_INVLDDRV;
|
|
|
|
|
|
|
|
/* First test if anyone has changed the removable media */
|
2003-12-03 00:34:43 +01:00
|
|
|
ret = rqblockio(C_MEDIACHK, dpbp);
|
2003-10-30 15:34:39 +01:00
|
|
|
if (ret < SUCCESS)
|
|
|
|
return ret;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-08-04 03:14:18 +02:00
|
|
|
switch (MediaReqHdr.r_mcretcode | dpbp->dpb_flags)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
case M_NOT_CHANGED:
|
|
|
|
/* It was definitely not changed, so ignore it */
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
|
|
/* If it is forced or the media may have changed, */
|
|
|
|
/* rebuild the bpb */
|
|
|
|
case M_DONT_KNOW:
|
2002-08-04 03:14:18 +02:00
|
|
|
/* hazard: no error checking! */
|
2000-05-06 21:34:20 +02:00
|
|
|
flush_buffers(dpbp->dpb_unit);
|
|
|
|
|
|
|
|
/* If it definitely changed, don't know (falls through) */
|
|
|
|
/* or has been changed, rebuild the bpb. */
|
|
|
|
case M_CHANGED:
|
|
|
|
default:
|
|
|
|
setinvld(dpbp->dpb_unit);
|
2003-12-03 00:34:43 +01:00
|
|
|
ret = rqblockio(C_BLDBPB, dpbp);
|
2003-10-30 15:34:39 +01:00
|
|
|
if (ret < SUCCESS)
|
|
|
|
return ret;
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
2002-05-09 00:49:35 +02:00
|
|
|
/* extend dpb only for internal or FAT32 devices */
|
|
|
|
bpb_to_dpb(MediaReqHdr.r_bpptr, dpbp,
|
|
|
|
ISFAT32(dpbp) || FP_SEG(dpbp) == FP_SEG(&os_major));
|
2001-09-23 22:39:44 +02:00
|
|
|
#else
|
2001-04-15 05:21:50 +02:00
|
|
|
bpb_to_dpb(MediaReqHdr.r_bpptr, dpbp);
|
2001-09-23 22:39:44 +02:00
|
|
|
#endif
|
2000-05-06 21:34:20 +02:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* translate the fd into an f_node pointer */
|
2001-06-03 16:16:18 +02:00
|
|
|
f_node_ptr xlt_fd(COUNT fd)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
return fd >= f_nodes_cnt ? (f_node_ptr) 0 : &f_nodes[fd];
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* translate the f_node pointer into an fd */
|
2001-06-03 16:16:18 +02:00
|
|
|
COUNT xlt_fnp(f_node_ptr fnp)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
return (COUNT) (fnp - f_nodes);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2001-07-10 00:19:33 +02:00
|
|
|
/* TE
|
|
|
|
if the current filesize in FAT is larger then the dir_size
|
|
|
|
it's truncated here.
|
|
|
|
the BUG was:
|
|
|
|
copy COMMAND.COM xxx
|
|
|
|
echo >xxx
|
|
|
|
|
|
|
|
then, the dirsize of xxx was set to ~20, but the allocated
|
|
|
|
FAT entries not returned.
|
|
|
|
this code corrects this
|
|
|
|
|
|
|
|
Unfortunately, this code _nearly_ works, but fails one of the
|
2001-11-04 20:47:39 +01:00
|
|
|
Apps tested (VB ISAM); BO: confirmation???
|
2001-07-10 00:19:33 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
STATIC VOID shrink_file(f_node_ptr fnp)
|
|
|
|
{
|
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
ULONG lastoffset = fnp->f_offset; /* has to be saved */
|
|
|
|
CLUSTER next, st;
|
|
|
|
struct dpb FAR *dpbp = fnp->f_dpb;
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2003-03-13 00:29:08 +01:00
|
|
|
fnp->f_offset = fnp->f_dir.dir_size; /* end of file */
|
2001-07-28 20:13:06 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
if (fnp->f_offset)
|
|
|
|
fnp->f_offset--; /* last existing cluster */
|
2001-09-23 22:39:44 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
if (map_cluster(fnp, XFR_READ) != SUCCESS) /* error, don't truncate */
|
|
|
|
goto done;
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
st = fnp->f_cluster;
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
next = next_cluster(dpbp, st);
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2004-03-23 01:45:24 +01:00
|
|
|
if (next == 1) /* error */
|
2001-11-18 15:01:12 +01:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* Loop from start until either a FREE entry is */
|
|
|
|
/* encountered (due to a damaged file system) or the */
|
|
|
|
/* last cluster is encountered. */
|
|
|
|
/* zap the FAT pointed to */
|
|
|
|
|
2003-03-13 00:29:08 +01:00
|
|
|
if (fnp->f_dir.dir_size == 0)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2004-03-23 01:45:24 +01:00
|
|
|
fnp->f_cluster = FREE;
|
2004-01-26 01:51:49 +01:00
|
|
|
setdstart(dpbp, &fnp->f_dir, FREE);
|
2001-11-18 15:01:12 +01:00
|
|
|
link_fat(dpbp, st, FREE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-03-23 01:45:24 +01:00
|
|
|
if (next == LONG_LAST_CLUSTER) /* nothing to do */
|
|
|
|
goto done;
|
2001-11-18 15:01:12 +01:00
|
|
|
link_fat(dpbp, st, LONG_LAST_CLUSTER);
|
|
|
|
}
|
|
|
|
|
|
|
|
wipe_out_clusters(dpbp, next);
|
2001-07-10 00:19:33 +02:00
|
|
|
|
|
|
|
done:
|
2001-11-18 15:01:12 +01:00
|
|
|
fnp->f_offset = lastoffset; /* has to be restored */
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
}
|
2001-09-23 22:39:44 +02:00
|
|
|
|
2001-11-18 00:26:45 +01:00
|
|
|
/*
|
|
|
|
* TE 12 jun 2001 bugs corrected
|
|
|
|
* handles disk full (in a incompatible way :-( )
|
|
|
|
* allows use of last cluster
|
|
|
|
* prevents mkdir, if disk is full (was creating crosslinked dirs)
|
|
|
|
* bugs detected, but NOT corrected
|
|
|
|
* on disk full, MSDOS will NOT write any byte, simply return SUCCESS, 0 bytes
|
|
|
|
* FreeDOS will write all possible bytes, then close file(BUG)
|
|
|
|
*
|
|
|
|
* the dos_mkdir/extenddir (with getblock() instead of getblockOver) was a real
|
|
|
|
* performance killer on large drives. (~0.5 sec /dos_mkdir) TE
|
|
|
|
*/
|