#include #include #include #include #include #include "symutil.h" #include "symsrv.h" typedef struct _FILE_INFO { DWORD TimeDateStamp; DWORD CheckSum; DWORD Signature; TCHAR szName[_MAX_PATH+ _MAX_FNAME + _MAX_EXT + 2]; } FILE_INFO, *PFILE_INFO; // Prototypes PCOM_ARGS GetCommandLineArgs( int argc, char **argv ); BOOL InitializeTrans( PTRANSACTION *pTrans, PCOM_ARGS pArgs, PHANDLE hFile ); BOOL DeleteTrans( PTRANSACTION pTrans, PCOM_ARGS pArgs ); VOID Usage ( VOID ); StoreDirectory( LPTSTR szDir, LPTSTR szFName, LPTSTR szDestDir, PFILE_COUNTS pFileCounts, LPTSTR szPath ); DWORD StoreAllDirectories( LPTSTR szDir, LPTSTR szFName, LPTSTR szDestDir, PFILE_COUNTS pFileCounts, LPTSTR szPath ); BOOL CorrectPath( LPTSTR szFileName, LPTSTR szPathName, LPTSTR szCorrectPath ); BOOL AddTransToFile( PTRANSACTION pTrans, LPTSTR szFileName, PHANDLE hFile ); BOOL UpdateServerFile( PTRANSACTION pTrans, LPTSTR szServerFileName ); BOOL GetNextId( LPTSTR szMasterFileName, LPTSTR *szId, PHANDLE hFile ); BOOL DeleteEntry( LPTSTR szDir, LPTSTR szId ); BOOL CopyTheFile( LPTSTR szDir, LPTSTR szFilePathName ); BOOL DeleteTheFile( LPTSTR szDir, LPTSTR szFilePathName ); BOOL StoreSystemTime( LPTSTR *szTime, LPSYSTEMTIME lpSystemTime ); BOOL StoreSystemDate( LPTSTR *szDate, LPSYSTEMTIME lpSystemTime ); ULONG GetMaxLineOfHistoryFile( VOID ); ULONG GetMaxLineOfTransactionFile( VOID ); ULONG GetMaxLineOfRefsPtrFile( VOID ); BOOL GetSrcDirandFileName ( LPTSTR szStr, LPTSTR szSrcDir, LPTSTR szFileName ); PCOM_ARGS pArgs; HANDLE hTransFile; DWORD StoreFlags; PTRANSACTION pTrans; LONG lMaxTrans; LONG NumSkippedFiles=0; int _cdecl main( int argc, char **argv) { DWORD NumErrors = 0; FILE_COUNTS FileCounts; BOOL rc; HANDLE hFile; hFile=0; // This also initializes the name of the Log File pArgs = GetCommandLineArgs(argc, argv); // Initialize the transaction record // Opens the master file (hFile) and leaves it open // Get exclusive access to this file InitializeTrans(&pTrans, pArgs, &hFile); if (pArgs->StoreFlags != ADD_DONT_STORE) { AddTransToFile(pTrans, pArgs->szMasterFileName, &hFile); } CloseHandle(hFile); if (pArgs->TransState==TRANSACTION_DEL) { rc = DeleteTrans(pTrans,pArgs); UpdateServerFile(pTrans, pArgs->szServerFileName); return(rc); } if ( pArgs->StoreFlags == ADD_STORE || pArgs->StoreFlags == ADD_STORE_FROM_FILE ) { // Update server file UpdateServerFile(pTrans, pArgs->szServerFileName); } // Make sure the directory path exists for the transaction // file if we are doing ADD_DONT_STORE if ( pArgs->StoreFlags == ADD_DONT_STORE ) { if ( !MakeSureDirectoryPathExists(pTrans->szTransFileName) ) { printf("Cannot create the directory %s - GetLastError() = %d\n", pTrans->szTransFileName, GetLastError() ); exit(1); } // Open the file and move the file pointer to the end if we are // in appending mode. if (pArgs->AppendStoreFile) { hTransFile = CreateFile(pTrans->szTransFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (hTransFile == INVALID_HANDLE_VALUE ) { printf("Cannot create file %s - GetLastError = %d\n", pTrans->szTransFileName, GetLastError() ); exit(1); } if ( SetFilePointer( hTransFile, 0, NULL, FILE_END ) == INVALID_SET_FILE_POINTER ) { printf("Cannot move to end of file %s - GetLastError = %d\n", pTrans->szTransFileName, GetLastError() ); exit(1); } } else { hTransFile = CreateFile(pTrans->szTransFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (hTransFile == INVALID_HANDLE_VALUE ) { printf("Cannot create file %s - GetLastError = %d\n", pTrans->szTransFileName, GetLastError() ); exit(1); } } } else { hTransFile = CreateFile(pTrans->szTransFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); if (hTransFile == INVALID_HANDLE_VALUE ) { printf("Cannot create a new file %s - GetLastError = %d\n", pTrans->szTransFileName, GetLastError() ); exit(1); } } StoreFlags=pArgs->StoreFlags; if (hTransFile == INVALID_HANDLE_VALUE ) { printf("Cannot create a new file %s - GetLastError = %d\n", pTrans->szTransFileName, GetLastError() ); exit(1); } memset( &FileCounts, 0, sizeof(FILE_COUNTS) ); if ( pArgs->StoreFlags==ADD_STORE_FROM_FILE ) { // This will only store pointers NumErrors += StoreFromFile( pArgs->pStoreFromFile, pArgs->szSymbolsDir, &FileCounts ); fclose(pArgs->pStoreFromFile); } else if ( !pArgs->Recurse ) { NumErrors += StoreDirectory( pArgs->szSrcDir, pArgs->szFileName, pArgs->szSymbolsDir, &FileCounts, pArgs->szSrcPath ); } else { NumErrors += StoreAllDirectories( pArgs->szSrcDir, pArgs->szFileName, pArgs->szSymbolsDir, &FileCounts, pArgs->szSrcPath ); } if (pArgs->szSrcPath) { printf("SYMSTORE: Number of pointers stored = %d\n",FileCounts.NumPassedFiles); } else { printf("SYMSTORE: Number of files stored = %d\n",FileCounts.NumPassedFiles); } printf("SYMSTORE: Number of errors = %d\n",NumErrors); printf("SYMSTORE: Number of ignored files = %d\n", NumSkippedFiles); SetEndOfFile(hTransFile); CloseHandle(hTransFile); return (0); } DWORD StoreAllDirectories( LPTSTR szDir, LPTSTR szFName, LPTSTR szDestDir, PFILE_COUNTS pFileCounts, LPTSTR szPath ) /* ++ IN szDir Directory of files to Store -- */ { HANDLE hFindFile; TCHAR szCurPath[_MAX_PATH+2]; TCHAR szFilePtrPath[_MAX_PATH+2]; // This is the path that will get stored as a // pointer to the file. LPTSTR szPtrPath = NULL; BOOL Found = FALSE; DWORD NumBadFiles=0; LPWIN32_FIND_DATA lpFindFileData; NumBadFiles += StoreDirectory(szDir, szFName, szDestDir, pFileCounts, szPath ); lpFindFileData = (LPWIN32_FIND_DATA) malloc (sizeof(WIN32_FIND_DATA) ); if (!lpFindFileData) { printf("Symchk: Not enough memory.\n"); exit(1); } // Look for all the subdirectories _tcscpy(szCurPath, szDir); _tcscat(szCurPath, _T("*.*") ); Found = TRUE; hFindFile = FindFirstFile((LPCTSTR)szCurPath, lpFindFileData); if ( hFindFile == INVALID_HANDLE_VALUE) { Found = FALSE; } while ( Found ) { if ( lpFindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if ( !_tcscmp(lpFindFileData->cFileName, _T(".")) || !_tcscmp(lpFindFileData->cFileName, _T("..")) ) { } else { // Get the current path that we are searching in _tcscpy(szCurPath, szDir); _tcscat(szCurPath, lpFindFileData->cFileName); EnsureTrailingBackslash(szCurPath); // Get the current path to use as the pointer to the // file, if we are storing file pointers instead of // files in this tree. if ( szPath ) { _tcscpy(szFilePtrPath, szPath); _tcscat(szFilePtrPath, lpFindFileData->cFileName); EnsureTrailingBackslash(szFilePtrPath); szPtrPath = szFilePtrPath; } NumBadFiles += StoreAllDirectories( szCurPath, szFName, szDestDir, pFileCounts, szPtrPath ); } } Found = FindNextFile(hFindFile, lpFindFileData); } free(lpFindFileData); FindClose(hFindFile); return(NumBadFiles); } StoreDirectory( LPTSTR szDir, LPTSTR szFName, LPTSTR szDestDir, PFILE_COUNTS pFileCounts, LPTSTR szPath ) { HANDLE hFindFile; TCHAR szFileName[_MAX_PATH+2]; TCHAR szCurPath[_MAX_PATH+2]; TCHAR szCurFileName[_MAX_PATH+2]; TCHAR szCurPtrFileName[_MAX_PATH+2]; // Ptr to the file to put in "file.ptr" // instead of storing the file. BOOL Found, length, rc; DWORD NumBadFiles=0; BOOL skipped = 0; USHORT rc_flag; LPWIN32_FIND_DATA lpFindFileData; // Create the file name _tcscpy(szFileName, szDir); _tcscat(szFileName, szFName); // Get the current path that we are searching in _tcscpy(szCurPath, szDir); lpFindFileData = (LPWIN32_FIND_DATA) malloc (sizeof(WIN32_FIND_DATA) ); if (!lpFindFileData) { printf("Symchk: Not enough memory.\n"); exit(1); } Found = TRUE; hFindFile = FindFirstFile((LPCTSTR)szFileName, lpFindFileData); if ( hFindFile == INVALID_HANDLE_VALUE ) { Found = FALSE; } while ( Found ) { // Found a file, not a directory if ( !(lpFindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { _tcscpy(szCurFileName, szCurPath); _tcscat(szCurFileName, lpFindFileData->cFileName ); if ( szPath ) { _tcscpy(szCurPtrFileName, szPath); _tcscat(szCurPtrFileName, lpFindFileData->cFileName ); } // Figure out if its a dbg or pdb length = _tcslen(szCurFileName); rc = FALSE; skipped = FALSE; if (length > 4 ) { if ( _tcsicmp(_T(".dbg"), szCurFileName + length - 4) == 0 ) { if ( szPath ) { rc = StoreDbg( szDestDir, szCurFileName, szCurPtrFileName ); } else { rc = StoreDbg( szDestDir, szCurFileName, NULL ); } } else if ( _tcsicmp(_T(".pdb"), szCurFileName + length - 4) == 0 ) { if ( szPath ) { rc = StorePdb( szDestDir, szCurFileName, szCurPtrFileName ); } else { rc = StorePdb( szDestDir, szCurFileName, NULL ); } } else { if ( szPath ) { rc = StoreNtFile( szDestDir, szCurFileName, szCurPtrFileName, &rc_flag ); } else { rc = StoreNtFile( szDestDir, szCurFileName, NULL, &rc_flag ); } if (rc_flag == FILE_SKIPPED) { NumSkippedFiles++; skipped = TRUE; if(pArgs->VerboseOutput) { printf("SYMSTORE: Skipping %s - not a dbg, pdb, or executable\n", szCurFileName); } } } } if (!skipped && !rc) { pFileCounts->NumFailedFiles++; NumBadFiles++; printf("SYMSTORE: ERROR: Could not store %s\n", szCurFileName); } else if (!skipped) { pFileCounts->NumPassedFiles++; if (pFileCounts->NumPassedFiles % 50 == 0) { printf("."); } } } Found = FindNextFile(hFindFile, lpFindFileData); } free(lpFindFileData); FindClose(hFindFile); return(NumBadFiles); } VOID Usage ( VOID ) { puts("\n" "Usage:\n" "symstore add [/r] [/p] [/l] /f File /s Store /t Product [/v Version]\n" " [/c Comment]\n\n" "symstore add [/r] [/p] [/l] /g Share /f File /x IndexFile [/a]\n\n" "symstore add /y IndexFile /g Share /s Store [/p] /t Product [/v Version]\n" " [/c Comment]\n\n" "symstore del /i ID /s Store\n\n" " /f File Network path of files or directories to add.\n\n" " /g Share This is the server and share where the symbol files were\n" " originally stored. When used with /f, Share should be\n" " identical to the beginning of the File specifier. When\n" " used with the /y, Share should be the location of the\n" " original symbol files, not the index file. This allows\n" " you to later change this portion of the file path in case\n" " you move the symbol files to a different server and share.\n\n" " /i ID Transaction ID string.\n\n" " /l Allows the file to be in a local directory rather than a\n" " network path. (This option is only used with the /p option.)\n\n" " /p Causes SymStore to store a pointer to the file, rather than\n" " the file itself.\n\n" " /r Add files or directories recursively.\n\n" " /s Store Root directory for the symbol store.\n\n" " /t Product Name of the product.\n\n" " /v Version Version of the product.\n\n" " /c Comment Comment for the transaction.\n\n" " /x IndexFile Causes SymStore not to store the actual symbol files in the\n" " symbol store. Instead, information is stored which will\n" " allow the files to be added later.\n\n" " /y IndexFile This reads the data from a file created with /x.\n\n" " /a Causes SymStore to append new indexing information\n" " to an existing index file. (This option is only used with\n" " /x option.)\n\n" " /o Give verbose output.\n\n" "\n" ); exit(1); } PCOM_ARGS GetCommandLineArgs( int argc, char **argv ) { PCOM_ARGS pArgs; int i,cur,length; TCHAR c; BOOL NeedSecond = FALSE; BOOL StorePtrs = FALSE; BOOL AllowLocalNames = FALSE; BOOL rc; LPTSTR szFileArg = NULL; TCHAR szNameExt[_MAX_FNAME + _MAX_EXT + 1]; HANDLE fHandle; WIN32_FIND_DATA FindFileData; if (argc <= 2) Usage(); pArgs = (PCOM_ARGS)malloc( sizeof(COM_ARGS) ); if (!pArgs) MallocFailed(); memset( pArgs, 0, sizeof(COM_ARGS) ); if (!_tcsicmp(argv[1], _T("add")) ){ pArgs->TransState = TRANSACTION_ADD; pArgs->StoreFlags=ADD_STORE; } else if (!_tcsicmp(argv[1], _T("del")) ) { pArgs->TransState = TRANSACTION_DEL; pArgs->StoreFlags=DEL; } else { printf("ERROR: First argument needs to be ""add"" or ""del""\n"); exit(1); } for (i=2; iAppendStoreFile = TRUE; break; case 'c': NeedSecond = TRUE; break; case 'f': NeedSecond = TRUE; break; case 'g': NeedSecond = TRUE; break; case 'i': NeedSecond = TRUE; break; case 'l': AllowLocalNames=TRUE; break; case 'r': if (pArgs->TransState==TRANSACTION_DEL) { printf("ERROR: /r is an incorrect parameter with del\n\n"); exit(1); } pArgs->Recurse = TRUE; break; case 'p': StorePtrs = TRUE; if (pArgs->TransState==TRANSACTION_DEL) { printf("ERROR: /p is an incorrect parameter with del\n\n"); exit(1); } break; case 's': NeedSecond = TRUE; break; case 't': NeedSecond = TRUE; break; case 'v': NeedSecond = TRUE; break; case 'x': NeedSecond = TRUE; break; case 'y': NeedSecond = TRUE; break; case 'o': pArgs->VerboseOutput = TRUE; break; default: Usage(); } } } else { printf("ERROR: Expecting a / option before %s\n", argv[i] ); exit(1); } } else { NeedSecond = FALSE; switch (c) { case 'c': if (pArgs->TransState==TRANSACTION_DEL) { printf("ERROR: /c is an incorrect parameter with del\n\n"); exit(1); } if ( _tcslen(argv[i]) > MAX_COMMENT ) { printf("ERROR: Comment must be %d characters or less\n", MAX_COMMENT); exit(1); } pArgs->szComment = (LPTSTR)malloc( (_tcslen(argv[i]) + 1) * sizeof(TCHAR) ); if (!pArgs->szComment) MallocFailed(); _tcscpy(pArgs->szComment, argv[i]); break; case 'i': if (pArgs->TransState==TRANSACTION_ADD) { printf("ERROR: /i is an incorrect parameter with add\n\n"); exit(1); } if ( _tcslen(argv[i]) != MAX_ID ) { printf("ERROR: /i ID is not a valid ID length\n"); exit(1); } pArgs->szId = (LPTSTR)malloc( (_tcslen(argv[i]) + 1) * sizeof(TCHAR) ); if (!pArgs->szId) MallocFailed(); _tcscpy(pArgs->szId, argv[i]); break; case 'f': if (pArgs->TransState==TRANSACTION_DEL) { printf("ERROR: /f is an incorrect parameter with del\n\n"); exit(1); } szFileArg = argv[i]; break; case 'g': if (pArgs->TransState==TRANSACTION_DEL) { printf("ERROR: /g is an incorrect parameter with del\n\n"); exit(1); } pArgs->szShareName=(LPTSTR) malloc( (_tcslen(argv[i]) + 2) * sizeof(TCHAR) ); if (!pArgs->szShareName) MallocFailed(); _tcscpy(pArgs->szShareName, argv[i]); pArgs->ShareNameLength=_tcslen(pArgs->szShareName); break; case 's': if ( _tcslen(argv[i]) > (_MAX_PATH-2) ) { printf("ERROR: Path following /s is too long\n"); exit(1); } // Be sure to allocate enough to add a trailing backslash pArgs->szRootDir = (LPTSTR) malloc ( (_tcslen(argv[i]) + 2) * sizeof(TCHAR) ); if (!pArgs->szRootDir) MallocFailed(); _tcscpy(pArgs->szRootDir,argv[i]); EnsureTrailingBackslash(pArgs->szRootDir); break; case 't': if (pArgs->TransState==TRANSACTION_DEL) { printf("ERROR: /t is an incorrect parameter with del\n\n"); exit(1); } if ( _tcslen(argv[i]) > MAX_PRODUCT ) { printf("ERROR: Product following /t must be <= %d characters\n", MAX_PRODUCT); exit(1); } pArgs->szProduct = (LPTSTR) malloc ( (_tcslen(argv[i]) + 1) * sizeof(TCHAR) ); if (!pArgs->szProduct) MallocFailed(); _tcscpy(pArgs->szProduct,argv[i]); break; case 'v': if (pArgs->TransState==TRANSACTION_DEL) { printf("ERROR: /v is an incorrect parameter with del\n\n"); exit(1); } if ( _tcslen(argv[i]) > MAX_VERSION ) { printf("ERROR: Version following /v must be <= %d characters\n", MAX_VERSION); exit(1); } pArgs->szVersion = (LPTSTR) malloc ( (_tcslen(argv[i]) + 1) * sizeof(TCHAR) ); if (!pArgs->szVersion) MallocFailed(); _tcscpy(pArgs->szVersion,argv[i]); break; case 'x': pArgs->szTransFileName = (LPTSTR) malloc ( (_tcslen(argv[i]) + 1) * sizeof(TCHAR) ); if (!pArgs->szTransFileName) MallocFailed(); _tcscpy(pArgs->szTransFileName,argv[i]); pArgs->StoreFlags = ADD_DONT_STORE; // Since we are throwing away the first part of this path, we can allow // local paths for the files to be stored on the symbols server AllowLocalNames=TRUE; break; case 'y': if (pArgs->TransState==TRANSACTION_DEL) { printf("ERROR: /f is an incorrect parameter with del\n\n"); exit(1); } pArgs->StoreFlags = ADD_STORE_FROM_FILE; szFileArg = argv[i]; break; default: Usage(); } } } // Check that everything has been entered if (NeedSecond) { printf("ERROR: /%c must be followed by an argument\n\n", c); exit(1); } if ( pArgs->StoreFlags == ADD_STORE_FROM_FILE ) { if (pArgs->szShareName == NULL ) { printf("/g must be used when /y is used. \n"); exit(1); } EnsureTrailingBackslash(pArgs->szShareName); hTransFile = CreateFile(szFileArg, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hTransFile == INVALID_HANDLE_VALUE ) { printf("Cannot open file %s - GetLastError = %d\n", szFileArg, GetLastError() ); exit(1); } } if ( pArgs->StoreFlags == ADD_DONT_STORE ) { if (pArgs->szShareName == NULL ) { printf("/g must be used when /x is used. \n"); exit(1); } // Verify that szShare is a prefix of szFileArg if (szFileArg == NULL ) { printf("/f is a required parameter\n"); exit(1); } if ( _tcslen(szFileArg) < pArgs->ShareNameLength ) { printf("/g %s must be a prefix of /f %s\n",pArgs->szShareName, szFileArg); exit(1); } if ( _tcsncicmp(pArgs->szShareName, szFileArg, pArgs->ShareNameLength) != 0 ) { printf("/g %s must be a prefix of /f %s\n", pArgs->szShareName, szFileArg); exit(1); } // Now, make sure that szFileArg has a trailing backslash EnsureTrailingBackslash(pArgs->szShareName); pArgs->ShareNameLength=_tcslen(pArgs->szShareName); // Set the symbol directory under the server to "" // so that tcscpy's will work correctly in the rest of the pArgs->szSymbolsDir = (LPTSTR) malloc ( sizeof(TCHAR) * 2 ); if ( !pArgs->szSymbolsDir) MallocFailed(); _tcscpy( pArgs->szSymbolsDir, _T("") ); } // Get the various symbol server related file names if ( pArgs->StoreFlags == ADD_STORE || pArgs->StoreFlags == ADD_STORE_FROM_FILE || pArgs->StoreFlags == DEL ) { if ( pArgs->szRootDir == NULL ) { // Verify that the root of the symbols server was entered printf("ERROR: /s server is a required parameter\n\n"); exit(1); } // Store the name of the symbols dir pArgs->szSymbolsDir = (LPTSTR) malloc ( sizeof(TCHAR) * (_tcslen(pArgs->szRootDir) + 1) ); if (!pArgs->szSymbolsDir) MallocFailed(); _stprintf(pArgs->szSymbolsDir, "%s", pArgs->szRootDir); // Verify that the symbols dir exists if ( !MakeSureDirectoryPathExists(pArgs->szSymbolsDir) ) { printf("Cannot create the directory %s - GetLastError() = %d\n", pArgs->szSymbolsDir, GetLastError() ); exit(1); } // Store the name of the admin dir pArgs->szAdminDir = (LPTSTR) malloc ( sizeof(TCHAR) * (_tcslen(pArgs->szRootDir) + _tcslen(_T("000admin\\")) + 1) ); if (!pArgs->szAdminDir) MallocFailed(); _stprintf(pArgs->szAdminDir, "%s000admin\\", pArgs->szRootDir); // Verify that the Admin dir exists if ( !MakeSureDirectoryPathExists(pArgs->szAdminDir) ) { printf("Cannot create the directory %s - GetLastError() = %d\n", pArgs->szAdminDir, GetLastError() ); exit(1); } // Store the name of the master file pArgs->szMasterFileName = (LPTSTR) malloc ( sizeof(TCHAR) * (_tcslen(pArgs->szAdminDir) + _tcslen(_T("history.txt")) + 1) ); if (!pArgs->szMasterFileName ) MallocFailed(); _stprintf(pArgs->szMasterFileName, "%shistory.txt", pArgs->szAdminDir); // // Store the name of the "server" file - this contains all // the transactions that currently make up the server // pArgs->szServerFileName = (LPTSTR) malloc ( sizeof(TCHAR) * (_tcslen(pArgs->szAdminDir) + _tcslen(_T("server.txt")) + 1) ); if (!pArgs->szServerFileName ) MallocFailed(); _stprintf(pArgs->szServerFileName, "%sserver.txt", pArgs->szAdminDir); } if ( pArgs->StoreFlags==DEL && !pArgs->szId ) { printf("ERROR: /i id is a required parameter\n\n"); exit(1); } // Done if this is a delete transaction if ( pArgs->StoreFlags == DEL ) { return(pArgs); } if ( pArgs->StoreFlags == ADD_STORE || pArgs->StoreFlags == ADD_STORE_FROM_FILE ) { if ( !pArgs->szProduct ) { printf("ERROR: /t product is a required parameter\n\n"); exit(1); } // Since Version and Comment are optional parameters, initialize them to // the empty string if they haven't been assigned if ( !pArgs->szVersion ) { pArgs->szVersion = (LPTSTR)malloc(sizeof(TCHAR) ); if (!pArgs->szVersion) MallocFailed(); _tcscpy(pArgs->szVersion,_T("") ); } if ( !pArgs->szComment ) { pArgs->szComment = (LPTSTR)malloc(sizeof(TCHAR) ); if (!pArgs->szComment) MallocFailed(); _tcscpy(pArgs->szComment,_T("") ); } if ( !pArgs->szUnused ) { pArgs->szUnused = (LPTSTR)malloc(sizeof(TCHAR) ); if (!pArgs->szUnused) MallocFailed(); _tcscpy(pArgs->szUnused,_T("") ); } } if ( pArgs->StoreFlags == ADD_STORE || pArgs->StoreFlags == ADD_DONT_STORE ) { pArgs->szSrcDir = (LPTSTR) malloc ( (_MAX_PATH+_MAX_FNAME+_MAX_EXT+2) * sizeof(TCHAR) ); if (!pArgs->szSrcDir ) MallocFailed(); pArgs->szFileName = (LPTSTR) malloc ( (_MAX_FNAME + _MAX_EXT + 1) * sizeof(TCHAR) ); if (!pArgs->szFileName ) MallocFailed(); // Decide what part of szFileArg is a file name and what part of it // is a directory rc = GetSrcDirandFileName( szFileArg, pArgs->szSrcDir, pArgs->szFileName); if (!rc) { Usage(); } // Get the pointer path if we are storing pointers // Later, if pArgs->szSrcPath == NULL is used as a way of telling if // the user wanted pointers or files. if (StorePtrs ) { if ( !AllowLocalNames ) { // Make sure that they are entering a network path. // The reason is that this is the path that will be used to // add and delete entries from the symbols server. And, when // pointers are used, this is the path the debugger will use to // get the file. if ( _tcslen(szFileArg) >= 2 ) { if ( szFileArg[0] != '\\' || szFileArg[1] != '\\' ) { printf("ERROR: /f must be followed by a network path\n"); exit(1); } } else { printf("ERROR: /f must be followed by a network path\n"); exit(1); } } pArgs->szSrcPath = (LPTSTR) malloc ( (_tcslen(pArgs->szSrcDir)+1) * sizeof(TCHAR) ); if (pArgs->szSrcPath == NULL ) MallocFailed(); _tcscpy(pArgs->szSrcPath, pArgs->szSrcDir); } } if ( pArgs->StoreFlags == ADD_STORE_FROM_FILE ) { pArgs->pStoreFromFile = _tfopen(szFileArg, _T("r") ); if (!pArgs->pStoreFromFile ) { printf("Cannot open file %s - GetLastError = %d\n", szFileArg, GetLastError() ); exit(1); } } return (pArgs); } BOOL CorrectPath( LPTSTR szFileName, LPTSTR szPathName, LPTSTR szCorrectPath ) { // To return TRUE, szPathName should equal szCorrectPath + \ + szFileName // The only hitch is that there could be extraneous \'s TCHAR CorrectPathx[_MAX_PATH + _MAX_FNAME + _MAX_EXT + 2]; TCHAR PathNamex[_MAX_PATH + _MAX_FNAME + _MAX_EXT + 2]; LONG length, index, i; // Get rid of any extra \'s length = _tcslen(szPathName); PathNamex[0] = szPathName[0]; index = 1; for (i=1; i<=length; i++) { if ( (szPathName[i-1] != '\\') || (szPathName[i] != '\\') ) { PathNamex[index] = szPathName[i]; index++; } } length = _tcslen(szCorrectPath); CorrectPathx[0] = szCorrectPath[0]; index = 1; for (i=1; i<=length; i++) { if ( (szCorrectPath[i-1] != '\\') || (szCorrectPath[i] != '\\') ) { CorrectPathx[index] = szCorrectPath[i]; index++; } } // Make sure that the correct path doesn't end in a '\' length = _tcslen(CorrectPathx); if ( CorrectPathx[length-1] == '\\' ) CorrectPathx[length-1] = '\0'; _tcscat(CorrectPathx,"\\"); _tcscat(CorrectPathx,szFileName); if ( _tcsicmp(CorrectPathx, szPathName) == 0) return TRUE; else return FALSE; } BOOL InitializeTrans( PTRANSACTION *pTrans, PCOM_ARGS pArgs, PHANDLE hFile ) { BOOL rc; SYSTEMTIME SystemTime; lMaxTrans = MAX_ID + MAX_VERSION + MAX_PRODUCT + MAX_COMMENT + TRANS_NUM_COMMAS + TRANS_EOL + TRANS_ADD_DEL + TRANS_FILE_PTR + MAX_DATE + MAX_TIME + MAX_UNUSED; *pTrans = NULL; *pTrans = (PTRANSACTION) malloc( sizeof(TRANSACTION) ); if (!*pTrans) { printf("SYMSTORE: Not enough memory to allocate a TRANSACTION\n"); exit(1); } memset(*pTrans,0,sizeof(TRANSACTION) ); // // If this is a delete transaction, then use the ID that was entered from // the command line to set the ID of the transaction to be deleted. // if (pArgs->TransState==TRANSACTION_DEL ) { (*pTrans)->TransState = pArgs->TransState; (*pTrans)->szId = pArgs->szId; rc = GetNextId(pArgs->szMasterFileName,&((*pTrans)->szDelId),hFile); } else if ( pArgs->StoreFlags == ADD_DONT_STORE ) { rc = TRUE; } else{ rc = GetNextId(pArgs->szMasterFileName,&((*pTrans)->szId),hFile ); } if (!rc) { printf("SYMSTORE: Cannot create a new transaction ID number\n"); exit(1); } // If the things that are needed for both types of adding // That is, creating a transaction file only, and adding the // files to the symbols server if (pArgs->TransState==TRANSACTION_ADD) { (*pTrans)->TransState = pArgs->TransState; (*pTrans)->FileOrPtr = pArgs->szSrcPath ? STORE_PTR : STORE_FILE; } // If this is a add, but don't store the files, then the transaction // file name is already in pArgs. if (pArgs->StoreFlags == ADD_DONT_STORE) { (*pTrans)->szTransFileName=(LPTSTR)malloc( sizeof(TCHAR) * (_tcslen(pArgs->szTransFileName) + 1) ); if (!(*pTrans)->szTransFileName ) { printf("Malloc cannot allocate memory for (*pTrans)->szTransFileName \n"); exit(1); } _tcscpy( (*pTrans)->szTransFileName, pArgs->szTransFileName ); return TRUE; } // Now, set the full path name of the transaction file (*pTrans)->szTransFileName=(LPTSTR)malloc( sizeof(TCHAR) * (_tcslen( pArgs->szAdminDir ) + _tcslen( (*pTrans)->szId ) + 1 ) ); if (!(*pTrans)->szTransFileName ) { printf("Malloc cannot allocate memory for (*pTrans)->szTransFilename \n"); exit(1); } _stprintf( (*pTrans)->szTransFileName, "%s%s", pArgs->szAdminDir, (*pTrans)->szId ); (*pTrans)->szProduct = pArgs->szProduct; (*pTrans)->szVersion = pArgs->szVersion; (*pTrans)->szComment = pArgs->szComment; (*pTrans)->szUnused = pArgs->szUnused; // Set the time and date GetLocalTime(&SystemTime); StoreSystemTime( & ((*pTrans)->szTime), &SystemTime ); StoreSystemDate( & ((*pTrans)->szDate), &SystemTime ); return (TRUE); } // // AddTransToFile // // Purpose - Add a record to the end of the Master File // BOOL AddTransToFile( PTRANSACTION pTrans, LPTSTR szFileName, PHANDLE hFile ) { LPTSTR szBuf=NULL; LPTSTR szBuf2=NULL; TCHAR szTransState[4]; TCHAR szFileOrPtr[10]; DWORD dwNumBytesToWrite; DWORD dwNumBytesWritten; DWORD FileSizeHigh; DWORD FileSizeLow; assert (pTrans); // Master file should already be opened assert(*hFile); // Create the buffer to store one record in szBuf = (LPTSTR) malloc( sizeof(TCHAR) * (lMaxTrans + 1) ); if (!szBuf) MallocFailed(); // Create the buffer to store one record in szBuf2 = (LPTSTR) malloc( sizeof(TCHAR) * (lMaxTrans + 1) ); if (!szBuf2) MallocFailed(); // Move to the end of the file SetFilePointer( *hFile, 0, NULL, FILE_END ); if (pTrans->TransState == TRANSACTION_ADD) { _tcscpy(szTransState,_T("add")); switch (pTrans->FileOrPtr) { case STORE_FILE: _tcscpy(szFileOrPtr,_T("file")); break; default: printf("Incorrect value for pTrans->FileOrPtr - assuming ptr\n"); case STORE_PTR: _tcscpy(szFileOrPtr,_T("ptr")); break; } _stprintf(szBuf2, "%s,%s,%s,%s,%s,%s,%s,%s,%s", pTrans->szId, szTransState, szFileOrPtr, pTrans->szDate, pTrans->szTime, pTrans->szProduct, pTrans->szVersion, pTrans->szComment, pTrans->szUnused ); } else if (pTrans->TransState == TRANSACTION_DEL) { _tcscpy(szTransState,_T("del")); _stprintf(szBuf2, "%s,%s,%s", pTrans->szDelId, szTransState, pTrans->szId); } else { printf("SYMSTORE: The transaction state is unknown\n"); free(szBuf); free(szBuf2); return (FALSE); } // If this is not the first line in the file, then put a '\n' before the // line. FileSizeLow = GetFileSize(*hFile, &FileSizeHigh); dwNumBytesToWrite = (_tcslen(szBuf2) ) * sizeof(TCHAR); if ( FileSizeLow == 0 && FileSizeHigh == 0 ) { _stprintf(szBuf,"%s", szBuf2); } else { _stprintf(szBuf,"\n%s", szBuf2); dwNumBytesToWrite += 1 * sizeof(TCHAR); } // Append this to the master file WriteFile( *hFile, (LPCVOID)szBuf, dwNumBytesToWrite, &dwNumBytesWritten, NULL ); free(szBuf); free(szBuf2); if ( dwNumBytesToWrite != dwNumBytesWritten ) { printf( "FAILED to write to %s, with GetLastError = %d\n", szFileName, GetLastError()); return (FALSE); } return (TRUE); } BOOL GetNextId( LPTSTR szMasterFileName, LPTSTR *szId, PHANDLE hFile ) { LPWIN32_FIND_DATA lpFindFileData; LONG lFileSize,lId; LPTSTR szbuf; LONG i,NumLeftZeros; BOOL Found; LONG lNumBytesToRead; DWORD dwNumBytesRead; DWORD dwNumBytesToRead; DWORD dwrc; BOOL rc; TCHAR TempId[MAX_ID + 1]; DWORD First; DWORD timeout; *szId = (LPTSTR)malloc( (MAX_ID + 1) * sizeof(TCHAR) ); if (!*szId) MallocFailed(); memset(*szId,0,MAX_ID + 1); szbuf = (LPTSTR) malloc( (lMaxTrans + 1) * sizeof(TCHAR) ); if (!szbuf) MallocFailed(); memset(szbuf,0,lMaxTrans+1); lpFindFileData = (LPWIN32_FIND_DATA) malloc (sizeof(WIN32_FIND_DATA) ); if (!lpFindFileData) MallocFailed(); // If the MasterFile is empty, then use the number "0000000001" *hFile = FindFirstFile((LPCTSTR)szMasterFileName, lpFindFileData); if ( *hFile == INVALID_HANDLE_VALUE) { _tcscpy(*szId, _T("0000000001") ); } // Otherwise, get the last number from the master file // Open the Master File timeout=0; First = 1; do { *hFile = CreateFile( szMasterFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( *hFile == INVALID_HANDLE_VALUE ) { *hFile = CreateFile( szMasterFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); } // Only print a message the first time through if ( First && *hFile == INVALID_HANDLE_VALUE ) { First = 0; printf("Waiting to open %s ... \n", szMasterFileName); } if ( *hFile == INVALID_HANDLE_VALUE ) { SleepEx(1000,0); timeout+=1; } } while ( *hFile == INVALID_HANDLE_VALUE && timeout <= 50 ); if (timeout > 50 ) { printf("Timed out -- could not open %s\n", szMasterFileName); return(1); } if (!_tcscmp(*szId, _T("0000000001") ) ) goto finish_GetNextId; // Read the last record in from the end of the file. Allocate one more space to // read in the next to last '\n', so we can verify that we are at the beginning of // the last record lFileSize = GetFileSize(*hFile,NULL); if ( lFileSize < (TRANS_NUM_COMMAS + TRANS_EOL + TRANS_ADD_DEL + TRANS_FILE_PTR + MAX_ID) ) { printf("The file %s does not have accurate transaction records in it\n", szMasterFileName); CloseHandle(*hFile); exit(1); } lNumBytesToRead = lFileSize < (lMaxTrans+1) ? lFileSize : (lMaxTrans + 1); lNumBytesToRead *= sizeof(TCHAR); dwNumBytesToRead = (DWORD)lNumBytesToRead; dwrc = SetFilePointer(*hFile,(-1 * dwNumBytesToRead),NULL,FILE_END); if ( dwrc == INVALID_SET_FILE_POINTER) { printf("SYMSTORE: Could not set file pointer\n"); CloseHandle(*hFile); exit(1); } rc = ReadFile(*hFile,(LPVOID)szbuf,dwNumBytesToRead,&dwNumBytesRead,NULL); if ( !rc ) { printf("SYMSTORE: Read file of %s failed - GetLastError() == %d\n", szMasterFileName, GetLastError() ); CloseHandle(*hFile); exit(1); } if ( dwNumBytesToRead != dwNumBytesRead ) { printf("SYMSTORE: Read file failure for %s - dwNumBytesToRead = %d, dwNumBytesRead = %d\n", szMasterFileName,dwNumBytesToRead, dwNumBytesRead ); CloseHandle(*hFile); exit(1); } // Now search from the end of the string until you get to the beginning of the string // or a '\n'. Count down from the end of the file. i = lNumBytesToRead - TRANS_NUM_COMMAS; Found = FALSE; while ( !Found && (i != 0 ) ) { if ( szbuf[i] == '\n' ) { Found = TRUE; } else { i--; } } // Move to the first character of the record if (Found) i++; // Now, verify that the next ten characters are the ID if ( szbuf[i + MAX_ID] != ',' ) { printf("There is a comma missing after the ID number of the\n"); printf("last record in the file %s\n", szMasterFileName); CloseHandle(*hFile); exit(1); } else { szbuf[i + MAX_ID] = '\0'; } // Now increment the number lId = atoi(szbuf + i); if (lId == 9999999999) { printf("The last ID number has been used. No more transactions are allowed\n"); CloseHandle(*hFile); exit(1); } lId++; _itoa(lId, TempId, 10); // Now pad the left side with zeros // *szId was already set to 0 NumLeftZeros = MAX_ID - _tcslen(TempId); _tcscpy( (*szId) + NumLeftZeros, TempId); for (i=0; i < NumLeftZeros; i++) { (*szId)[i] = '0'; } if (_tcslen(*szId) != MAX_ID ) { printf("Could not obtain a correct Id number\n"); CloseHandle(*hFile); exit(1); } finish_GetNextId: free(szbuf); free(lpFindFileData); return (TRUE); } VOID MallocFailed() { printf("SYMSTORE: Malloc failed to allocate enough memory\n"); exit(1); } BOOL DeleteTrans( PTRANSACTION pTrans, PCOM_ARGS pArgs ) { FILE *pFile; LONG MaxLine; LPTSTR szBuf; TCHAR szDir[_MAX_PATH + 2]; TCHAR *token; TCHAR seps[] = _T(","); // First, go get the transaction file // and delete its entries from the symbols server pFile = _tfopen(pTrans->szTransFileName, _T("r") ); if (!pFile ) { printf("Cannot open file %s - GetLastError = %d\n", pTrans->szTransFileName, GetLastError() ); exit(1); } // Figure out the maximum line length // Add space for 1 commas and a '\0' MaxLine = GetMaxLineOfTransactionFile(); szBuf = (LPTSTR)malloc(MaxLine * sizeof(TCHAR) ); if (!szBuf) MallocFailed(); while ( (!feof(pFile)) && fgets(szBuf, MaxLine, pFile)) { // Find the first token that ends with ',' token=_tcstok(szBuf, seps); // Compute the directory we are deleting from _tcscpy(szDir,pArgs->szSymbolsDir); _tcscat(szDir,token); EnsureTrailingBackslash(szDir); // Delete entry DeleteEntry(szDir, pTrans->szId); } free(szBuf); fclose(pFile); return(TRUE); } BOOL DeleteEntry( LPTSTR szDir, LPTSTR szId ) /*++ This deletes szID from the directory szDir on the symbols server -- */ { LPTSTR szRefsFile; // Full path and name of the refs.ptr file LPTSTR szTempFile; // Full path and name for a temporaty refs.ptr file LPTSTR szPtrFile; // Full path and name of the pointer file LPTSTR szParentDir; FILE *fRefsFile; FILE *fTempFile; FILE *fPtrFile; LPTSTR szBuf; // Used to process entries in the refs file TCHAR *token; TCHAR seps[] = _T(","); fpos_t CurFilePos; fpos_t IdFilePos; fpos_t PrevFilePos; fpos_t Prev2FilePos; BOOL IdIsFile; BOOL Found; BOOL rc = FALSE; ULONG MaxLine; // Maximim length of a record in refs.ptr ULONG NumLines = 0; ULONG NumFiles = 0; ULONG NumPtrs = 0; ULONG IdLineNum = 0; ULONG CurLine = 0; ULONG i; LONG j; DWORD len; ULONG ReplaceIsFile; ULONG ReplaceLineNum; szRefsFile = (LPTSTR) malloc ( (_tcslen(szDir) + _tcslen(_T("refs.ptr")) + 1) * sizeof(TCHAR) ); if (!szRefsFile) MallocFailed(); _stprintf(szRefsFile, "%srefs.ptr", szDir ); szPtrFile = (LPTSTR) malloc ( (_tcslen(szDir) + _tcslen(_T("file.ptr")) + 1) * sizeof(TCHAR) ); if (!szPtrFile) MallocFailed(); _stprintf(szPtrFile, "%sfile.ptr", szDir); szTempFile = (LPTSTR) malloc ( (_tcslen(szRefsFile) + _tcslen(".tmp") + 1) * sizeof(TCHAR) ); if (!szTempFile) MallocFailed(); _stprintf(szTempFile, "%s.tmp", szRefsFile ); MaxLine = GetMaxLineOfRefsPtrFile(); szBuf = (LPTSTR) malloc( MaxLine * sizeof(TCHAR) ); if ( !szBuf ) MallocFailed(); ZeroMemory(szBuf,MaxLine*sizeof(TCHAR)); fRefsFile = _tfopen(szRefsFile, _T("r+") ); if ( fRefsFile == NULL ) { // BARB - Check for corruption -- if the file doesn't exist, // verify that the parent directory structure doesn't exist either goto finish_DeleteEntry; } // // Read through the refs.ptr file and gather information // NumFiles = 0; NumPtrs = 0; Found = FALSE; NumLines = 0; fgetpos( fRefsFile, &CurFilePos); PrevFilePos = CurFilePos; // Position of the current line Prev2FilePos = CurFilePos; // Position of the line before the current line while ( _fgetts( szBuf, MaxLine, fRefsFile) != NULL ) { len=_tcslen(szBuf); if ( len > 3 ) { // CurFilePos is set to the next character to be read // We need to remember the beginning position of this line (PrevFilePos) // And the beginning position of the line before this line (Prev2FilePos) Prev2FilePos = PrevFilePos; PrevFilePos = CurFilePos; fgetpos( fRefsFile, &CurFilePos); NumLines++; token = _tcstok(szBuf, seps); // Look at the ID if ( _tcscmp(token,szId) == 0 ) { // We found the ID Found = TRUE; IdFilePos = PrevFilePos; IdLineNum = NumLines; token = _tcstok(NULL, seps); // Look at the "file" or "ptr" field if (token && ( _tcscmp(token,_T("file")) == 0)) { IdIsFile = TRUE; } else if (token && ( _tcscmp(token,_T("ptr")) == 0 )) { IdIsFile = FALSE; } else { printf("SYMSTORE: Error in %s - entry for %s does not contain ""file"" or ""ptr""\n", szRefsFile, szId); rc = FALSE; goto finish_DeleteEntry; } } else { // Record info about the other records token = _tcstok(NULL, seps); // Look at the "file" or "ptr" field if (token && ( _tcscmp(token,_T("file")) == 0)) { NumFiles++; } else if (token && ( _tcscmp(token,_T("ptr")) == 0 )) { NumPtrs++; } else { printf("SYMSTORE: Error in %s - entry for %s does not contain ""file"" or ""ptr""\n", szRefsFile, szId); rc = FALSE; goto finish_DeleteEntry; } } } ZeroMemory(szBuf, MaxLine*sizeof(TCHAR)); } fclose(fRefsFile); // If we didn't find the ID we are deleting, then don't do anything in this directory if (IdLineNum == 0 ) goto finish_DeleteEntry; // If there was only one record, then just delete everything if (NumLines == 1) { DeleteAllFilesInDirectory(szDir); // Delete this directory rc = RemoveDirectory(szDir); if ( !rc ) { printf("SYMSTORE: Could not delete %s, GetLastError=%d\n", szDir, GetLastError() ); goto finish_DeleteEntry; } // If the first directory was deleted, remove the parent directory szParentDir=(LPTSTR)malloc(_tcslen(szDir) + 1 ); if ( szParentDir == NULL ) MallocFailed(); // First figure out the parent directory _tcscpy(szParentDir, szDir); // szDir ended with a '\' -- find the previous one j = _tcslen(szParentDir)-2; while ( j >=0 && szParentDir[j] != '\\' ) { j--; } if (j<0) { printf("SYMSTORE: Could not delete the parent directory of %s\n", szDir); } else { szParentDir[j+1] = '\0'; // This call will remove the directory only if its empty RemoveDirectory(szParentDir); } free(szParentDir); goto finish_DeleteEntry; } // // Get the replacement info for this deletion // if ( IdLineNum == NumLines ) { ReplaceLineNum = NumLines-1; } else { ReplaceLineNum = NumLines; } // // Now, delete the entry from refs.ptr // Rename "refs.ptr" to "refs.ptr.tmp" // Then copy refs.ptr.tmp line by line to refs.ptr, skipping the line we are // supposed to delete // rename( szRefsFile, szTempFile); fTempFile= _tfopen(szTempFile, "r" ); if (fTempFile == NULL) { goto finish_DeleteEntry; } fRefsFile= _tfopen(szRefsFile, "w" ); if (fRefsFile == NULL) { fclose(fTempFile); goto finish_DeleteEntry; } CurLine = 0; i=0; while ( _fgetts( szBuf, MaxLine, fTempFile) != NULL ) { len=_tcslen(szBuf); if ( len > 3 ) { i++; if ( i != IdLineNum ) { // Make sure that the last line doesn't end with a '\n' if ( i == NumLines || (IdLineNum == NumLines && i == NumLines-1) ) { if ( token[_tcslen(token)-1] == '\n' ) { token[_tcslen(token)-1] = '\0'; } } _fputts( szBuf, fRefsFile); } // This is the replacement, either get the new file, or update file.ptr if ( i == ReplaceLineNum ) { // This is the replacement information, // Figure out if it is a file or a pointer token = _tcstok(szBuf, seps); // Skip the ID number token = _tcstok(NULL, seps); // Get "file" or "ptr" field if ( _tcscmp(token,_T("file")) == 0) { ReplaceIsFile = TRUE; } else if ( _tcscmp(token,_T("ptr")) == 0 ) { ReplaceIsFile = FALSE; } else { printf("SYMSTORE: Error in %s - entry for %s does not contain ""file"" or ""ptr""\n", szRefsFile, szId); rc = FALSE; goto finish_DeleteEntry; } token = _tcstok(NULL, seps); // Get the replacement path and filename // Strip off the last character if it is a '\n' if ( token[_tcslen(token)-1] == '\n' ) { token[_tcslen(token)-1] = '\0'; } // // If the replacement is a file, then copy the file // If the replacement if a ptr, then update "file.ptr" // rc = TRUE; if (ReplaceIsFile) { rc = CopyTheFile(szDir, token); DeleteFile(szPtrFile); } else { // // Put the new pointer into "file.ptr" // fPtrFile = _tfopen(szPtrFile, _T("w") ); if ( !fPtrFile ) { printf("SYMSTORE: Could not open %s for writing\n", szPtrFile); rc = FALSE; } else { _fputts( token, fPtrFile); fclose(fPtrFile); } // // If the deleted record was a "file", and we are placing it with a // pointer, and there are no other "file" records in refs.ptr, then // delete the file from the directory. // if ( IdIsFile && NumFiles == 0 ) { DeleteTheFile(szDir, token); } } } } } fclose(fTempFile); fclose(fRefsFile); // Now, delete the temporary file DeleteFile(szTempFile); finish_DeleteEntry: free (szBuf); free (szRefsFile); free (szPtrFile); free (szTempFile); return (rc); } BOOL CopyTheFile( LPTSTR szDir, LPTSTR szFilePathName ) /*++ IN szDir The directory that the file is copied to IN szFilePathName The full path and name of the file to be copied "CopyTheFile" copies szFilePathName to the directory szDir, if the file does not already exist in szDir --*/ { BOOL rc; USHORT j; LPTSTR szFileName; // Figure out index in "szFilePathName" where the file name starts j = _tcslen(szFilePathName) - 1; if ( szFilePathName[j] == '\\' ) { printf("SYMSTORE: %s\refs.ptr has a bad file name %s\n", szDir, szFilePathName); return(FALSE); } while ( szFilePathName[j] != '\\' && j != 0 ) j--; if ( j == 0 ) { printf("SYMSTORE: %s\refs.ptr has a bad file name for %s\n", szDir, szFilePathName ); return(FALSE); } // Set j == the index of first character after the last '\' in szFilePathName j++; // Allocate and store the full path and name of szFileName = (LPTSTR) malloc ( sizeof(TCHAR) * (_tcslen(szDir) + _tcslen(szFilePathName+j) + 1) ); if ( szFileName == NULL ) MallocFailed(); _stprintf(szFileName, "%s%s", szDir, szFilePathName+j ); // If this file doesn't exist, then copy it rc = MyCopyFile( szFilePathName, szFileName ); free(szFileName); return(rc); } BOOL DeleteTheFile( LPTSTR szDir, LPTSTR szFilePathName ) /*++ IN szDir The directory that the file is to be deleted from IN szFilePathName The file name of the file to be deleted. It is preceded by the wrong path. That's why we need to strip off the file name and add it to szDir "DeleteTheFile" figures out the file name at the end of szFilePathName, and deletes it from szDir if it exists. It will delete the file and/or the corresponding compressed file name that has the same name with a _ at the end of it. --*/ { BOOL rc,returnval=TRUE; USHORT j; LPTSTR szFileName; DWORD dw; // Figure out index in "szFilePathName" where the file name starts j = _tcslen(szFilePathName) - 1; if ( szFilePathName[j] == '\\' ) { printf("SYMSTORE: %s\refs.ptr has a bad file name %s\n", szDir, szFilePathName); return(FALSE); } while ( szFilePathName[j] != '\\' && j != 0 ) j--; if ( j == 0 ) { printf("SYMSTORE: %s\refs.ptr has a bad file name for %s\n", szDir, szFilePathName ); return(FALSE); } // Set j == the index of first character after the last '\' in szFilePathName j++; // Allocate and store the full path and name of szFileName = (LPTSTR) malloc ( sizeof(TCHAR) * (_tcslen(szDir) + _tcslen(szFilePathName+j) + 1) ); if ( szFileName == NULL ) MallocFailed(); _stprintf(szFileName, "%s%s", szDir, szFilePathName+j ); // See if the file exists dw = GetFileAttributes( szFileName ); if ( dw != 0xffffffff ) { rc = DeleteFile( szFileName ); if (!rc && GetLastError() != ERROR_NOT_FOUND ) { printf("SYMSTORE: Could not delete %s - GetLastError = %d\n", szFileName, GetLastError() ); returnval=FALSE; } } // See if the compressed file exists and delete it. szFileName[ _tcslen(szFileName) -1 ] = _T('_'); dw = GetFileAttributes( szFileName ); if ( dw != 0xffffffff ) { rc = DeleteFile( szFileName ); if (!rc && GetLastError() != ERROR_NOT_FOUND ) { printf("SYMSTORE: Could not delete %s - GetLastError = %d\n", szFileName, GetLastError() ); returnval=FALSE; } } free(szFileName); return(returnval); } BOOL UpdateServerFile( PTRANSACTION pTrans, LPTSTR szServerFileName ) /* ++ IN pTrans // Transaction Info IN szServerFile // Full path and name of the server transaction file // This file tells what is currently on the server Purpose: UpdateServerFile adds the transaction to the server text file if this is an "add. If this is a "del", it deletes it from the server file. The "server.txt" file is in the admin directory. -- */ { ULONG i; ULONG NumLines; ULONG IdLineNum; LPTSTR szBuf; LPTSTR szTempFileName; FILE *fTempFile; FILE *fServerFile; ULONG MaxLine; TCHAR *token; TCHAR seps[]=","; BOOL rc; HANDLE hFile; DWORD First; DWORD timeout; if (pTrans->TransState == TRANSACTION_ADD ) { // Open the File -- wait until we can get access to it First = 1; timeout=0; do { hFile = CreateFile( szServerFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) { hFile = CreateFile( szServerFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); } if ( First && hFile == INVALID_HANDLE_VALUE ) { First = 0; printf("Waiting to open %s ... \n", szServerFileName); } if ( hFile == INVALID_HANDLE_VALUE ) { SleepEx(1000,0); timeout++; } } while ( hFile == INVALID_HANDLE_VALUE && timeout <= 50 ); if ( timeout > 50 ) { printf("Timed out -- could not open %s\n", szServerFileName); return (1); } rc = AddTransToFile(pTrans, szServerFileName,&hFile); CloseHandle(hFile); return(rc); } if (pTrans->TransState != TRANSACTION_DEL) { return(FALSE); } // // Now, delete this transaction ID from the file // Get the name of the temporary file // and open it for writing // szTempFileName = (LPTSTR)malloc(sizeof(TCHAR) * _tcslen(szServerFileName) + _tcslen(".tmp") + 1 ); if (szTempFileName == NULL) MallocFailed(); _stprintf(szTempFileName, "%s.tmp", szServerFileName); fTempFile = _tfopen(szTempFileName, _T("w") ); if ( fTempFile == NULL ) { printf("SYMSTORE: Cannot create a temporary file %s\n", szTempFileName); exit(1); } // // Open the Server file for reading // fServerFile = _tfopen(szServerFileName, _T("r") ); if ( fServerFile == NULL ) { printf("SYMSTORE: Cannot create a temporary file %s\n", szServerFileName); exit(1); } // // Allocate enough space to hold a line of the master file // MaxLine = GetMaxLineOfHistoryFile(); szBuf = (LPTSTR)malloc(sizeof(TCHAR) * MaxLine); if (szBuf == NULL) MallocFailed(); // // Copy the master file to the temporary file. // // Do some stuff so that we don't put an extra '\n' at the end of the file // Figure out how many lines there are and which line the ID is on. // If we are removing the last line of the file, then the next to the last // line needs to have a '\n' stripped from it. // NumLines = 0; IdLineNum = 0; while ( _fgetts( szBuf, MaxLine, fServerFile) != NULL ) { NumLines++; token = _tcstok(szBuf,seps); if (_tcscmp(token, pTrans->szId) == 0 ) { IdLineNum = NumLines; } } fclose(fServerFile); // Now, reopen it and copy it, deleting the line with ID in it fServerFile = _tfopen(szServerFileName, _T("r") ); if ( fServerFile == NULL ) { printf("SYMSTORE: Cannot create a temporary file %s\n", szServerFileName); exit(1); } for (i=1; i<=NumLines; i++ ) { _fgetts( szBuf, MaxLine, fServerFile); if ( i != IdLineNum ) { // Make sure that the last line doesn't end with a '\n' if ( i == NumLines || (IdLineNum == NumLines && i == NumLines-1) ) { if ( szBuf[_tcslen(szBuf)-1] == '\n' ) { szBuf[_tcslen(szBuf)-1] = '\0'; } } _fputts( szBuf, fTempFile); } } fclose(fServerFile); fclose(fTempFile); // Now, delete the original Server file and // replace it with the temporary file rc = DeleteFile(szServerFileName); if (!rc) { printf("SYMSTORE: Could not delete %s to update it with %s\n", szServerFileName, szTempFileName); exit(1); } rc = _trename(szTempFileName, szServerFileName); if ( rc != 0 ) { printf("SYMSTORE: Could not rename %s to %s\n", szTempFileName, szServerFileName); exit(1); } free(szBuf); free(szTempFileName); return(TRUE); } BOOL StoreSystemTime( LPTSTR *szBuf, LPSYSTEMTIME lpSystemTime ) { TCHAR Hour[20]; TCHAR Minute[20]; TCHAR Second[20]; (*szBuf) = (LPTSTR) malloc (20 * sizeof(TCHAR) ); if ( (*szBuf) == NULL ) MallocFailed(); _itoa(lpSystemTime->wHour, Hour, 10); _itoa(lpSystemTime->wMinute, Minute, 10); _itoa(lpSystemTime->wSecond, Second, 10); _stprintf(*szBuf, "%2s:%2s:%2s", Hour, Minute, Second ); if ( (*szBuf)[0] == ' ' ) (*szBuf)[0] = '0'; if ( (*szBuf)[3] == ' ' ) (*szBuf)[3] = '0'; if ( (*szBuf)[6] == ' ' ) (*szBuf)[6] = '0'; return(TRUE); } BOOL StoreSystemDate( LPTSTR *szBuf, LPSYSTEMTIME lpSystemTime ) { TCHAR Day[20]; TCHAR Month[20]; TCHAR Year[20]; (*szBuf) = (LPTSTR) malloc (20 * sizeof(TCHAR) ); if ( (*szBuf) == NULL ) MallocFailed(); _itoa(lpSystemTime->wMonth, Month, 10); _itoa(lpSystemTime->wDay, Day, 10); _itoa(lpSystemTime->wYear, Year, 10); _stprintf(*szBuf, "%2s/%2s/%2s", Month, Day, Year+2 ); if ( (*szBuf)[0] == ' ' ) (*szBuf)[0] = '0'; if ( (*szBuf)[3] == ' ' ) (*szBuf)[3] = '0'; return(TRUE); } ULONG GetMaxLineOfTransactionFile( VOID ) /*++ This returns the maximum length of a line in a transaction file. The transaction file is a unique file for each transaction that gets created in the admin directory. Its name is a number (i.e., "0000000001") --*/ { ULONG Max; Max = (_MAX_PATH * 2 + 3) * sizeof(TCHAR); return(Max); } ULONG GetMaxLineOfHistoryFile( VOID ) /*++ This returns the maximum length of a line in the history file. The history file contains one line for every transaction. It exists in the admin directory. --*/ { ULONG Max; Max = MAX_ID + MAX_VERSION + MAX_PRODUCT + MAX_COMMENT + TRANS_NUM_COMMAS + TRANS_EOL + TRANS_ADD_DEL + TRANS_FILE_PTR + MAX_DATE + MAX_TIME + MAX_UNUSED; Max *= sizeof(TCHAR); return(Max); } ULONG GetMaxLineOfRefsPtrFile( VOID ) /* ++ This returns the maximum length of a line in the refs.ptr file. This file exists in the individual directories of the symbols server. -- */ { ULONG Max; Max = _MAX_PATH+2 + MAX_ID + TRANS_FILE_PTR + 3; Max *= sizeof(TCHAR); return(Max); } /* GetSrcDirandFileName This procedure takes a path and separates it into two strings. One string for the directory portion of the path and one string for the file name portion of the path. szStr - INPUT string that contains a path szSrcDir - OUTPUT string that contains the directory followed by a backslash szFileName - OUTPUT string that contains the file name */ BOOL GetSrcDirandFileName ( LPTSTR szStr, LPTSTR szSrcDir, LPTSTR szFileName ) { DWORD szStrLength; DWORD found, i, j, lastslash; HANDLE fHandle; WIN32_FIND_DATA FindFileData; szStrLength = _tcslen(szStr); if ( szStrLength == 0 ) { return (FALSE); } // See if the user entered "." // If so, set the src directory to . followed by a \, and // set the file name to * if ( szStrLength == 1 && szStr[0] == _T('.') ) { _tcscpy( szSrcDir, _T(".\\") ); _tcscpy( szFileName, _T("*") ); return (TRUE); } // Give an error if the end of the string is a colon if ( szStr[szStrLength-1] == _T(':') ) { printf("SYMSTORE: ERROR: path %s does not specify a file\n", szStr); return (FALSE); } // See if this is a file name only. See if there are no // backslashes in the string. found = 0; for ( i=0; i= szStrLength ) { printf("SYMSTORE: ERROR: %s is not a correct UNC path\n", szStr); return (FALSE); } switch (szStr[i]) { case _T('.'): case _T('*'): case _T(':'): case _T('\\'): case _T('?'): printf("SYMSTORE: ERROR: %s is not correct UNC path\n",szStr); return (FALSE); default: break; } // Now, we have \\server\share so far -- if there are no more // backslashes, then the filename is * and the directory is // szStr i++; while ( i < szStrLength && szStr[i] != _T('\\') ) { i++; } if ( i == szStrLength ) { // verify that there are no wildcards in this found = 0; for ( j=0; j