//
// $Header: D:/ext2-os2/RCS/fs_misc.c,v 1.19 1995/08/16 17:37:23 Willm Exp Willm $
//
// Linux ext2 file system driver for OS/2 2.x and WARP - Allows OS/2 to
// access your Linux ext2fs partitions as normal drive letters.
// OS/2 implementation : Copyright (C) 1995 Matthieu WILLM
//
// This program 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 of the License, or
// (at your option) any later version.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#define INCL_DOS
#define INCL_DOSERRORS
#include <os2.h> // From the "Developer Connection Device Driver Kit" version 2.0
#include <dhcalls.h> // From the "Developer Connection Device Driver Kit" version 2.0
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fsd.h>
#include <fsh.h>
/***********************************************************************************/
/*** Fichiers inclus locaux ***/
/***********************************************************************************/
#include <linux/stat.h>
#include <os2/ifsdbg.h>
#include <os2/filefind.h>
#include <os2/cdfsd.h>
#include <os2/errors.h>
#include <os2/log.h> /* Prototypes des fonctions de log.c */
#include <os2/volume.h> /* Prototypes des fonctions de volume.c */
#include <os2/files.h> /* Prototypes des fonctions de files.c */
#include <os2/os2proto.h>
#include <os2/os2misc.h>
#include <linux/fs.h>
#include <linux/fs_proto.h>
#include <linux/e2_fs.h>
#include <linux/e2_proto.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
extern unsigned short getuid(void);
extern void setuid(unsigned short uid);
/***********************************************************************************/
/*** Nom et attributs du FSD ***/
/***********************************************************************************/
char FS_NAME[] = "ext2";
unsigned long FS_ATTRIBUTE = FSA_LVL7;
/***********************************************************************************/
/*** Errors not in bseerr.h (IFS specific or ext2_os2 specific) ***/
/***********************************************************************************/
#define ERROR_VOLUME_NOT_MOUNTED 0xEE00 // IFS specific
#define ERROR_DEVICE_NOT_OPEN 0xEE01 // ext2_os2 specific
/***********************************************************************************/
/*** Some useful defines for FS_OPENCREATE() ... ***/
/***********************************************************************************/
#define OPEN_ACCESS_MASK 0x0007 /* ---- ---- ---- -111 */
#define OPEN_ACCESS_EXECUTE 0x0003 /* ---- ---- ---- -100 */
#define OPEN_SHARE_MASK 0x0070 /* ---- ---- -111 ---- */
#define OPEN_LOCALITY_MASK 0x0700 /* ---- -111 ---- ---- */
#define OPEN_ACTION_EXIST_MASK 0x000F /* ---- ---- ---- 1111 */
#define OPEN_ACTION_NEW_MASK 0x00F0 /* ---- ---- 1111 ---- */
#define FILE_NONFAT 0x0040 // File is non 8.3 compliant
/***********************************************************************************/
/*** Messages ***/
/***********************************************************************************/
extern char Msg_0[]; // Banner
/***********************************************************************************/
/*** Volume related global data ***/
/***********************************************************************************/
#define NB_MAX_VOLS 26
#define VOL_STATUS_FREE 1
#define VOL_STATUS_MOUNTED 2
#define VOL_STATUS_REMOVED 3
typedef struct {
unsigned short hVPB;
int status;
struct super_block *sb;
} volume_list;
typedef struct {
UINT32 sem;
volume_list listvol[NB_MAX_VOLS];
} volume_global_data;
volume_global_data volglobdat;
extern unsigned long Device_Help;
#define THISFILE FILE_TEST_C
/***********************************************************************************/
/*** Some external data ... ***/
/***********************************************************************************/
extern unsigned long event; // To be moved somewhere in a .h file
extern unsigned long cache_size; // To be moved somewhere in a .h file
int Read_Write = 0; // 0 read only - 1 read write
int auto_fsck = 1; // 1 force e2fsck - 0 do not force e2fsck
/***********************************************************************************/
/*** FS_INIT() ***/
/***********************************************************************************/
_FS_RET _FS_ENTRY FS_INIT(
pchar szParm,
unsigned long DevHelp,
unsigned long _FS_PTR pMiniFSD
)
{
pchar pTmp1;
int lg;
int i;
int Quiet = 0;
BufPtr = 0;
BufOpen = 0;
Device_Help = DevHelp;
volglobdat.sem = 0;
for (i = 0; i < NB_MAX_VOLS; i++) {
volglobdat.listvol[i].hVPB = 0;
volglobdat.listvol[i].status = VOL_STATUS_FREE;
volglobdat.listvol[i].sb = 0;
}
if (szParm != 0) {
strupr(szParm);
for (pTmp1 = strtok(szParm, "-/") ; pTmp1 != NULL ; pTmp1 = strtok(NULL, "-/")) {
if (pTmp1 != NULL) {
//
// Per volume disk cache size.
//
if (strncmp(pTmp1, "CACHE:", sizeof("CACHE:") - 1) == 0) {
cache_size = (unsigned long)atol(pTmp1 + sizeof("CACHE:") - 1);
cache_size = ((cache_size * 1024) / 65536) * 65536;
if ((cache_size < 65536) || (cache_size > NB_MAX_SEL_CACHE * 65536)) {
DosWrite(1, "EXT2-OS2 : Invalid cache size - Using 256 Kb\r\n", sizeof("EXT2-OS2 : Invalid cache size - Using 256 Kb\r\n"), &lg);
cache_size = 256L * 1024L;
}
continue;
}
//
// Quiet initialization.
//
if (strncmp(pTmp1, "Q", sizeof("Q") - 1) == 0) {
Quiet = 1;
continue;
}
//
// Read/Write access enabled
//
if (strncmp(pTmp1, "RW", sizeof("RW") - 1) == 0) {
Read_Write = 1;
continue;
}
//
// Disable automatic e2fsck when Linux mounts an ext2fs partition "touched"
// by OS/2.
//
if (strncmp(pTmp1, "NO_AUTO_FSCK", sizeof("NO_AUTO_FSCK") - 1) == 0) {
auto_fsck = 0;
continue;
}
//
// Unknown command line option
//
// DosWrite(1, "EXT2-OS2 : Unknown option ", sizeof("EXT2-OS2 : Unknown option ") - 1, &lg);
// DosWrite(1, pTmp1, strlen(pTmp1), &lg);
// DosWrite(1, "\r\n", sizeof("\r\n") - 1, &lg);
}
}
}
if (!Quiet) {
DosWrite(1, Msg_0, strlen(Msg_0), &lg);
}
return NO_ERROR;
} /*** FS_INIT() ***/
_FS_RET _FS_ENTRY FS_CHGFILEPTR(
struct sffsi _FS_PTR psffsi,
struct sffsd _FS_PTR psffsd,
long offset,
unsigned short type,
unsigned short IOflag
)
{
off_t newfileptr;
struct super_block *sb;
struct file *p_file;
/*******************************************************************/
/*** Gets the superblock from psffsi ***/
/*******************************************************************/
sb = getvolume(psffsi->sfi_hVPB);
/*******************************************************************/
/*******************************************************************/
/*** Gets the file structure from psffsd ***/
/*******************************************************************/
if (!(p_file = ((_sffsd _FS_PTR)psffsd)->p_file)) {
kernel_printf("FS_CHGFILEPTR() - p_file = NULL");
return ERROR_INVALID_PARAMETER;
}
/*******************************************************************/
switch(type) {
case CFP_RELBEGIN :
#ifdef FS_TRACE
kernel_printf("FS_CHFILEPTR( ino = %lu ) - Type CFP_RELBEGIN", p_file->f_inode->i_ino);
#endif
newfileptr = offset;
break;
case CFP_RELCUR :
#ifdef FS_TRACE
kernel_printf("FS_CHFILEPTR( ino = %lu ) - Type CFP_RELCUR", p_file->f_inode->i_ino);
#endif
newfileptr = psffsi->sfi_position + offset;
break;
case CFP_RELEND :
#ifdef FS_TRACE
kernel_printf("FS_CHFILEPTR( ino = %lu ) - Type CFP_RELEND", p_file->f_inode->i_ino);
#endif
newfileptr = p_file->f_inode->i_size + offset;
break;
default :
kernel_printf("FS_CHFILEPTR( ino = %lu ) : unknown type", p_file->f_inode->i_ino);
return ERROR_INVALID_PARAMETER;
}
//
// Offsets below 0 should normally be supported for DOS box requests
//
if (newfileptr < 0) {
kernel_printf("FS_CHGFILEPTR - new file pointer is < 0");
return ERROR_INVALID_PARAMETER;
}
p_file->f_pos = newfileptr;
p_file->f_reada = 0;
p_file->f_version = ++event;
psffsi->sfi_position = newfileptr;
return NO_ERROR;
}
_FS_RET _FS_ENTRY FS_CLOSE(
unsigned short type,
unsigned short IOflag,
struct sffsi _FS_PTR psffsi,
struct sffsd _FS_PTR psffsd
)
{
struct super_block * sb;
struct file * p_file;
int rc;
#ifdef FS_TRACE
kernel_printf("FS_CLOSE(ino = %lu, type = %d)", ((_sffsd _FS_PTR)psffsd)->p_file->f_inode->i_ino, type);
#endif
//
// Gets the superblock from psffsi
//
if (!(sb = getvolume(psffsi->sfi_hVPB))) {
os2_panic("FS_CLOSE - Unable to retrieve superblock");
}
//
// Gets the file structure from psffsd
//
if (!(p_file = ((_sffsd _FS_PTR)psffsd)->p_file)) {
os2_panic("FS_CLOSE - p_file = NULL");
}
//
// The doc isn't clear about the role of the 'type' parameter. It seems we must
// only free the resources (file structure in sffsd) at FS_CL_FORSYS time. Otherwise
// we'' receive an empty sffsd somewhere else !
// For other 'type' values, maybe we could do a flush ...
//
if (type != FS_CL_FORSYS) {
#ifdef FS_TRACE
kernel_printf("***** Non final system close **** - sffsi->sfi_type = %d - Type = %d", psffsi->sfi_type, type);
#endif
return NO_ERROR;
} /* endif */
//
// Final close for the system
//
if ((type == FS_CL_FORSYS) && (Read_Write) && (p_file->f_inode->i_ino != INODE_DASD)) {
if (p_file->f_op && p_file->f_op->release) {
p_file->f_op->release(p_file->f_inode, p_file);
} else {
os2_panic("FS_CLOSE - p_file->f_op == NULL : shouldn't occur in this release");
}
}
//
// Closes the file
//
if ((rc = _close(sb, &p_file)) != NO_ERROR) {
fs_err(FUNC_FS_CLOSE, FUNC_CLOSE, rc, FILE_TEST_C, __LINE__);
return rc;
}
//
// Clean up of sffsd (safety purposes ...)
//
memset(psffsd, 0, sizeof(struct sffsd));
return NO_ERROR;
}
_FS_RET _FS_ENTRY FS_COMMIT(
unsigned short type,
unsigned short IOflag,
struct sffsi _FS_PTR psffsi,
struct sffsd _FS_PTR psffsd
)
{
#ifdef FS_TRACE
kernel_printf("FS_COMMIT");
#endif
if (Read_Write) {
return NO_ERROR; // we must fsync here
} else {
return ERROR_WRITE_PROTECT;
}
}
_FS_RET _FS_ENTRY FS_COPY(
unsigned short flag ,
struct cdfsi _FS_PTR pcdfsi,
struct cdfsd _FS_PTR pcdfsd,
char _FS_PTR pSrc,
unsigned short iSrcCurrDirEnd,
char _FS_PTR pDst,
unsigned short iDstCurrDirEnd,
unsigned short nameType
)
{
#ifdef FS_TRACE
kernel_printf("FS_COPY(%s -> %s)", pSrc, pDst);
#endif
if (Read_Write) {
return ERROR_CANNOT_COPY; // Doscall1.dll should emulate it for us ...
// until someone writes a better COPY routine :-)
} else {
return ERROR_WRITE_PROTECT;
}
}
_FS_RET _FS_ENTRY FS_DELETE(
struct cdfsi _FS_PTR pcdfsi,
struct cdfsd _FS_PTR pcdfsd,
char _FS_PTR pFile,
unsigned short iCurDirEnd
)
{
int rc; /* return code */
struct super_block *sb; /* volume descriptor */
struct inode *dir;
struct file *filp;
ino_t ino_no;
char parent[CCHMAXPATH];
char name[CCHMAXPATH];
id_t myid;
UINT32 DOSmode;
umode_t i_mode;
//
// Trace
//
#ifdef FS_TRACE
kernel_printf("FS_DELETE( %s )", pFile);
#endif
//
// Process identification (to recognize DOS box requests)
//
if ((rc = FSH_QSYSINFO(2, (pchar)&myid, sizeof(id_t))) != NO_ERROR) {
fs_log("erreur FSH_QSYSINFO() dans FS_DELETE");
return rc;
}
if (myid.pdb != 0) {
DOSmode = OPENMODE_DOSBOX;
} else {
DOSmode = 0;
}
if (Read_Write) {
//
// *** This is UGLY ... but it works !
//
sb = getvolume(pcdfsi->cdi_hVPB);
if ((filp = _open_by_name(sb, pFile, OPENMODE_READONLY | DOSmode)) == NULL) {
#ifdef FS_TRACE
fs_err(FUNC_FS_DELETE, FUNC_OPEN_BY_NAME, -1, THISFILE, __LINE__);
#endif
return ERROR_FILE_NOT_FOUND;
} /* end if */
i_mode = filp->f_inode->i_mode;
if ((rc = _close(sb, &filp)) != NO_ERROR) {
fs_err(FUNC_FS_DELETE, FUNC_CLOSE, rc, THISFILE, __LINE__);
return -1;
}
if (!S_ISREG(i_mode)) {
#ifdef FS_TRACE
kernel_printf("FS_DELETE - %s is not a regular file", pFile);
#endif
return ERROR_ACCESS_DENIED;
}
if ((!(i_mode & S_IWUSR)) &&
(!(i_mode & S_IWGRP)) &&
(!(i_mode & S_IWOTH))) {
#ifdef FS_TRACE
kernel_printf("FS_DELETE - %s is read only", pFile);
#endif
return ERROR_ACCESS_DENIED;
}
ExtractPath(pFile, parent);
ExtractName(pFile, name);
if ((filp = _open_by_name(sb, parent, OPENMODE_READONLY | DOSmode)) == NULL) {
#ifdef FS_TRACE
fs_err(FUNC_FS_DELETE, FUNC_OPEN_BY_NAME, -1, THISFILE, __LINE__);
#endif
return ERROR_PATH_NOT_FOUND;
} /* end if */
ino_no = filp->f_inode->i_ino;
if ((rc = _close(sb, &filp)) != NO_ERROR) {
fs_err(FUNC_FS_DELETE, FUNC_CLOSE, rc, THISFILE, __LINE__);
return -1;
}
dir = iget(sb, ino_no);
if ((rc = dir->i_op->unlink (dir, name, strlen(name))) != NO_ERROR) {
kernel_printf("FS_DELETE(%s) : dir->i_op->unlink() - rc = %d", pFile, rc);
}
// iput(dir);
return map_err(rc); // rc is a Linux error code (from linux/errno.h)
} else {
return ERROR_WRITE_PROTECT;
}
}
void _FS_ENTRY FS_EXIT(
unsigned short uid,
unsigned short pid,
unsigned short pdb
)
{
#ifdef FS_TRACE
kernel_printf("FS_EXIT( uid = %u pid = %u pdb = %u )", uid, pid, pdb);
#endif
}
_FS_RET _FS_ENTRY FS_FILEATTRIBUTE(
unsigned short flag,
struct cdfsi _FS_PTR pcdfsi,
struct cdfsd _FS_PTR pcdfsd,
char _FS_PTR pName,
unsigned short iCurDirEnd,
unsigned short _FS_PTR pAttr
)
{
int rc;
struct super_block *sb;
pfile p_file;
char component[CCHMAXPATH];
id_t myid;
UINT32 DOSmode;
//
// Process identification (to recognize DOS box requests)
//
if ((rc = FSH_QSYSINFO(2, (pchar)&myid, sizeof(id_t))) != NO_ERROR) {
fs_log("erreur FSH_QSYSINFO() dans FS_FINDFIRST");
return rc;
}
if (myid.pdb != 0) {
DOSmode = OPENMODE_DOSBOX;
} else {
DOSmode = 0;
}
//
// Gets the superblock from pcdfsi
//
sb = getvolume(pcdfsi->cdi_hVPB);
switch(flag) {
case FA_RETRIEVE :
#ifdef FS_TRACE
kernel_printf("FS_FILEATTRIBUTE( %s ) - flag = FA_RETRIEVE", pName);
#endif
if ((p_file = _open_by_name(sb, pName, OPENMODE_READONLY | DOSmode)) == 0) {
#ifdef FS_TRACE
fs_err(FUNC_FS_FILEATTRIBUTE, FUNC_OPEN_BY_NAME, ERROR_OPEN_FAILED, FILE_TEST_C, __LINE__);
#endif
return ERROR_FILE_NOT_FOUND;
} /* end if */
ExtractName(pName, component);
*pAttr = Linux_To_DOS_Attrs(p_file->f_inode, component);
if ((rc = _close(sb, &p_file)) != NO_ERROR) {
fs_err(FUNC_FS_CLOSE, FUNC_CLOSE, rc, FILE_TEST_C, __LINE__);
return rc;
}
return NO_ERROR;
case FA_SET :
#ifdef FS_TRACE
kernel_printf("FS_FILEATTRIBUTE( %s ) - flag = FA_SET", pName);
#endif
if (Read_Write) {
// We should do something here !!
return NO_ERROR;
} else {
return ERROR_WRITE_PROTECT;
}
default :
kernel_printf("FS_FILEATTRIBUTE() Unknown flag %u", flag);
return ERROR_INVALID_PARAMETER;
}
return NO_ERROR;
}
_FS_RET _FS_ENTRY FS_FLUSHBUF(
unsigned short hVPB,
unsigned short flag
)
{
#ifdef FS_TRACE
kernel_printf("FS_FLUSHBUF(hVPB = %d, flag = %d)", hVPB, flag);
#endif
//
// This seems to be called only after FS_SHUTDOWN, for each volume mounted
//
return NO_ERROR;
}
_FS_RET _FS_ENTRY FS_FSCTL(
union argdat _FS_PTR pArgdat,
unsigned short iArgType,
unsigned short func,
char _FS_PTR pParm,
unsigned short lenParm,
unsigned short _FS_PTR plenParmOut,
char _FS_PTR pData,
unsigned short lenData,
unsigned short _FS_PTR plenDataOut
)
{
int rc;
int i;
struct super_block *sb;
struct vpfsi *pvpfsi;
struct vpfsd *pvpfsd;
switch(func) {
/******************* hack **************************************/
case IFSDBG_FLUSHCACHE :
if (Read_Write) {
for (i = 0 ; i < NB_MAX_VOLS ; i++) {
if (volglobdat.listvol[i].status == VOL_STATUS_MOUNTED) {
FSH_GETVOLPARM(volglobdat.listvol[i].hVPB, &pvpfsi, &pvpfsd);
sb = ((hvolume *)pvpfsd)->p_volume;
if (sb) {
kernel_printf("Flushing volume 0x%0X", volglobdat.listvol[i].hVPB);
sync_volume(sb);
}
}
}
return NO_ERROR;
} else {
return ERROR_NOT_SUPPORTED;
}
case IFSDBG_LAZY_WRITE :
if (Read_Write) {
for (i = 0 ; i < NB_MAX_VOLS ; i++) {
if (volglobdat.listvol[i].status == VOL_STATUS_MOUNTED) {
FSH_GETVOLPARM(volglobdat.listvol[i].hVPB, &pvpfsi, &pvpfsd);
sb = ((hvolume *)pvpfsd)->p_volume;
if (sb) {
lazy_write(sb);
}
}
}
return NO_ERROR;
} else {
return ERROR_NOT_SUPPORTED;
}
/***************************************************************/
case IFSDBG_OPEN :
if (BufOpen == 0) {
BufOpen = 1;
if (BufPtr == 0) {
if ((rc = FSH_SEMSET(&BufSem)) == ERROR_INTERRUPT) {
BufOpen = 0;
return rc;
} /* end if */
} /* end if */
return NO_ERROR;
} else {
return ERROR_DEVICE_IN_USE;
} /* end if */
case IFSDBG_CLOSE:
if (BufOpen == 1) {
BufOpen = 0;
return NO_ERROR;
} else {
return ERROR_DEVICE_NOT_OPEN;
} /* end if */
case IFSDBG_READ:
if (BufOpen == 1) {
/*************************************************************/
/*** Waits on the log semaphore ***/
/*************************************************************/
if ((rc = FSH_SEMWAIT(&BufSem, TO_INFINITE)) == ERROR_INTERRUPT) {
BufOpen = 0;
return rc;
} /* end if */
/*************************************************************/
/*** verify access to the user buffer ***/
/*************************************************************/
if ((rc = FSH_PROBEBUF(1, pData, lenData)) != NO_ERROR) {
return rc;
}
/*************************************************************/
/*** vefify access to the user lenght to be returned ***/
/*************************************************************/
if ((rc = FSH_PROBEBUF(1, (char _FS_PTR)plenDataOut, sizeof(unsigned int))) != NO_ERROR) {
return rc;
}
/*************************************************************/
/*** If no data is present, simply set the semaphore ***/
/*************************************************************/
if (BufPtr == 0) {
*plenDataOut = 0;
if ((rc = FSH_SEMSET(&BufSem)) == ERROR_INTERRUPT) {
BufOpen = 0;
return rc;
} /* end if */
return NO_ERROR;
} /* end if */
/*************************************************************/
/*** If the log data is smaller than the requested amount ***/
/*** we copy them all ***/
/*************************************************************/
if (BufPtr < lenData) {
memcpy(pData, BufMsg, BufPtr + 1);
*plenDataOut = BufPtr + 1;
BufPtr = 0;
if ((rc = FSH_SEMSET(&BufSem)) == ERROR_INTERRUPT) {
BufOpen = 0;
return rc;
} /* end if */
return NO_ERROR;
} /* end if */
/*************************************************************/
/*** We set the log semaphore ***/
/*** ext2-os2.exe will wait on it until some more data is ***/
/*** present ***/
/*************************************************************/
if ((rc = FSH_SEMSET(&BufSem)) == ERROR_INTERRUPT) {
BufOpen = 0;
return rc;
} /* end if */
return NO_ERROR;
} else {
return ERROR_DEVICE_NOT_OPEN;
} /* end if */
case IFSDBG_SETUID :
{
unsigned short uid = *(unsigned short *)pData;
setuid(uid);
return NO_ERROR;
}
default:
#ifdef FS_TRACE
kernel_printf("FS_FSCTL( func = %d ", func);
#endif
return ERROR_NOT_SUPPORTED;
} /* end switch */
}
_FS_RET _FS_ENTRY FS_FSINFO(
unsigned short flag,
unsigned short hVPB,
char _FS_PTR pData,
unsigned short cbData,
unsigned short level
)
{
int rc;
FSALLOCATE *pfsil_alloc;
struct super_block * sb;
struct ext2_super_block *psb;
struct vpfsi _FS_PTR pvpfsi;
struct vpfsd _FS_PTR pvpfsd;
FSINFO *pvolser;
/*******************************************************************/
/*** Traitement des cas suivant flag (INFO_RETRIEVE - INFO_SET) ***/
/*******************************************************************/
switch(flag) {
/*******************************************************************/
/*** INFO_RETRIEVE : retrieves file system information ***/
/*******************************************************************/
case INFO_RETREIVE :
/*******************************************************************/
/*** Verify write access to the user buffer ***/
/*******************************************************************/
if ((rc = FSH_PROBEBUF(PB_OPWRITE, pData, cbData)) != NO_ERROR) {
kernel_printf("FS_FSINFO() - ERROR_BUFFER_OVERFLOW");
return rc;
} /* end if */
/*******************************************************************/
switch(level) {
case FSIL_VOLSER :
#ifdef FS_TRACE
if ((rc = fs_log("FS_FSINFO : flag = INFO_RETREIVE, level = FSIL_VOLSER")) != NO_ERROR) {
return rc;
} /* end if */
#endif
FSH_GETVOLPARM(hVPB, &pvpfsi, &pvpfsd);
if (cbData < sizeof(FSINFO)) {
kernel_printf("FS_FSINFO - buffer overflow");
return ERROR_BUFFER_OVERFLOW;
}
pvolser = (FSINFO *)pData;
pvolser->ulVSN = pvpfsi->vpi_vid;
pvolser->vol.cch = (BYTE)strlen(pvpfsi->vpi_text);
strcpy(pvolser->vol.szVolLabel, pvpfsi->vpi_text);
return NO_ERROR;
case FSIL_ALLOC :
#ifdef FS_TRACE
if ((rc = fs_log("FS_FSINFO : flag = INFO_RETREIVE, level = FSIL_ALLOC")) != NO_ERROR) {
return rc;
} /* end if */
#endif
if (cbData < sizeof(FSALLOCATE)) {
kernel_printf("FS_FSINFO - buffer overflow");
return ERROR_BUFFER_OVERFLOW;
}
sb = getvolume(hVPB);
psb = (struct ext2_super_block *)sb->u.ext2_sb.s_sbh->b_data;
pfsil_alloc = (FSALLOCATE *)pData;
// pfsil_alloc->idFileSystem = ????? ;
pfsil_alloc->cSectorUnit = sb->sectors_per_block;
pfsil_alloc->cUnit = psb->s_blocks_count;
pfsil_alloc->cUnitAvail = (psb->s_free_blocks_count > psb->s_r_blocks_count ? psb->s_free_blocks_count - psb->s_r_blocks_count : 0);
pfsil_alloc->cbSector = (UINT16)sb->sector_size;
return NO_ERROR;
default :
if ((rc = fs_log("FS_FSINFO flag = INFO_RETREIVE, invalid level")) != NO_ERROR) {
return rc;
} /* end if */
return ERROR_INVALID_PARAMETER;
} /* end switch */
break;
/*******************************************************************/
/*******************************************************************/
/*** INFO_SET : used to set the volume label and volume serial ***/
/*** number. We currently do nothing ***/
/*******************************************************************/
case INFO_SET :
#ifdef FS_TRACE
kernel_printf("FS_FSINFO(INFO_SET)");
#endif
if (Read_Write) {
return NO_ERROR;
} else {
return ERROR_WRITE_PROTECT;
}
/*******************************************************************/
/*******************************************************************/
/*** Unknown flag ***/
/*******************************************************************/
default :
if ((rc = kernel_printf("FS_FSINFO() Unknown flag %d", flag)) != NO_ERROR) {
return rc;
} /* end if */
return ERROR_INVALID_PARAMETER;
/*******************************************************************/
} /* end switch */
/*******************************************************************/
return NO_ERROR;
}
_FS_RET _FS_ENTRY FS_IOCTL(
struct sffsi _FS_PTR psffsi,
struct sffsd _FS_PTR psffsd,
unsigned short cat,
unsigned short func,
char _FS_PTR pParm,
unsigned short lenParm,
unsigned _FS_PTR pParmLenInOut,
char _FS_PTR pData,
unsigned short lenData,
unsigned _FS_PTR pDataLenInOut
)
{
int rc;
struct vpfsi _FS_PTR pvpfsi;
struct vpfsd _FS_PTR pvpfsd;
#ifdef FS_TRACE
kernel_printf("FS_IOCTL( cat = 0x%0X, func = 0x%0X )", cat, func);
#endif
FSH_GETVOLPARM(psffsi->sfi_hVPB, &pvpfsi, &pvpfsd);
if ((rc = FSH_DEVIOCTL(
0,
pvpfsi->vpi_hDEV,
psffsi->sfi_selfsfn, /* sfn */
cat,
func,
pParm,
*pParmLenInOut,
pData,
*pDataLenInOut
)) != NO_ERROR) {
fs_log("FS_IOCTL() - Erreur FSH_DEVIOCTL");
return rc;
}
return NO_ERROR;
}
_FS_RET _FS_ENTRY FS_MOUNT(
unsigned short flag,
struct vpfsi _FS_PTR pvpfsi,
struct vpfsd _FS_PTR pvpfsd,
unsigned short hVPB,
char _FS_PTR pBoot
)
{
int rc;
int i;
struct super_block *sb;
unsigned short oldhVPB;
switch(flag) {
case MOUNT_MOUNT :
kernel_printf("FS_MOUNT flg = MOUNT_MOUNT hVPB = 0x%04X", hVPB);
//
// We zero out pvpfsd ... for safety purposes !
//
memset(pvpfsd, 0, sizeof(struct vpfsd));
//
// First make a (small) test to see if it can be a ext2fs volume
// This is NECESSARY since we could get a FS_MOUNT call for a volume
// already mounted by another IFS. In this case we MUST know it's not
// an ext2fs volume BEFORE calling FSH_FINDDUPHVPB (...if not we'll see
// later a MOUNT_RELEASE for a non ext2fs volume !! The test case is :
// put cdfs.ifs after ext2-os2.ifs in CONFIG.SYS, and start WinOS2 file manager)
//
if (!Check_Ext2fs_magic(pvpfsi, hVPB)) {
return ERROR_VOLUME_NOT_MOUNTED;
}
//
// The volume serial number is a CRC checksum of the boot sector
//
pvpfsi->vpi_vid = updcrc((unsigned char *)pBoot, pvpfsi->vpi_bsize);
//
// The volume label is dummy for the moment ("ext2fs_<drive>")
//
sprintf(pvpfsi->vpi_text, "EXT2FS_%c", pvpfsi->vpi_unit + 'A');
//
// Is there another instance of the drive ?
// - Yes : update internal volume table and return silently
// - No : continue the mount process
//
if ((rc = FSH_FINDDUPHVPB(hVPB, &oldhVPB)) == NO_ERROR) {
kernel_printf(" \tFSH_FINDDUPHVPB(0x%0X) - Found dup hVPB 0x%0X", hVPB, oldhVPB);
//
// We insert the new dup hVPB in the table so that it can be MOUNT_RELEASEd
//
i = 0;
while ((volglobdat.listvol[i].status != VOL_STATUS_FREE) && (i<NB_MAX_VOLS)) {
i++;
}
if (i == NB_MAX_VOLS) {
fs_log("ERROR : No more volumes ");
return ERROR_VOLUME_NOT_MOUNTED;
}
volglobdat.listvol[i].hVPB = hVPB;
volglobdat.listvol[i].status = VOL_STATUS_MOUNTED;
volglobdat.listvol[i].sb = 0;
//
// We update the status of the old hVPB if necessary
//
i = 0;
while ((volglobdat.listvol[i].hVPB != oldhVPB) && (i < NB_MAX_VOLS)) {
i++;
}
if (i == NB_MAX_VOLS) {
os2_panic("ERROR : Cannot find dup volume in my internal tables !");
}
if (volglobdat.listvol[i].status == VOL_STATUS_REMOVED) {
kernel_printf("Remounting removed volume");
volglobdat.listvol[i].status == VOL_STATUS_MOUNTED;
}
return NO_ERROR;
} else {
kernel_printf(" \tFSH_FINDDUPHVPB(0x%0X) - No dup hVPB", hVPB);
}
i = 0;
while ((volglobdat.listvol[i].status != VOL_STATUS_FREE) && (i<NB_MAX_VOLS)) {
i++;
}
if (i == NB_MAX_VOLS) {
fs_log("ERROR : No more volumes");
return ERROR_VOLUME_NOT_MOUNTED;
}
if ((sb = openvolume(pvpfsi, hVPB)) == 0) {
return ERROR_VOLUME_NOT_MOUNTED;
} /* end if */
((hvolume *)pvpfsd)->p_volume = sb;
volglobdat.listvol[i].hVPB = hVPB;
volglobdat.listvol[i].status = VOL_STATUS_MOUNTED;
volglobdat.listvol[i].sb = sb;
kernel_printf("Volume characteristics :");
kernel_printf("\t volume id : 0x%08X", pvpfsi->vpi_vid);
kernel_printf("\t hDEV : 0x%08X", pvpfsi->vpi_hDEV);
kernel_printf("\t sector size : %u", pvpfsi->vpi_bsize);
kernel_printf("\t sector/track : %u", pvpfsi->vpi_trksec);
kernel_printf("\t heads : %u", pvpfsi->vpi_nhead);
kernel_printf("\t tot sectors : %lu", pvpfsi->vpi_totsec);
kernel_printf("\t drive (0=A) : %d", (int)(pvpfsi->vpi_drive));
kernel_printf("\t unit code : %d", (int)(pvpfsi->vpi_unit));
kernel_printf("\t volume label : %s", pvpfsi->vpi_text);
kernel_printf("\t hVPB : 0x%08X", hVPB);
return NO_ERROR;
case MOUNT_VOL_REMOVED :
kernel_printf("FS_MOUNT flg = MOUNT_VOL_REMOVED hVPB = 0x%04X", hVPB);
i = 0;
while ((volglobdat.listvol[i].hVPB != hVPB) && (i<NB_MAX_VOLS)) {
i++;
}
if (i == NB_MAX_VOLS) {
fs_log("ERROR : volume not found !");
return -1;
}
if (volglobdat.listvol[i].status != VOL_STATUS_MOUNTED) {
fs_log("ERROR : invalid volume status !");
return -1;
}
volglobdat.listvol[i].status = VOL_STATUS_REMOVED;
return NO_ERROR;
case MOUNT_RELEASE :
kernel_printf("FS_MOUNT flg = MOUNT_RELEASE hVPB = 0x%04X", hVPB);
i = 0;
while ((volglobdat.listvol[i].hVPB != hVPB) && (i<NB_MAX_VOLS)) {
i++;
}
if (i == NB_MAX_VOLS) {
fs_log("ERROR : volume not found !");
return -1;
}
if ((volglobdat.listvol[i].status != VOL_STATUS_MOUNTED) &&
(volglobdat.listvol[i].status != VOL_STATUS_REMOVED)) {
fs_log("ERROR : invalid volume status !");
return -1;
}
//
// Now we unmount the volume
//
sb = ((hvolume _FS_PTR)pvpfsd)->p_volume;
if (sb) {
if ((volglobdat.listvol[i].status == VOL_STATUS_MOUNTED) &&
(Read_Write)) {
{
struct file *f;
f = sb->usedhfiles;
while (f) {
_close(sb, &f);
f = sb->usedhfiles;
}
}
sync_inodes(sb->s_dev);
invalidate_inodes(sb->s_dev);
ext2_put_super(sb);
sync_volume(sb);
}
volglobdat.listvol[i].status = VOL_STATUS_FREE; // To protect us against lazy write ....
if ((rc = free_volume(&(((hvolume _FS_PTR)pvpfsd)->p_volume))) != NO_ERROR) {
kernel_printf("ERROR - free_volume returned %d", rc);
// return rc;
}
memset(pvpfsd, 0, sizeof(struct vpfsd));
}
volglobdat.listvol[i].sb = 0;
volglobdat.listvol[i].status = VOL_STATUS_FREE;
return NO_ERROR;
case MOUNT_ACCEPT :
kernel_printf("FS_MOUNT flg = MOUNT_ACCEPT hVPB = 0x%04X", hVPB);
return ERROR_NOT_SUPPORTED;
default :
kernel_printf("FS_MOUNT() invalid flag %d", flag);
return ERROR_INVALID_PARAMETER;
} /* end switch */
}
_FS_RET _FS_ENTRY FS_MOVE(
struct cdfsi _FS_PTR pcdfsi,
struct cdfsd _FS_PTR pcdfsd,
char _FS_PTR pSrc,
unsigned short iSrcCurDirEnd,
char _FS_PTR pDst,
unsigned short iDstCurDirEnd,
unsigned short flags
)
{
int error;
char *srcPath, *srcName, *dstPath, *dstName;
struct inode *isrcdir, *idstdir;
struct file *file;
struct super_block *sb;
#ifdef FS_TRACE
kernel_printf("FS_MOVE(%s -> %s)", pSrc, pDst);
#endif
sb = getvolume(pcdfsi->cdi_hVPB);
if (!Read_Write) {
return ERROR_WRITE_PROTECT;
}
if ((srcPath = G_malloc(4 * CCHMAXPATH)) == NULL) {
kernel_printf("FS_MOVE - G_malloc failed !");
return ERROR_NOT_ENOUGH_MEMORY;
}
srcName = srcPath + CCHMAXPATH;
dstPath = srcName + CCHMAXPATH;
dstName = dstPath + CCHMAXPATH;
ExtractPath(pSrc, srcPath); // Source path
ExtractName(pSrc, srcName); // Source name
ExtractPath(pDst, dstPath); // Destination path
ExtractName(pDst, dstName); // Destination name
//
// Does the destination path exists ? (this is a hack until I write a true dir_namei routine)
//
if ((file = _open_by_name(sb, dstPath, OPENMODE_READONLY)) == NULL) {
kernel_printf("FS_MOVE() - Destination path %s not found", dstPath);
G_free(srcPath);
return ERROR_PATH_NOT_FOUND;
} /* end if */
idstdir = file->f_inode;
free_hfile(sb, file);
//
// Does the source path exists ? (this is a hack until I write a true dir_namei routine)
//
if ((file = _open_by_name(sb, srcPath, OPENMODE_READONLY)) == NULL) {
kernel_printf("FS_MOVE() - Source path %s not found", srcPath);
iput(idstdir);
G_free(srcPath);
return ERROR_PATH_NOT_FOUND;
} /* end if */
isrcdir = file->f_inode;
free_hfile(sb, file);
//
// Now we do the move operation
//
idstdir->i_count++;
down(&idstdir->i_sem);
if (isrcdir->i_op && isrcdir->i_op->rename) {
error = isrcdir->i_op->rename(isrcdir, srcName, strlen(srcName),
idstdir, dstName, strlen(dstName));
} else {
if (!isrcdir->i_op)
os2_panic("FS_MOVE - isrcdir->i_op = 0 - shoudn't occur for ext2-os2");
if (!isrcdir->i_op->rename)
os2_panic("FS_MOVE - isrcdir->i_op->rename = 0 - shoudn't occur for ext2-os2");
}
up(&idstdir->i_sem);
iput(idstdir);
G_free(srcPath);
return map_err(error);
}
_FS_RET _FS_ENTRY FS_NEWSIZE(
struct sffsi _FS_PTR psffsi,
struct sffsd _FS_PTR psffsd,
unsigned long len,
unsigned short IOflag
)
{
struct file *filp;
#ifdef FS_TRACE
kernel_printf("FS_NEWSIZE(ino = %lu, sz = %lu)", ((_sffsd *)psffsd)->p_file->f_inode->i_ino, len);
#endif
if (!Read_Write) {
kernel_printf("ERROR ! FS_NEWSIZE called and write access not enabled");
return ERROR_WRITE_PROTECT;
}
filp = ((_sffsd *)psffsd)->p_file;
if (!filp) {
kernel_printf("FS_NEWSIZE() - p_file = NULL");
return ERROR_INVALID_PARAMETER;
}
if (filp->f_inode->i_ino == INODE_DASD) {
kernel_printf("FS_NEWSIZE() called on a direct access device handle !");
return ERROR_INVALID_PARAMETER;
}
filp->f_inode->i_size = len;
psffsi->sfi_size = len;
return NO_ERROR;
}
_FS_RET _FS_ENTRY FS_OPENCREATE(
struct cdfsi _FS_PTR pcdfsi,
struct cdfsd _FS_PTR pcdfsd,
char _FS_PTR pName,
unsigned short iCurDirEnd,
struct sffsi _FS_PTR psffsi,
struct sffsd _FS_PTR psffsd,
unsigned long ulOpenMode,
unsigned short openflag,
unsigned short _FS_PTR pAction,
unsigned short attr,
char _FS_PTR pEABuf,
unsigned short _FS_PTR pfgenFlag
)
{
int rc;
struct super_block * sb;
pfile p_file, dir;
UINT32 openmode, DOSmode;
UINT32 accessmode;
UINT16 newflag, existflag;
id_t myid;
char component[CCHMAXPATH];
char parent[CCHMAXPATH];
struct inode *inode;
struct inode *inode_parent;
ino_t ino_no;
#ifdef FS_TRACE
if ((rc = kernel_printf("FS_OPENCREATE( %s )", pName)) != NO_ERROR) {
return rc;
} /* end if */
#endif
//
// Process identification (to recognize DOS box requests)
//
if ((rc = FSH_QSYSINFO(2, (pchar)&myid, sizeof(id_t))) != NO_ERROR) {
fs_log("erreur FSH_QSYSINFO() dans FS_FINDFIRST");
return rc;
}
if (myid.pdb != 0) {
DOSmode = OPENMODE_DOSBOX;
} else {
DOSmode = 0;
}
//
// Gets the superblock from psffsi
//
sb = getvolume(psffsi->sfi_hVPB);
#ifdef FS_TRACE
if (ulOpenMode & OPEN_FLAGS_DASD) {
fs_log("OPEN_FLAGS_DASD");
}
if (ulOpenMode & OPEN_FLAGS_WRITE_THROUGH) {
fs_log("OPEN_FLAGS_WRITE_THROUGH");
}
if (ulOpenMode & OPEN_FLAGS_FAIL_ON_ERROR) {
fs_log("OPEN_FLAGS_FAIL_ON_ERROR");
}
if (ulOpenMode & OPEN_FLAGS_NO_CACHE) {
fs_log("OPEN_FLAGS_NO_CACHE");
}
if (ulOpenMode & OPEN_FLAGS_NOINHERIT) {
fs_log("OPEN_FLAGS_NO_INHERIT");
}
#endif
accessmode = ulOpenMode & OPEN_ACCESS_MASK;
if (accessmode == OPEN_ACCESS_READONLY) {
#ifdef FS_TRACE
fs_log("OPEN_ACCESS_READONLY");
#endif
openmode = OPENMODE_READONLY;
}
if (accessmode == OPEN_ACCESS_WRITEONLY) {
#ifdef FS_TRACE
fs_log("OPEN_ACCESS_WRITEONLY");
#endif
openmode = OPENMODE_WRITEONLY;
}
if (accessmode == OPEN_ACCESS_READWRITE) {
#ifdef FS_TRACE
fs_log("OPEN_ACCESS_READWRITE");
#endif
openmode = OPENMODE_READWRITE;
}
#ifdef FS_TRACE
if (accessmode == OPEN_ACCESS_EXECUTE) {
fs_log("OPEN_ACCESS_EXECUTE");
}
#endif
newflag = openflag & OPEN_ACTION_NEW_MASK;
#ifdef FS_TRACE
if (newflag == OPEN_ACTION_FAIL_IF_NEW) {
fs_log("OPEN_ACTION_FAIL_IF_NEW");
}
if (newflag == OPEN_ACTION_CREATE_IF_NEW) {
fs_log("OPEN_ACTION_CREATE_IF_NEW");
}
#endif
existflag = openflag & OPEN_ACTION_EXIST_MASK;
#ifdef FS_TRACE
if (existflag == OPEN_ACTION_OPEN_IF_EXISTS) {
fs_log("OPEN_ACTION_OPEN_IF_EXISTS");
}
if (existflag == OPEN_ACTION_FAIL_IF_EXISTS) {
fs_log("OPEN_ACTION_FAIL_IF_EXISTS");
}
if (existflag == OPEN_ACTION_REPLACE_IF_EXISTS) {
fs_log("OPEN_ACTION_REPLACE_IF_EXISTS");
}
#endif
if ((!Read_Write) &&
((accessmode == OPEN_ACCESS_READWRITE) ||
(accessmode == OPEN_ACCESS_WRITEONLY))) {
fs_log("FS_OPENCREATE() - Write access not enabled");
return ERROR_WRITE_PROTECT;
}
//
// Direct access open of the whole device
//
if (ulOpenMode & OPEN_FLAGS_DASD) {
kernel_printf("OPEN_FLAGS_DASD");
if ((p_file = _open_by_inode(sb, INODE_DASD, openmode)) == 0) {
kernel_printf("FS_OPENCREATE() - couldn't DASD open %s", pName);
return ERROR_OPEN_FAILED;
}
((_sffsd _FS_PTR)psffsd)->p_file = p_file;
psffsi->sfi_tstamp = ST_SCREAT | ST_PCREAT;
psffsi->sfi_size = p_file->f_inode->i_size;
psffsi->sfi_position = p_file->f_pos;
date_unix2dos(p_file->f_inode->i_ctime, &(psffsi->sfi_ctime), &(psffsi->sfi_cdate));
date_unix2dos(p_file->f_inode->i_ctime, &(psffsi->sfi_atime), &(psffsi->sfi_adate));
date_unix2dos(p_file->f_inode->i_ctime, &(psffsi->sfi_mtime), &(psffsi->sfi_mdate));
return NO_ERROR;
}
//
// Now that we treated the OPEN_FLAGS_DASD special case, lets treat the general case :
// Try to open the file readonly
// Success : the file exists
// if !S_ISDIR && !S_ISREG => error
// if OPEN_ACTION_FAIL_IF_EXISTS set => error
// if OPEN_ACTION_OPEN_IF_EXISTS set
// <test file attrs>
// change the open mode and return OK
// if OPEN_ACTION_REPLACE_IF_EXISTS set
// OPEN_ACCESS_READONLY or OPEN_ACCESS_EXECUTE set => error
// OPEN_ACCESS_READWRITE or OPEN_ACCESS_WRITEONLY set
// truncate
// change openmode and return
// Failure : the file does not exist
// OPEN_ACCESS_READONLY or OPEN_ACCESS_EXECUTE set => error
// OPEN_ACCESS_READWRITE or OPEN_ACCESS_WRITEONLY set
// if OPEN_ACTION_CREATE_IF_NEW set
// try to create the file
// open the file and return
// if OPEN_ACTION_FAIL_IF_NEW set => error
p_file = _open_by_name(sb, pName, openmode | DOSmode);
if (p_file) { // The file exists
//
// If it's not a regular file or a directory we cannot open
//
if (!S_ISREG(p_file->f_inode->i_mode)) {
kernel_printf("Can't FS_OPENCREATE - %s is not a regular file", pName);
if ((rc =_close(sb, &p_file)) != NO_ERROR) {
fs_err(FUNC_FS_OPENCREATE, FUNC_CLOSE, rc, FILE_TEST_C, __LINE__);
return rc;
}
return ERROR_ACCESS_DENIED;
}
//
// if OPEN_ACTION_FAIL_IF_EXISTS set => error
//
if (existflag == OPEN_ACTION_FAIL_IF_EXISTS) {
#ifdef FS_TRACE
fs_log("Can't FS_OPENCREATE() - File exists & OPEN_ACTION_FAIL_IF_EXISTS");
#endif
if ((rc =_close(sb, &p_file)) != NO_ERROR) {
fs_err(FUNC_FS_OPENCREATE, FUNC_CLOSE, rc, FILE_TEST_C, __LINE__);
return rc;
}
return ERROR_FILE_EXISTS;
}
//
// if OPEN_ACTION_OPEN_IF_EXISTS : OK
//
if (existflag == OPEN_ACTION_OPEN_IF_EXISTS) {
*pAction = FILE_EXISTED;
}
//
// if OPEN_ACTION_REPLACE_IF_EXISTS : truncate
//
if (existflag == OPEN_ACTION_REPLACE_IF_EXISTS) {
p_file->f_inode->i_op->truncate(p_file->f_inode);
p_file->f_flags = O_TRUNC;
*pAction = FILE_TRUNCATED;
}
} else { // The file doesn't exist
ExtractPath(pName, parent);
ExtractName(pName, component);
//
// We try to open the parent dir
//
if ((dir = _open_by_name(sb, parent, OPENMODE_READONLY | DOSmode)) == 0) {
kernel_printf("FS_OPENCREATE() - The parent directory %s doesn't seem to exist", parent);
return ERROR_PATH_NOT_FOUND;
}
//
// The parent dir exists
//
//
// If the file is open for execution : error (it doesn't even exist)
//
if (accessmode == OPEN_ACCESS_EXECUTE) {
#ifdef FS_TRACE
fs_log("Can't FS_OPENCREATE() - File doesn't exist & OPEN_ACCESS_EXECUTE");
#endif
if ((rc =_close(sb, &dir)) != NO_ERROR) {
fs_err(FUNC_FS_OPENCREATE, FUNC_CLOSE, rc, FILE_TEST_C, __LINE__);
return rc;
}
return ERROR_FILE_NOT_FOUND;
}
//
// If the file is open for writing or readwrite ...
//
if ((accessmode == OPEN_ACCESS_READONLY) ||
(accessmode == OPEN_ACCESS_READWRITE) ||
(accessmode == OPEN_ACCESS_WRITEONLY)) {
if (newflag == OPEN_ACTION_FAIL_IF_NEW) {
#ifdef FS_TRACE
fs_log("Can't FS_OPENCREATE() - File doesn't exist & OPEN_ACTION_FAIL_IF_NEW");
#endif
if ((rc =_close(sb, &dir)) != NO_ERROR) {
fs_err(FUNC_FS_OPENCREATE, FUNC_CLOSE, rc, FILE_TEST_C, __LINE__);
return rc;
}
return ERROR_OPEN_FAILED;
}
if (newflag == OPEN_ACTION_CREATE_IF_NEW) {
ino_no = dir->f_inode->i_ino;
if ((rc = _close(sb, &dir)) != NO_ERROR) {
fs_err(FUNC_FS_OPENCREATE, FUNC_CLOSE, rc, THISFILE, __LINE__);
return rc;
}
inode_parent = iget(sb, ino_no);
inode_parent->i_count++;
down(&inode_parent->i_sem);
rc = inode_parent->i_op->create (inode_parent,component, strlen(component), S_IRWXU | S_IFREG , &inode);
up(&inode_parent->i_sem);
if (rc) {
kernel_printf("Couldn't create %s", pName);
iput(inode_parent);
return rc;
}
ino_no = inode->i_ino;
iput(inode_parent);
iput(inode);
if ((p_file = _open_by_inode(sb, ino_no, openmode)) == 0) {
kernel_printf("open_by_inode(%lu) failed in FS_OPENCREATE", ino_no);
return ERROR_OPEN_FAILED;
}
p_file->f_flags = O_CREAT;
*pAction = FILE_CREATED;
}
}
}
((_sffsd _FS_PTR)psffsd)->p_file = p_file;
psffsi->sfi_tstamp = ST_SCREAT | ST_PCREAT | ST_PREAD | ST_SREAD | ST_PWRITE | ST_SWRITE;
psffsi->sfi_size = p_file->f_inode->i_size;
psffsi->sfi_position = p_file->f_pos;
date_unix2dos(p_file->f_inode->i_ctime, &(psffsi->sfi_ctime), &(psffsi->sfi_cdate));
date_unix2dos(p_file->f_inode->i_ctime, &(psffsi->sfi_atime), &(psffsi->sfi_adate));
date_unix2dos(p_file->f_inode->i_ctime, &(psffsi->sfi_mtime), &(psffsi->sfi_mdate));
psffsi->sfi_DOSattr = (unsigned char)Linux_To_DOS_Attrs(p_file->f_inode, component);
if ((ulOpenMode & OPEN_FLAGS_WRITE_THROUGH) ||
(ulOpenMode & OPEN_FLAGS_NO_CACHE)) {
p_file->f_flags |= O_SYNC;
p_file->f_inode->i_flags |= MS_SYNCHRONOUS;
}
return NO_ERROR;
}
_FS_RET _FS_ENTRY FS_PROCESSNAME(
pchar pNameBuf
)
{
id_t myid;
int rc;
#ifdef FS_TRACE
kernel_printf("FS_PROCESSNAME( %s )", pNameBuf);
#endif
//
// Process identification (to recognize DOS box requests)
//
if ((rc = FSH_QSYSINFO(2, (pchar)&myid, sizeof(id_t))) != NO_ERROR) {
fs_log("erreur FSH_QSYSINFO() dans FS_FINDFIRST");
return rc;
}
if (myid.pdb != 0) { // DOS Box request => uppercase
FSH_UPPERCASE(pNameBuf, CCHMAXPATH, pNameBuf);
}
return NO_ERROR;
}
_FS_RET _FS_ENTRY FS_READ(
struct sffsi _FS_PTR psffsi,
struct sffsd _FS_PTR psffsd,
char _FS_PTR pData,
unsigned short _FS_PTR pLen,
unsigned short IOflag
)
{
int rc = NO_ERROR;
pfile p_file;
struct super_block * sb;
UINT32 BytesRead;
#ifdef FS_TRACE
kernel_printf("FS_READ(ino = %lu, len = %d", ((_sffsd _FS_PTR)psffsd)->p_file->f_inode->i_ino, *pLen);
#endif
//
// Verify we have write access to the user buffer
//
if ((rc = FSH_PROBEBUF(PB_OPWRITE, pData, *pLen)) != NO_ERROR) {
fs_err(FUNC_FS_READ, FUNC_FSH_PROBEBUF, rc, FILE_TEST_C, __LINE__);
return rc;
} /* end if */
//
// Gets the superblock from psffsi
//
sb = getvolume(psffsi->sfi_hVPB);
//
// Gets the file structure from psffsd
//
p_file = ((_sffsd _FS_PTR)psffsd)->p_file;
if (!(p_file = ((_sffsd _FS_PTR)psffsd)->p_file)) {
kernel_printf("FS_READ() - p_file = NULL");
return ERROR_INVALID_PARAMETER;
}
//
// Tests if it is a regular file
//
if (!S_ISREG(p_file->f_inode->i_mode)) {
kernel_printf("Can't FS_READ( %lu ) - Not a regular file", p_file->f_inode->i_ino);
*pLen = 0;
return ERROR_ACCESS_DENIED;
}
//
// If the file position in psffsi is not consistent with the
// one in the file structure in psffsd, something went wrong => panic
//
if (psffsi->sfi_position != (UINT32)p_file->f_pos) {
kernel_printf("FS_READ( %lu ) very weird : psffsi->sfi_position (%ld) != p_file->f_pos (%ld)", p_file->f_inode->i_ino, psffsi->sfi_position, p_file->f_pos);
*pLen = 0;
return ERROR_READ_FAULT; // Maybe we should FSH_INTERR ?
}
rc = VFS_read(p_file, pData, (UINT32)*pLen, &BytesRead);
*pLen = (UINT16)BytesRead;
psffsi->sfi_tstamp = ST_SREAD | ST_PREAD;
psffsi->sfi_position = p_file->f_pos;
return rc;
}
_FS_RET _FS_ENTRY FS_SHUTDOWN(
unsigned short usType,
unsigned long ulReserved
)
{
int rc;
int i;
struct super_block *sb;
struct vpfsi *pvpfsi;
struct vpfsd *pvpfsd;
if ((rc = fs_log("FS_SHUTDOWN")) != NO_ERROR) {
return rc;
} /* end if */
switch(usType) {
case SD_BEGIN :
break;
case SD_COMPLETE :
//
// Normally at this stage the system should have commited/closed every
// file handles.
//
for (i = 0 ; i < NB_MAX_VOLS ; i++) {
if (volglobdat.listvol[i].status == VOL_STATUS_MOUNTED) {
FSH_GETVOLPARM(volglobdat.listvol[i].hVPB, &pvpfsi, &pvpfsd);
sb = ((hvolume *)pvpfsd)->p_volume;
if ((sb) && (Read_Write)) {
kernel_printf("Flushing volume 0x%0X", volglobdat.listvol[i].hVPB);
//
// Are there any opened files yet (normally no) ?
// This closes pending search handles (the WPS seems to let pending
// search handles opened ...)
//
{
struct file *f;
f = sb->usedhfiles;
while (f) {
kernel_printf("FS_SHUTDOWN - Found opened file %lu", f->f_inode->i_ino);
_close(sb, &f);
f = sb->usedhfiles;
}
}
sync_inodes(sb->s_dev);
invalidate_inodes(sb->s_dev);
ext2_put_super(sb);
sync_volume(sb);
}
}
}
break;
default :
return ERROR_INVALID_PARAMETER;
}
return NO_ERROR;
}
_FS_RET _FS_ENTRY FS_WRITE(
struct sffsi _FS_PTR psffsi,
struct sffsd _FS_PTR psffsd,
char _FS_PTR pData,
unsigned short _FS_PTR pLen,
unsigned short IOflag
)
{
int rc, err;
pfile p_file;
struct super_block * sb;
long BytesWritten;
#ifdef FS_TRACE
kernel_printf("FS_WRITE( len = %u )", *pLen);
#endif
if (!Read_Write) {
kernel_printf("ERROR ! FS_WRITE() called and write access not enabled");
return ERROR_WRITE_PROTECT;
}
//
// Verify we have read access to the user buffer
//
if ((rc = FSH_PROBEBUF(PB_OPREAD, pData, *pLen)) != NO_ERROR) {
kernel_printf("FS_WRITE : FSH_PROBEBUF() returned %d", rc);
return rc;
} /* end if */
//
// Gets the superblock from psffsi
//
sb = getvolume(psffsi->sfi_hVPB);
//
// Gets the file structure from psffsd
//
p_file = ((_sffsd _FS_PTR)psffsd)->p_file;
if (!(p_file = ((_sffsd _FS_PTR)psffsd)->p_file)) {
kernel_printf("FS_WRITE() - p_file = NULL");
return ERROR_INVALID_PARAMETER;
}
//
// Tests if it is a regular file
//
if (!S_ISREG(p_file->f_inode->i_mode)) {
kernel_printf("Can't FS_WRITE( %lu ) - Not a regular file", p_file->f_inode->i_ino);
*pLen = 0;
return ERROR_ACCESS_DENIED;
}
//
// If the file position in psffsi is not consistent with the
// one in the file structure in psffsd, something went wrong => panic
//
if (psffsi->sfi_position != (unsigned long)p_file->f_pos) {
kernel_printf("FS_WRITE( %lu ) very weird : psffsi->sfi_position != p_file->f_pos : %ld %ld", p_file->f_inode->i_ino, psffsi->sfi_position, p_file->f_pos);
*pLen = 0;
return ERROR_WRITE_FAULT; // Maybe we should FSH_INTERR ?
}
err = VFS_write(p_file, pData, (loff_t)*pLen, &BytesWritten);
*pLen = (unsigned short)BytesWritten;
psffsi->sfi_tstamp = ST_SWRITE | ST_PWRITE;
psffsi->sfi_size = p_file->f_inode->i_size;
psffsi->sfi_position = p_file->f_pos;
return err;
}