/* createfile.c -- create / open file / directory / volume name Copyright (C) 1999-2000 Wojciech Galazka 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "lfnsrv.h" #if 0 static WORD process_open_file_volume( IN LPCSTR lpFileName, IN WORD nAction); #endif WORD GetShortPathName2( IN OUT LPSTR lpFileName); WORD CreateFile2( IN LPCSTR lpFileName); WORD process_create_file( IN OUT LPSTR lpFileName, IN WORD nAttributes, IN WORD nAction, OUT PWORD pResult) // if 0 then operation completed, don't call AH=6C, else call with respective code { WORD result ; WORD result2 ; PROLOG(process_create_file); IS_NULL(pResult, ERROR_INVALID_FUNCTION); IS_NULL(lpFileName, ERROR_FILE_NOT_FOUND); IS_MAX_PATH_SIZE(lpFileName); DBGVALUE(lpFileName,"%s"); DBGVALUE(nAttributes,"%d"); DBGVALUE(nAction,"%d"); // // See comments to process_open_file_volume // if (nAttributes & FILE_ATTR_VOLUME_LABEL) if (nAction == LONG_CREATE_FILE_OPEN) nAttributes &= ~FILE_ATTR_VOLUME_LABEL; else { #if 0 result = process_open_file_volume(lpFileName,nAction); #else result = ERROR_ACCESS_DENIED; #endif EPILOG(process_create_file, TRUE); return result; } *pResult = 0; // // there semms to be a bug in CreateFile that manifests as described // when 'fooname' file is requested 'FOONAME' file is created instead. // // or is a bug/feature with int 21h, ax=6C00h ? // // action not exists exits // LONG_CREATE_FILE_OPEN fails opens // LONG_CREATE_FILE_TRUNCATE fails opens/truncates // LONG_CREATE_FILE_CREATE creates fails // LONG_CREATE_FILE_CREATE_OPEN creates opens // LONG_CREATE_FILE_CREATE_TRUNCATE creates opens/truncates // // case not exists exists // OPEN_EXISTING fails opens // TRUNCATE_EXISTING fails opens/truncates // CREATE_NEW creates fails // OPEN_ALWAYS creates opens // CREATE_ALWAYS creates opens/truncate // // // Assumptions: OPEN_ALWAYS works correctly // GetShortPathName doesn't require opening a file // FileExists = ERROR_SUCCESS file exists // error code otherwise // Algorithm // if (action == LONG_CREATE_FILE_OPEN || // action == LONG_CREATE_FILE_TRUNCATE ) // GetShortPathName // return, normal processing of int 21h // if (action & LONG_CREATE_FILE_CREATE) // if file exists // if (action & LONG_CREATE_FILE_OPEN) // GetShortPathName // return, processing of int 21h with LONG_CREATE_FILE_OPEN // else // if (action & LONG_CREATE_FILE_TRUNCATE) // GetShortPathName // return, processing of int 21h with LONG_CREATE_FILE_TRUNCATE // else // fail // return // if file not exists // create with OPEN_ALWAYS // GetShortPathName // return, processing of int 21h with LONG_CREATE_FILE_CREATE_TRUNCATE // else // GetShortPathName // return, normal processing of int 21h // switch (nAction) { case LONG_CREATE_FILE_OPEN : result = GetShortPathName2(lpFileName); *pResult = nAction; break; case LONG_CREATE_FILE_TRUNCATE : result = FileExists(lpFileName); if (result == ERROR_SUCCESS) { result = GetShortPathName2(lpFileName); *pResult = nAction; } break; case LONG_CREATE_FILE_CREATE : case LONG_CREATE_FILE_CREATE_OPEN : case LONG_CREATE_FILE_CREATE_TRUNCATE : result2 = FileExists(lpFileName); switch (result2) { case ERROR_SUCCESS: if (nAction & LONG_CREATE_FILE_OPEN) { result = GetShortPathName2(lpFileName); *pResult = LONG_CREATE_FILE_OPEN; } else if (nAction & LONG_CREATE_FILE_TRUNCATE) { result = GetShortPathName2(lpFileName); *pResult = LONG_CREATE_FILE_TRUNCATE; } else result = ERROR_ACCESS_DENIED; break; case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: result = CreateFile2(lpFileName); if (result == ERROR_SUCCESS) { result = GetShortPathName2(lpFileName); *pResult = LONG_CREATE_FILE_CREATE_TRUNCATE; } break; default: result = result2; break; } break; default: result = ERROR_INVALID_FUNCTION; break; } DBGVALUE(lpFileName,"%s"); DBGVALUE(*pResult,"%d"); DBGVALUE(result,"%d"); EPILOG(process_create_file, TRUE); return result; } #if 0 /* It seems that any call to AX=616C with volume_name bit set fails except for case when DX=1. In that case a file from current directory is opened instead. If a file of that name is not present an 'file not found' is generated This is just after some checks, correct me if I'm wrong here .. */ static WORD process_open_file_volume( IN LPCSTR lpFileName, IN WORD nAction) { PROLOG(process_open_file_volume); switch (nAction) { case LONG_CREATE_FILE_OPEN : case LONG_CREATE_FILE_CREATE_OPEN : DBGMSG("Read volume label"); return ERROR_INVALID_FUNCTION; // hmmm ...not sure if DOS uses this call to create volume // if (!GetVolumeInformation(NULL, lpFileName, // MAX_PATHNAME_SIZE, NULL, NULL, NULL, NULL, 0)) { // EPILOG(process_open_file_volume, FALSE); // return (WORD)GetLastError(); // } case LONG_CREATE_FILE_TRUNCATE : case LONG_CREATE_FILE_CREATE_TRUNCATE : DBGMSG("Delete volume label"); if (!SetVolumeLabel(NULL, NULL)) { EPILOG(process_open_file_volume, FALSE); return (WORD)GetLastError(); } case LONG_CREATE_FILE_CREATE : DBGMSG("Create volume label"); if (!SetVolumeLabel(NULL, lpFileName)) { EPILOG(process_open_file_volume, FALSE); return (WORD)GetLastError(); } default: return ERROR_INVALID_FUNCTION; } EPILOG(process_open_file_volume, TRUE); return ERROR_SUCCESS; } #endif WORD GetShortPathName2( IN OUT LPSTR lpFileName) { WORD result = ERROR_SUCCESS; if(!GetShortPathName(lpFileName, lpFileName, MAX_PATHNAME_SIZE)) { result = (WORD)GetLastError(); switch (result) { case ERROR_SHARING_VIOLATION: DBGMSG("Sharing violation"); break; case ERROR_FILE_NOT_FOUND: DBGMSG("File not found"); break; case ERROR_PATH_NOT_FOUND: DBGMSG("Path not found"); break; case ERROR_NOT_SUPPORTED: DBGMSG("Network operation not supported"); break; default: DBGMSG("GetShortPathName2 failed"); DBGVALUE(result,"%d"); break; } if (result == ERROR_NOT_SUPPORTED) result = GetShortPathName_(lpFileName, lpFileName); } return result; } WORD CreateFile2( IN LPCSTR lpFileName) { HANDLE handle; WORD result; SetErrorMode(SEM_FAILCRITICALERRORS); if ((handle = CreateFile( lpFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL)) == INVALID_HANDLE_VALUE) { result = (WORD)GetLastError(); switch (result) { case ERROR_SHARING_VIOLATION: DBGMSG("Sharing violation"); break; case ERROR_FILE_NOT_FOUND: DBGMSG("File not found"); break; case ERROR_PATH_NOT_FOUND: DBGMSG("Path not found"); break; case ERROR_NOT_SUPPORTED: DBGMSG("Network operation not supported"); break; default: DBGMSG("CreateFile call failed"); DBGVALUE(result,"%d"); break; } if (result == ERROR_NOT_SUPPORTED) result = ERROR_FILE_NOT_FOUND; return result; } if (!CloseHandle(handle)) { result = (WORD)GetLastError(); DBGMSG("Close handle failed"); DBGVALUE(result,"%d"); } return ERROR_SUCCESS; }