Author: tkreuzer Date: Wed Jun 1 19:33:20 2011 New Revision: 52047
URL: http://svn.reactos.org/svn/reactos?rev=52047&view=rev Log: [CMD] replace FILE IO with Memory IO functions for batch files Patch by HansH (hans at atbas dot org)
See issue #5807 for more details.
Modified: trunk/reactos/base/shell/cmd/batch.c trunk/reactos/base/shell/cmd/batch.h trunk/reactos/base/shell/cmd/goto.c
Modified: trunk/reactos/base/shell/cmd/batch.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/batch.c?rev=... ============================================================================== --- trunk/reactos/base/shell/cmd/batch.c [iso-8859-1] (original) +++ trunk/reactos/base/shell/cmd/batch.c [iso-8859-1] Wed Jun 1 19:33:20 2011 @@ -156,6 +156,22 @@ return dp; }
+/* + * free the allocated memory of a batch file + */ +VOID ClearBatch() +{ + TRACE ("ClearBatch mem = %08x free = %d\n", bc->mem, bc->memfree); + + if (bc->mem && bc->memfree) + cmd_free(bc->mem); + + if (bc->raw_params) + cmd_free(bc->raw_params); + + if (bc->params) + cmd_free(bc->params); +}
/* * If a batch file is current, exits it, freeing the context block and @@ -169,19 +185,9 @@
VOID ExitBatch() { + ClearBatch(); + TRACE ("ExitBatch\n"); - - if (bc->hBatchFile) - { - CloseHandle (bc->hBatchFile); - bc->hBatchFile = INVALID_HANDLE_VALUE; - } - - if (bc->raw_params) - cmd_free(bc->raw_params); - - if (bc->params) - cmd_free(bc->params);
UndoRedirection(bc->RedirList, NULL); FreeRedirection(bc->RedirList); @@ -195,6 +201,33 @@ bc = bc->prev; }
+/* + * Load batch file into memory + * + */ +void BatchFile2Mem(HANDLE hBatchFile) +{ + TRACE ("BatchFile2Mem ()\n"); + + bc->memsize = GetFileSize(hBatchFile, NULL); + bc->mem = (char *)cmd_alloc(bc->memsize+1); /* 1 extra for '\0' */ + + /* if memory is available, read it in and close the file */ + if (bc->mem != NULL) + { + TRACE ("BatchFile2Mem memory %08x - %08x\n",bc->mem,bc->memsize); + SetFilePointer (hBatchFile, 0, NULL, FILE_BEGIN); + ReadFile(hBatchFile, (LPVOID)bc->mem, bc->memsize, &bc->memsize, NULL); + bc->mem[bc->memsize]='\0'; /* end this, so you can dump it as a string */ + bc->memfree=TRUE; /* this one needs to be freed */ + } + else + { + bc->memsize=0; /* this will prevent mem being accessed */ + bc->memfree=FALSE; + } + bc->mempos = 0; /* set position to the start */ +}
/* * Start batch file execution @@ -209,31 +242,37 @@ LPFOR_CONTEXT saved_fc; INT i; INT ret = 0; - - HANDLE hFile; + BOOL same_fn = FALSE; + + HANDLE hFile = 0; SetLastError(0); - hFile = CreateFile (fullname, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | - FILE_FLAG_SEQUENTIAL_SCAN, NULL); - - TRACE ("Batch: ('%s', '%s', '%s') hFile = %x\n", - debugstr_aw(fullname), debugstr_aw(firstword), debugstr_aw(param), hFile); - - if (hFile == INVALID_HANDLE_VALUE) - { - ConErrResPuts(STRING_BATCH_ERROR); - return 1; - } - + if (bc && bc->mem) + { + TCHAR fpname[MAX_PATH]; + GetFullPathName(fullname, sizeof(fpname) / sizeof(TCHAR), fpname, NULL); + if (_tcsicmp(bc->BatchFilePath,fpname)==0) + same_fn=TRUE; + } + TRACE ("Batch: ('%s', '%s', '%s') same_fn = %d\n", + debugstr_aw(fullname), debugstr_aw(firstword), debugstr_aw(param), same_fn); + + if (!same_fn) + { + hFile = CreateFile (fullname, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + ConErrResPuts(STRING_BATCH_ERROR); + return 1; + } + } + if (bc != NULL && Cmd == bc->current) { /* Then we are transferring to another batch */ - CloseHandle (bc->hBatchFile); - bc->hBatchFile = INVALID_HANDLE_VALUE; - if (bc->params) - cmd_free (bc->params); - if (bc->raw_params) - cmd_free (bc->raw_params); + ClearBatch(); AddBatchRedirection(&Cmd->Redirections); } else @@ -261,15 +300,27 @@ /* Create a new context. This function will not * return until this context has been exited */ new.prev = bc; + /* copy some fields in the new structure if it is the same file */ + if (same_fn) { + new.mem = bc->mem; + new.memsize = bc->memsize; + new.mempos = 0; + new.memfree = FALSE; /* don't free this, being used before this */ + } bc = &new; bc->RedirList = NULL; bc->setlocal = setlocal; }
GetFullPathName(fullname, sizeof(bc->BatchFilePath) / sizeof(TCHAR), bc->BatchFilePath, NULL); - - bc->hBatchFile = hFile; - SetFilePointer (bc->hBatchFile, 0, NULL, FILE_BEGIN); + /* if a new batch file, load it into memory and close the file */ + if (!same_fn) + { + BatchFile2Mem(hFile); + CloseHandle(hFile); + } + + bc->mempos = 0; /* goto begin of batch file */ bc->bEcho = bEcho; /* Preserve echo across batch calls */ for (i = 0; i < 10; i++) bc->shiftlevel[i] = i; @@ -340,6 +391,49 @@ }
/* + * Read a single line from the batch file from the current batch/memory position. + * Almost a copy of FileGetString with same UNICODE handling + */ +BOOL BatchGetString (LPTSTR lpBuffer, INT nBufferLength) +{ + LPSTR lpString; + INT len = 0; +#ifdef _UNICODE + lpString = cmd_alloc(nBufferLength); +#else + lpString = lpBuffer; +#endif + /* read all chars from memory until a '\n' is encountered */ + if (bc->mem) + { + for (; (bc->mempos < bc->memsize && len < (nBufferLength-1)); len++) + { + lpString[len] = bc->mem[bc->mempos++]; + if (lpString[len] == '\n' ) + { + len++; + break; + } + } + } + + if (!len) + { +#ifdef _UNICODE + cmd_free(lpString); +#endif + return FALSE; + } + + lpString[len++] = '\0'; +#ifdef _UNICODE + MultiByteToWideChar(OutputCodePage, 0, lpString, -1, lpBuffer, len); + cmd_free(lpString); +#endif + return TRUE; +} + +/* * Read and return the next executable line form the current batch file * * If no batch file is current or no further executable lines are found @@ -347,7 +441,6 @@ * * Set eflag to 0 if line is not to be echoed else 1 */ - LPTSTR ReadBatchLine () { TRACE ("ReadBatchLine ()\n"); @@ -360,7 +453,7 @@ return NULL; }
- if (!FileGetString (bc->hBatchFile, textline, sizeof (textline) / sizeof (textline[0]) - 1)) + if (!BatchGetString (textline, sizeof (textline) / sizeof (textline[0]) - 1)) { TRACE ("ReadBatchLine(): Reached EOF!\n"); /* End of file.... */
Modified: trunk/reactos/base/shell/cmd/batch.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/batch.h?rev=... ============================================================================== --- trunk/reactos/base/shell/cmd/batch.h [iso-8859-1] (original) +++ trunk/reactos/base/shell/cmd/batch.h [iso-8859-1] Wed Jun 1 19:33:20 2011 @@ -9,7 +9,10 @@ typedef struct tagBATCHCONTEXT { struct tagBATCHCONTEXT *prev; - HANDLE hBatchFile; + char *mem; /* batchfile content in memory */ + DWORD memsize; /* size of batchfile */ + DWORD mempos; /* current position to read from */ + BOOL memfree; /* true if it need to be freed when exitbatch is called */ TCHAR BatchFilePath[MAX_PATH]; LPTSTR params; LPTSTR raw_params; /* Holds the raw params given by the input */ @@ -47,5 +50,6 @@ LPTSTR BatchParams (LPTSTR, LPTSTR); VOID ExitBatch (VOID); INT Batch (LPTSTR, LPTSTR, LPTSTR, PARSED_COMMAND *); +BOOL BatchGetString (LPTSTR lpBuffer, INT nBufferLength); LPTSTR ReadBatchLine(VOID); -VOID AddBatchRedirection(REDIRECTION **); +VOID AddBatchRedirection(REDIRECTION **);
Modified: trunk/reactos/base/shell/cmd/goto.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/goto.c?rev=5... ============================================================================== --- trunk/reactos/base/shell/cmd/goto.c [iso-8859-1] (original) +++ trunk/reactos/base/shell/cmd/goto.c [iso-8859-1] Wed Jun 1 19:33:20 2011 @@ -74,14 +74,14 @@ /* jump to end of the file */ if ( _tcsicmp( param, _T(":eof"))==0) { - SetFilePointer (bc->hBatchFile, 0, &lNewPosHigh, FILE_END); + bc->mempos=bc->memsize; /* position at the end of the batchfile */ return 0; }
/* jump to begin of the file */ - SetFilePointer (bc->hBatchFile, 0, &lNewPosHigh, FILE_BEGIN); + bc->mempos=0;
- while (FileGetString (bc->hBatchFile, textline, sizeof(textline) / sizeof(textline[0]))) + while (BatchGetString (textline, sizeof(textline) / sizeof(textline[0]))) { int pos; int size;